107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com/*
207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Copyright 2012 Google Inc.
307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com *
407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * found in the LICENSE file.
607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com */
707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#include "SkIntersections.h"
8dac1d17027dcaa5596885a9f333979418b35001ccaryclark#include "SkOpContour.h"
907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#include "SkOpSegment.h"
1007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#include "SkPathWriter.h"
117dfbb0720a133c0f63ac7be504f335bbcc62a291caryclark@google.com#include "SkTSort.h"
1207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#define F (false)      // discard the edge
1407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#define T (true)       // keep the edge
1507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comstatic const bool gUnaryActiveEdge[2][2] = {
1707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com//  from=0  from=1
1807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com//  to=0,1  to=0,1
1907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    {F, T}, {T, F},
2007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com};
2107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
2207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comstatic const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = {
2307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com//                 miFrom=0                              miFrom=1
244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org//         miTo=0             miTo=1             miTo=0             miTo=1
254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org//     suFrom=0    1      suFrom=0    1      suFrom=0    1      suFrom=0    1
2607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com//   suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1  suTo=0,1 suTo=0,1
2707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}},  // mi - su
2807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}},  // mi & su
2907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}},  // mi | su
3007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}},  // mi ^ su
3107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com};
3207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
3307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#undef F
3407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#undef T
3507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
36570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comenum {
37570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    kOutsideTrackedTCount = 16,  // FIXME: determine what this should be
38570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    kMissingSpanCount = 4,  // FIXME: determine what this should be
39570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com};
4007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgconst SkOpAngle* SkOpSegment::activeAngle(int index, int* start, int* end, bool* done,
424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        bool* sortable) const {
434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (const SkOpAngle* result = activeAngleInner(index, start, end, done, sortable)) {
444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return result;
4507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
46570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    double referenceT = fTs[index].fT;
4707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = index;
48570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    while (--lesser >= 0
49570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) {
504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done, sortable)) {
514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return result;
5207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
5307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
5407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (const SkOpAngle* result = activeAngleOther(index, start, end, done, sortable)) {
564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return result;
5707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
58570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (++index == fTs.count()) {
59570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            break;
60570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
61570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (fTs[index - 1].fTiny) {
62570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            referenceT = fTs[index].fT;
63570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            continue;
64570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
65570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (precisely_negative(fTs[index].fT - referenceT));
664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return NULL;
6707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
6807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgconst SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, bool* done,
704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        bool* sortable) const {
7107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int next = nextExactSpan(index, 1);
7207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (next > 0) {
734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& upSpan = fTs[index];
7407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (upSpan.fWindValue || upSpan.fOppValue) {
754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (*end < 0) {
764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                *start = index;
774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                *end = next;
7807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
798cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            if (!upSpan.fDone) {
804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (upSpan.fWindSum != SK_MinS32) {
814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    return spanToAngle(index, next);
824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
834431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                *done = false;
844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } else {
864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(upSpan.fDone);
8707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
8807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
8907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int prev = nextExactSpan(index, -1);
9007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // edge leading into junction
9107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (prev >= 0) {
924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& downSpan = fTs[prev];
9307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (downSpan.fWindValue || downSpan.fOppValue) {
944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (*end < 0) {
954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                *start = index;
964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                *end = prev;
974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (!downSpan.fDone) {
994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (downSpan.fWindSum != SK_MinS32) {
1004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    return spanToAngle(index, prev);
1014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
1024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                *done = false;
10307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
1044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } else {
1054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(downSpan.fDone);
10607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
10707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
1084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return NULL;
1094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
1104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
1114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgconst SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end, bool* done,
1124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        bool* sortable) const {
1134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* span = &fTs[index];
1144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSegment* other = span->fOther;
1154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int oIndex = span->fOtherIndex;
1164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return other->activeAngleInner(oIndex, start, end, done, sortable);
11707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
11807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1198cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.orgSkPoint SkOpSegment::activeLeftTop(int* firstT) const {
12007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(!done());
12107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkPoint topPt = {SK_ScalarMax, SK_ScalarMax};
12207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int count = fTs.count();
12307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // see if either end is not done since we want smaller Y of the pair
12407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool lastDone = true;
12507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double lastT = -1;
12607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    for (int index = 0; index < count; ++index) {
12707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const SkOpSpan& span = fTs[index];
12807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (span.fDone && lastDone) {
12907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            goto next;
13007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
13107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (approximately_negative(span.fT - lastT)) {
13207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            goto next;
13307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
13407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        {
13507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            const SkPoint& xy = xyAtT(&span);
13607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
13707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                topPt = xy;
13807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                if (firstT) {
13907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    *firstT = index;
14007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                }
14107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
14207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (fVerb != SkPath::kLine_Verb && !lastDone) {
143277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com                SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT);
14407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY
14507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                        && topPt.fX > curveTop.fX)) {
14607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    topPt = curveTop;
14707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    if (firstT) {
14807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                        *firstT = index;
14907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    }
15007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                }
15107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
15207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            lastT = span.fT;
15307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
15407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comnext:
15507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        lastDone = span.fDone;
15607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
15707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return topPt;
15807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
15907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
16007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op) {
16107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int sumMiWinding = updateWinding(endIndex, index);
16207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int sumSuWinding = updateOppWinding(endIndex, index);
16307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fOperand) {
16407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkTSwap<int>(sumMiWinding, sumSuWinding);
16507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
1664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding);
16707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
16807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
16907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
1704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int* sumMiWinding, int* sumSuWinding) {
1714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
17207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    setUpWindings(index, endIndex, sumMiWinding, sumSuWinding,
1734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
17407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool miFrom;
17507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool miTo;
17607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool suFrom;
17707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool suTo;
17807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (operand()) {
1794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        miFrom = (oppMaxWinding & xorMiMask) != 0;
1804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        miTo = (oppSumWinding & xorMiMask) != 0;
1814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        suFrom = (maxWinding & xorSuMask) != 0;
1824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        suTo = (sumWinding & xorSuMask) != 0;
18307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } else {
1844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        miFrom = (maxWinding & xorMiMask) != 0;
1854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        miTo = (sumWinding & xorMiMask) != 0;
1864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        suFrom = (oppMaxWinding & xorSuMask) != 0;
1874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        suTo = (oppSumWinding & xorSuMask) != 0;
18807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
18907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
19007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_ACTIVE_OP
191dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n",
192dac1d17027dcaa5596885a9f333979418b35001ccaryclark            __FUNCTION__, debugID(), span(index).fT, span(endIndex).fT,
193570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result);
19407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
19507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return result;
19607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
19707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
19807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::activeWinding(int index, int endIndex) {
19907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int sumWinding = updateWinding(endIndex, index);
2004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return activeWinding(index, endIndex, &sumWinding);
20107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
20207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
2034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgbool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) {
2044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int maxWinding;
2054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    setUpWinding(index, endIndex, &maxWinding, sumWinding);
2064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool from = maxWinding != 0;
20707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool to = *sumWinding  != 0;
20807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool result = gUnaryActiveEdge[from][to];
20907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return result;
21007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
21107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
212570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt,
213570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSegment* other) {
21407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int tIndex = -1;
21507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int tCount = fTs.count();
21607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oIndex = -1;
21707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oCount = other->fTs.count();
21807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
21907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++tIndex;
220570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (startPt != fTs[tIndex].fPt && tIndex < tCount);
22107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int tIndexStart = tIndex;
22207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
22307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++oIndex;
224570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount);
22507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oIndexStart = oIndex;
226570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkPoint* nextPt;
22707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
228570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        nextPt = &fTs[++tIndex].fPt;
229570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt);
230570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (startPt == *nextPt);
231570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    double nextT = fTs[tIndex].fT;
232570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkPoint* oNextPt;
23307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
234570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        oNextPt = &other->fTs[++oIndex].fPt;
235570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt);
236570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (endPt == *oNextPt);
237570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    double oNextT = other->fTs[oIndex].fT;
23807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // at this point, spans before and after are at:
23907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    //  fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
24007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // if tIndexStart == 0, no prior span
24107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // if nextT == 1, no following span
24207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
24307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // advance the span with zero winding
24407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // if the following span exists (not past the end, non-zero winding)
24507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // connect the two edges
24607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!fTs[tIndexStart].fWindValue) {
24707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
24807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_CONCIDENT
24907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
25007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    __FUNCTION__, fID, other->fID, tIndexStart - 1,
25107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    fTs[tIndexStart].fT, xyAtT(tIndexStart).fX,
25207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    xyAtT(tIndexStart).fY);
25307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
254bdbb2422b9f20372597367a032d822b4297eab41caryclark            SkPoint copy = fTs[tIndexStart].fPt;  // add t pair may move the point array
255bdbb2422b9f20372597367a032d822b4297eab41caryclark            addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false, copy);
25607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
25707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (nextT < 1 && fTs[tIndex].fWindValue) {
25807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_CONCIDENT
25907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
26007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    __FUNCTION__, fID, other->fID, tIndex,
26107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    fTs[tIndex].fT, xyAtT(tIndex).fX,
26207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    xyAtT(tIndex).fY);
26307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
264bdbb2422b9f20372597367a032d822b4297eab41caryclark            SkPoint copy = fTs[tIndex].fPt;  // add t pair may move the point array
265bdbb2422b9f20372597367a032d822b4297eab41caryclark            addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, copy);
26607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
26707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } else {
26807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkASSERT(!other->fTs[oIndexStart].fWindValue);
26907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) {
27007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_CONCIDENT
27107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
27207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    __FUNCTION__, fID, other->fID, oIndexStart - 1,
27307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX,
27407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    other->xyAtT(oIndexStart).fY);
27507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT);
27607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
27707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
27807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (oNextT < 1 && other->fTs[oIndex].fWindValue) {
27907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_CONCIDENT
28007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
28107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    __FUNCTION__, fID, other->fID, oIndex,
28207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    other->fTs[oIndex].fT, other->xyAtT(oIndex).fX,
28307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    other->xyAtT(oIndex).fY);
28407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
28507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
28607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
28707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
28807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
28907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
290570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt,
291570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSegment* other) {
292570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // walk this to startPt
293570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // walk other to startPt
29407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // if either is > 0, add a pointer to the other, copying adjacent winding
29507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int tIndex = -1;
29607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oIndex = -1;
29707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
29807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++tIndex;
299570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (startPt != fTs[tIndex].fPt);
3004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int ttIndex = tIndex;
3014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool checkOtherTMatch = false;
3024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
3034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& span = fTs[ttIndex];
3044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (startPt != span.fPt) {
3054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
306a1ed7aec95eb8c77d1a39834fea476780007cadeskia.committer@gmail.com        }
3074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (span.fOther == other && span.fPt == startPt) {
3084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            checkOtherTMatch = true;
3094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
3104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
3114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (++ttIndex < count());
31207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
31307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++oIndex;
314570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (startPt != other->fTs[oIndex].fPt);
3154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool skipAdd = false;
3164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (checkOtherTMatch) {
3174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int ooIndex = oIndex;
3184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
3194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan& oSpan = other->fTs[ooIndex];
3204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (startPt != oSpan.fPt) {
3214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
322a1ed7aec95eb8c77d1a39834fea476780007cadeskia.committer@gmail.com            }
3234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (oSpan.fT == fTs[ttIndex].fOtherT) {
3244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                skipAdd = true;
3254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
3264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
3274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } while (++ooIndex < other->count());
3284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
3294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) {
330570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt);
33107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
332570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkPoint nextPt = startPt;
33307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
334570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        const SkPoint* workPt;
33507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        do {
336570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            workPt = &fTs[++tIndex].fPt;
337570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        } while (nextPt == *workPt);
3388cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        const SkPoint* oWorkPt;
33907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        do {
3408cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            oWorkPt = &other->fTs[++oIndex].fPt;
3418cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        } while (nextPt == *oWorkPt);
342570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        nextPt = *workPt;
343570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        double tStart = fTs[tIndex].fT;
344570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        double oStart = other->fTs[oIndex].fT;
34507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) {
34607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            break;
34707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
3488cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        if (*workPt == *oWorkPt) {
3498cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            addTPair(tStart, other, oStart, false, nextPt);
3508cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        }
351570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (endPt != nextPt);
35207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
35307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
35407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) {
35507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    init(pts, SkPath::kCubic_Verb, operand, evenOdd);
35607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fBounds.setCubicBounds(pts);
35707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
35807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
35907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const {
36007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkPoint edge[4];
36107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const SkPoint* ePtr;
36207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lastT = fTs.count() - 1;
36307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) {
36407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ePtr = fPts;
36507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } else {
36607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // OPTIMIZE? if not active, skip remainder and return xyAtT(end)
36707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        subDivide(start, end, edge);
36807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ePtr = edge;
36907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
37007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (active) {
37107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        bool reverse = ePtr == fPts && start != 0;
37207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (reverse) {
373277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com            path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]);
37407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            switch (fVerb) {
37507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                case SkPath::kLine_Verb:
37607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    path->deferredLine(ePtr[0]);
37707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    break;
37807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                case SkPath::kQuad_Verb:
37907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    path->quadTo(ePtr[1], ePtr[0]);
38007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    break;
38107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                case SkPath::kCubic_Verb:
38207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    path->cubicTo(ePtr[2], ePtr[1], ePtr[0]);
38307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    break;
38407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                default:
38507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    SkASSERT(0);
38607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
38707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com   //         return ePtr[0];
38807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com       } else {
38907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            path->deferredMoveLine(ePtr[0]);
39007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            switch (fVerb) {
39107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                case SkPath::kLine_Verb:
39207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    path->deferredLine(ePtr[1]);
39307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    break;
39407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                case SkPath::kQuad_Verb:
39507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    path->quadTo(ePtr[1], ePtr[2]);
39607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    break;
39707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                case SkPath::kCubic_Verb:
39807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    path->cubicTo(ePtr[1], ePtr[2], ePtr[3]);
39907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    break;
40007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                default:
40107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    SkASSERT(0);
40207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
40307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
40407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
405277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com  //  return ePtr[SkPathOpsVerbToPoints(fVerb)];
40607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
40707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
4084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::addEndSpan(int endIndex) {
40919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    SkASSERT(span(endIndex).fT == 1 || (span(endIndex).fTiny
41065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark//            && approximately_greater_than_one(span(endIndex).fT)
41165b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    ));
4124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int spanCount = fTs.count();
4134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int startIndex = endIndex - 1;
4144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) {
41519eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        --startIndex;
41619eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkASSERT(startIndex > 0);
41719eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        --endIndex;
4184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
419dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle& angle = fAngles.push_back();
420dac1d17027dcaa5596885a9f333979418b35001ccaryclark    angle.set(this, spanCount - 1, startIndex);
4214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_ANGLE
4224431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugCheckPointsEqualish(endIndex, spanCount);
4234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
424dac1d17027dcaa5596885a9f333979418b35001ccaryclark    setFromAngle(endIndex, &angle);
4254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
4264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
427dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::setFromAngle(int endIndex, SkOpAngle* angle) {
4284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int spanCount = fTs.count();
4294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
430dac1d17027dcaa5596885a9f333979418b35001ccaryclark        fTs[endIndex].fFromAngle = angle;
4314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (++endIndex < spanCount);
4324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
4334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
43407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) {
43507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    init(pts, SkPath::kLine_Verb, operand, evenOdd);
43607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fBounds.set(pts, 2);
43707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
43807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
43907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// add 2 to edge or out of range values to get T extremes
44007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::addOtherT(int index, double otherT, int otherIndex) {
44107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan& span = fTs[index];
4420361032c0b53401030a720bc8b4930c3ec59f19ecaryclark@google.com    if (precisely_zero(otherT)) {
44307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        otherT = 0;
4440361032c0b53401030a720bc8b4930c3ec59f19ecaryclark@google.com    } else if (precisely_equal(otherT, 1)) {
44507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        otherT = 1;
44607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
44707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span.fOtherT = otherT;
44807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span.fOtherIndex = otherIndex;
44907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
45007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
45107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) {
45207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    init(pts, SkPath::kQuad_Verb, operand, evenOdd);
45307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fBounds.setQuadBounds(pts);
45407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
45507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
456dac1d17027dcaa5596885a9f333979418b35001ccaryclarkSkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** anglePtr) {
457dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int spanIndex = count() - 1;
458dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int startIndex = nextExactSpan(spanIndex, -1);
459dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(startIndex >= 0);
460dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle& angle = fAngles.push_back();
461dac1d17027dcaa5596885a9f333979418b35001ccaryclark    *anglePtr = &angle;
462dac1d17027dcaa5596885a9f333979418b35001ccaryclark    angle.set(this, spanIndex, startIndex);
463dac1d17027dcaa5596885a9f333979418b35001ccaryclark    setFromAngle(spanIndex, &angle);
4644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSegment* other;
465dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int oStartIndex, oEndIndex;
4664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
467dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkOpSpan& span = fTs[spanIndex];
468dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(span.fT > 0);
469dac1d17027dcaa5596885a9f333979418b35001ccaryclark        other = span.fOther;
470dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oStartIndex = span.fOtherIndex;
471dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oEndIndex = other->nextExactSpan(oStartIndex, 1);
472dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (oEndIndex > 0 && other->span(oStartIndex).fWindValue) {
4734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
4744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
475dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oEndIndex = oStartIndex;
476dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oStartIndex = other->nextExactSpan(oEndIndex, -1);
4774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        --spanIndex;
478dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (oStartIndex < 0 || !other->span(oStartIndex).fWindSum);
479dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle& oAngle = other->fAngles.push_back();
480dac1d17027dcaa5596885a9f333979418b35001ccaryclark    oAngle.set(other, oStartIndex, oEndIndex);
481dac1d17027dcaa5596885a9f333979418b35001ccaryclark    other->setToAngle(oEndIndex, &oAngle);
4824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    *otherPtr = other;
483dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return &oAngle;
4844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
4854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
486dac1d17027dcaa5596885a9f333979418b35001ccaryclarkSkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr) {
487dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int endIndex = nextExactSpan(0, 1);
4884431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(endIndex > 0);
489dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle& angle = fAngles.push_back();
490dac1d17027dcaa5596885a9f333979418b35001ccaryclark    *anglePtr = &angle;
491dac1d17027dcaa5596885a9f333979418b35001ccaryclark    angle.set(this, 0, endIndex);
492dac1d17027dcaa5596885a9f333979418b35001ccaryclark    setToAngle(endIndex, &angle);
493dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int spanIndex = 0;
4944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSegment* other;
495dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int oStartIndex, oEndIndex;
4964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
497dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkOpSpan& span = fTs[spanIndex];
498dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(span.fT < 1);
499dac1d17027dcaa5596885a9f333979418b35001ccaryclark        other = span.fOther;
500dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oEndIndex = span.fOtherIndex;
501dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oStartIndex = other->nextExactSpan(oEndIndex, -1);
502dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (oStartIndex >= 0 && other->span(oStartIndex).fWindValue) {
5034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
5044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
505dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oStartIndex = oEndIndex;
506dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oEndIndex = other->nextExactSpan(oStartIndex, 1);
5074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        ++spanIndex;
508dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (oEndIndex < 0 || !other->span(oStartIndex).fWindValue);
509dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle& oAngle = other->fAngles.push_back();
510dac1d17027dcaa5596885a9f333979418b35001ccaryclark    oAngle.set(other, oEndIndex, oStartIndex);
511dac1d17027dcaa5596885a9f333979418b35001ccaryclark    other->setFromAngle(oEndIndex, &oAngle);
5124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    *otherPtr = other;
513dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return &oAngle;
5144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
5154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
516dac1d17027dcaa5596885a9f333979418b35001ccaryclarkSkOpAngle* SkOpSegment::addSingletonAngles(int step) {
5174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSegment* other;
518dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle* angle, * otherAngle;
5194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (step > 0) {
520dac1d17027dcaa5596885a9f333979418b35001ccaryclark        otherAngle = addSingletonAngleUp(&other, &angle);
5214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
522dac1d17027dcaa5596885a9f333979418b35001ccaryclark        otherAngle = addSingletonAngleDown(&other, &angle);
5234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
524dac1d17027dcaa5596885a9f333979418b35001ccaryclark    angle->insert(otherAngle);
525dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return angle;
5264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
5274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
5284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::addStartSpan(int endIndex) {
5294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = 0;
530dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle& angle = fAngles.push_back();
531dac1d17027dcaa5596885a9f333979418b35001ccaryclark    angle.set(this, index, endIndex);
5324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_ANGLE
5334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugCheckPointsEqualish(index, endIndex);
5344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
535dac1d17027dcaa5596885a9f333979418b35001ccaryclark    setToAngle(endIndex, &angle);
5364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
5374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
538dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::setToAngle(int endIndex, SkOpAngle* angle) {
5394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = 0;
5404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
541dac1d17027dcaa5596885a9f333979418b35001ccaryclark        fTs[index].fToAngle = angle;
5424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (++index < endIndex);
5434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
5444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
54507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // Defer all coincident edge processing until
54607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // after normal intersections have been computed
54707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
54807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// no need to be tricky; insert in normal T order
54907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// resolve overlapping ts when considering coincidence later
55007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
55107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // add non-coincident intersection. Resulting edges are sorted in T.
552866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.orgint SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) {
5534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(this != other || fVerb == SkPath::kCubic_Verb);
5544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org #if 0  // this needs an even rougher association to be useful
5554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt));
5564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org #endif
557dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkPoint& firstPt = fPts[0];
558dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)];
559dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(newT == 0 || !precisely_zero(newT));
560dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(newT == 1 || !precisely_equal(newT, 1));
56107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // FIXME: in the pathological case where there is a ton of intercepts,
56207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    //  binary search?
56307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int insertedAt = -1;
5644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int tCount = fTs.count();
5654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int index = 0; index < tCount; ++index) {
56607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // OPTIMIZATION: if there are three or more identical Ts, then
56707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // the fourth and following could be further insertion-sorted so
56807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // that all the edges are clockwise or counterclockwise.
56907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // This could later limit segment tests to the two adjacent
57007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // neighbors, although it doesn't help with determining which
57107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // circular direction to go in.
5727eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        const SkOpSpan& span = fTs[index];
5737eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        if (newT < span.fT) {
57407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            insertedAt = index;
57507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            break;
57607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
5777eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        if (newT == span.fT) {
5787eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            if (pt == span.fPt) {
5797eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                insertedAt = index;
5807eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                break;
5817eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            }
5827eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1)) {
5837eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                insertedAt = index;
5847eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                break;
5857eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            }
5867eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        }
58707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
58807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* span;
58907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (insertedAt >= 0) {
59007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        span = fTs.insert(insertedAt);
59107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } else {
59207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        insertedAt = tCount;
59307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        span = fTs.append();
59407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
59507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fT = newT;
596dac1d17027dcaa5596885a9f333979418b35001ccaryclark    span->fOtherT = -1;
59707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fOther = other;
59807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fPt = pt;
599a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com#if 0
600a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com    // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d)
601a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com    SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX)
602a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com            && approximately_equal(xyAtT(newT).fY, pt.fY));
603a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com#endif
604dac1d17027dcaa5596885a9f333979418b35001ccaryclark    span->fFromAngle = NULL;
605dac1d17027dcaa5596885a9f333979418b35001ccaryclark    span->fToAngle = NULL;
60607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fWindSum = SK_MinS32;
60707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fOppSum = SK_MinS32;
60807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fWindValue = 1;
60907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fOppValue = 0;
6104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    span->fChased = false;
611dac1d17027dcaa5596885a9f333979418b35001ccaryclark    span->fCoincident = false;
6124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    span->fLoop = false;
613dac1d17027dcaa5596885a9f333979418b35001ccaryclark    span->fNear = false;
614dac1d17027dcaa5596885a9f333979418b35001ccaryclark    span->fMultiple = false;
6154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    span->fSmall = false;
6164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    span->fTiny = false;
617dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if ((span->fDone = newT == 1)) {
618dac1d17027dcaa5596885a9f333979418b35001ccaryclark        ++fDoneSpans;
619dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
62007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int less = -1;
621dac1d17027dcaa5596885a9f333979418b35001ccaryclark// FIXME: note that this relies on spans being a continguous array
6224431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// find range of spans with nearly the same point as this one
62365b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the moment
6244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) {
62507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fVerb == SkPath::kCubic_Verb) {
6264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            double tInterval = newT - span[less].fT;
62707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            double tMid = newT - tInterval / 2;
62807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
62907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (!midPt.approximatelyEqual(xyAtT(span))) {
63007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                break;
63107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
63207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
63307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        --less;
63407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
63507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int more = 1;
63665b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the moment
6374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, pt)) {
63807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fVerb == SkPath::kCubic_Verb) {
6394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            double tEndInterval = span[more].fT - newT;
64007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            double tMid = newT - tEndInterval / 2;
64107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid);
64207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (!midEndPt.approximatelyEqual(xyAtT(span))) {
64307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                break;
64407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
64507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
64607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++more;
64707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
6484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    ++less;
6494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    --more;
6504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (more - 1 > less && span[more].fPt == span[more - 1].fPt
6514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            && span[more].fT == span[more - 1].fT) {
6524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        --more;
6534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
6544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (less == more) {
6554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return insertedAt;
6564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
6574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (precisely_negative(span[more].fT - span[less].fT)) {
6584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return insertedAt;
6594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
6604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// if the total range of t values is big enough, mark all tiny
6614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool tiny = span[less].fPt == span[more].fPt;
6624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = less;
6634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
6644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        fSmall = span[index].fSmall = true;
6654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        fTiny |= span[index].fTiny = tiny;
6664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (!span[index].fDone) {
6674431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            span[index].fDone = true;
6684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            ++fDoneSpans;
6694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
6704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (++index < more);
67107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return insertedAt;
67207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
67307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
67407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// set spans from start to end to decrement by one
67507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// note this walks other backwards
676a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com// FIXME: there's probably an edge case that can be constructed where
67707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// two span in one segment are separated by float epsilon on one span but
67807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// not the other, if one segment is very small. For this
67907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// case the counts asserted below may or may not be enough to separate the
68007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// spans. Even if the counts work out, what if the spans aren't correctly
68107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// sorted? It feels better in such a case to match the span's other span
68207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// pointer since both coincident segments must contain the same spans.
683a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com// FIXME? It seems that decrementing by one will fail for complex paths that
684a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com// have three or more coincident edges. Shouldn't this subtract the difference
685a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com// between the winding values?
686570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com/*                                      |-->                           |-->
687570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comthis     0>>>>1>>>>2>>>>3>>>4      0>>>>1>>>>2>>>>3>>>4      0>>>>1>>>>2>>>>3>>>4
688570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comother         2<<<<1<<<<0               2<<<<1<<<<0               2<<<<1<<<<0
689570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com              ^         ^                 <--|                           <--|
690570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com           startPt    endPt        test/oTest first pos      test/oTest final pos
691570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com*/
692570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) {
69307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool binary = fOperand != other->fOperand;
69407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int index = 0;
695570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    while (startPt != fTs[index].fPt) {
696570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(index < fTs.count());
69707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++index;
69807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
6994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) {
7007eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        --index;
7017eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
702dac1d17027dcaa5596885a9f333979418b35001ccaryclark    bool oFoundEnd = false;
70307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oIndex = other->fTs.count();
704570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    while (startPt != other->fTs[--oIndex].fPt) {  // look for startPt match
705570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(oIndex > 0);
706570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
7077eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    double oStartT = other->fTs[oIndex].fT;
7087eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    // look for first point beyond match
7094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (startPt == other->fTs[--oIndex].fPt || precisely_equal(oStartT, other->fTs[oIndex].fT)) {
71065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        if (!oIndex) {
71165b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            return;  // tiny spans may move in the wrong direction
71265b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        }
713570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
71407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* test = &fTs[index];
71507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* oTest = &other->fTs[oIndex];
716570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
717570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
718dac1d17027dcaa5596885a9f333979418b35001ccaryclark    bool decrement, track, bigger;
719dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int originalWindValue;
720dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkPoint* testPt;
721dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkPoint* oTestPt;
72207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
723570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(test->fT < 1);
724570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(oTest->fT < 1);
725dac1d17027dcaa5596885a9f333979418b35001ccaryclark        decrement = test->fWindValue && oTest->fWindValue;
726dac1d17027dcaa5596885a9f333979418b35001ccaryclark        track = test->fWindValue || oTest->fWindValue;
727dac1d17027dcaa5596885a9f333979418b35001ccaryclark        bigger = test->fWindValue >= oTest->fWindValue;
728dac1d17027dcaa5596885a9f333979418b35001ccaryclark        testPt = &test->fPt;
7297eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        double testT = test->fT;
730dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oTestPt = &oTest->fPt;
7317eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        double oTestT = oTest->fT;
73207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        do {
73307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (decrement) {
734a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com                if (binary && bigger) {
735570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    test->fOppValue--;
736a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com                } else {
737570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    decrementSpan(test);
738a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com                }
739570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            } else if (track) {
740dac1d17027dcaa5596885a9f333979418b35001ccaryclark                TrackOutsidePair(&outsidePts, *testPt, *oTestPt);
74107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
742570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkASSERT(index < fTs.count() - 1);
743570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            test = &fTs[++index];
744dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (*testPt == test->fPt || precisely_equal(testT, test->fT));
745dac1d17027dcaa5596885a9f333979418b35001ccaryclark        originalWindValue = oTest->fWindValue;
746570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        do {
747570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkASSERT(oTest->fT < 1);
748570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkASSERT(originalWindValue == oTest->fWindValue);
74907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (decrement) {
750a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com                if (binary && !bigger) {
751570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    oTest->fOppValue--;
752a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com                } else {
753570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    other->decrementSpan(oTest);
754a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com                }
755570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            } else if (track) {
756dac1d17027dcaa5596885a9f333979418b35001ccaryclark                TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
75707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
75807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (!oIndex) {
75907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                break;
76007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
761dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oFoundEnd |= endPt == oTest->fPt;
762570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            oTest = &other->fTs[--oIndex];
763dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (*oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT));
7647eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    } while (endPt != test->fPt && test->fT < 1);
76507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // FIXME: determine if canceled edges need outside ts added
766dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (!oFoundEnd) {
767dac1d17027dcaa5596885a9f333979418b35001ccaryclark        for (int oIdx2 = oIndex; oIdx2 >= 0; --oIdx2) {
768dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkOpSpan* oTst2 = &other->fTs[oIdx2];
769dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (originalWindValue != oTst2->fWindValue) {
770dac1d17027dcaa5596885a9f333979418b35001ccaryclark                goto skipAdvanceOtherCancel;
771dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
772dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (!oTst2->fWindValue) {
773dac1d17027dcaa5596885a9f333979418b35001ccaryclark                goto skipAdvanceOtherCancel;
774dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
775dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (endPt == other->fTs[oIdx2].fPt) {
776dac1d17027dcaa5596885a9f333979418b35001ccaryclark                break;
777dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
778dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
779dac1d17027dcaa5596885a9f333979418b35001ccaryclark        do {
780dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(originalWindValue == oTest->fWindValue);
781dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (decrement) {
782dac1d17027dcaa5596885a9f333979418b35001ccaryclark                if (binary && !bigger) {
783dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    oTest->fOppValue--;
784dac1d17027dcaa5596885a9f333979418b35001ccaryclark                } else {
785dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    other->decrementSpan(oTest);
786dac1d17027dcaa5596885a9f333979418b35001ccaryclark                }
787dac1d17027dcaa5596885a9f333979418b35001ccaryclark            } else if (track) {
788dac1d17027dcaa5596885a9f333979418b35001ccaryclark                TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt);
789dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
790dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (!oIndex) {
791dac1d17027dcaa5596885a9f333979418b35001ccaryclark                break;
792dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
793dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oTest = &other->fTs[--oIndex];
794dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oFoundEnd |= endPt == oTest->fPt;
795dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (!oFoundEnd || endPt == oTest->fPt);
796dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
797dac1d17027dcaa5596885a9f333979418b35001ccaryclarkskipAdvanceOtherCancel:
798570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int outCount = outsidePts.count();
799570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!done() && outCount) {
800570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        addCancelOutsides(outsidePts[0], outsidePts[1], other);
801570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (outCount > 2) {
802570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other);
80307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
80407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
805570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!other->done() && oOutsidePts.count()) {
806570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this);
80707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
808dac1d17027dcaa5596885a9f333979418b35001ccaryclark    setCoincidentRange(startPt, endPt, other);
809dac1d17027dcaa5596885a9f333979418b35001ccaryclark    other->setCoincidentRange(startPt, endPt, this);
81007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
81107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
8124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgint SkOpSegment::addSelfT(const SkPoint& pt, double newT) {
813570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // if the tail nearly intersects itself but not quite, the caller records this separately
8144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int result = addT(this, pt, newT);
81507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* span = &fTs[result];
8164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    fLoop = span->fLoop = true;
81707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return result;
81807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
81907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
820dac1d17027dcaa5596885a9f333979418b35001ccaryclark// find the starting or ending span with an existing loop of angles
821dac1d17027dcaa5596885a9f333979418b35001ccaryclark// FIXME? replicate for all identical starting/ending spans?
822dac1d17027dcaa5596885a9f333979418b35001ccaryclark// OPTIMIZE? remove the spans pointing to windValue==0 here or earlier?
823dac1d17027dcaa5596885a9f333979418b35001ccaryclark// FIXME? assert that only one other span has a valid windValue or oppValue
8244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::addSimpleAngle(int index) {
825dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan* span = &fTs[index];
82619eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    int idx;
82719eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    int start, end;
82819eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    if (span->fT == 0) {
82919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        idx = 0;
83019eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        span = &fTs[0];
831dac1d17027dcaa5596885a9f333979418b35001ccaryclark        do {
832dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (span->fToAngle) {
833dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkASSERT(span->fToAngle->loopCount() == 2);
834dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkASSERT(!span->fFromAngle);
835dac1d17027dcaa5596885a9f333979418b35001ccaryclark                span->fFromAngle = span->fToAngle->next();
836dac1d17027dcaa5596885a9f333979418b35001ccaryclark                return;
837dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
83819eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark            span = &fTs[++idx];
839dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (span->fT == 0);
84019eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkASSERT(!fTs[0].fTiny && fTs[idx].fT > 0);
84119eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        addStartSpan(idx);
84219eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        start = 0;
84319eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        end = idx;
8444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
84519eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        idx = count() - 1;
84619eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        span = &fTs[idx];
847dac1d17027dcaa5596885a9f333979418b35001ccaryclark        do {
848dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (span->fFromAngle) {
849dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkASSERT(span->fFromAngle->loopCount() == 2);
850dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkASSERT(!span->fToAngle);
851dac1d17027dcaa5596885a9f333979418b35001ccaryclark                span->fToAngle = span->fFromAngle->next();
852dac1d17027dcaa5596885a9f333979418b35001ccaryclark                return;
853dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
85419eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark            span = &fTs[--idx];
855dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (span->fT == 1);
85619eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkASSERT(!fTs[idx].fTiny && fTs[idx].fT < 1);
85719eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        addEndSpan(++idx);
85819eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        start = idx;
85919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        end = count();
8604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
86119eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    SkOpSegment* other;
86219eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    SkOpSpan* oSpan;
86319eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    index = start;
86419eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    do {
86519eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        span = &fTs[index];
86619eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        other = span->fOther;
86719eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        int oFrom = span->fOtherIndex;
86819eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        oSpan = &other->fTs[oFrom];
86919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        if (oSpan->fT < 1 && oSpan->fWindValue) {
87019eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark            break;
87119eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        }
87219eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        if (oSpan->fT == 0) {
87319eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark            continue;
87419eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        }
87519eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        oFrom = other->nextExactSpan(oFrom, -1);
87619eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkOpSpan* oFromSpan = &other->fTs[oFrom];
87719eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkASSERT(oFromSpan->fT < 1);
87819eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        if (oFromSpan->fWindValue) {
87919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark            break;
88019eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        }
88119eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    } while (++index < end);
8824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* angle, * oAngle;
88319eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark    if (span->fT == 0) {
884dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(span->fOtherIndex - 1 >= 0);
885dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(span->fOtherT == 1);
88619eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkDEBUGCODE(int oPriorIndex = other->nextExactSpan(span->fOtherIndex, -1));
88719eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkDEBUGCODE(const SkOpSpan& oPrior = other->span(oPriorIndex));
8884431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(!oPrior.fTiny && oPrior.fT < 1);
889dac1d17027dcaa5596885a9f333979418b35001ccaryclark        other->addEndSpan(span->fOtherIndex);
890dac1d17027dcaa5596885a9f333979418b35001ccaryclark        angle = span->fToAngle;
89119eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        oAngle = oSpan->fFromAngle;
8924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
893dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(span->fOtherIndex + 1 < other->count());
894dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(span->fOtherT == 0);
89519eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        SkASSERT(!oSpan->fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0
896dac1d17027dcaa5596885a9f333979418b35001ccaryclark                || (other->fTs[span->fOtherIndex + 1].fFromAngle == NULL
897dac1d17027dcaa5596885a9f333979418b35001ccaryclark                && other->fTs[span->fOtherIndex + 1].fToAngle == NULL)));
8984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int oIndex = 1;
8994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
9004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan& osSpan = other->span(oIndex);
901dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (osSpan.fFromAngle || osSpan.fT > 0) {
9024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
9034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
9044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            ++oIndex;
9054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(oIndex < other->count());
9064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } while (true);
9074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        other->addStartSpan(oIndex);
908dac1d17027dcaa5596885a9f333979418b35001ccaryclark        angle = span->fFromAngle;
90919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark        oAngle = oSpan->fToAngle;
9104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
9114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    angle->insert(oAngle);
9124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
9134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
914dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::alignMultiples(SkTDArray<AlignedSpan>* alignedArray) {
915dac1d17027dcaa5596885a9f333979418b35001ccaryclark    debugValidate();
916dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int count = this->count();
917dac1d17027dcaa5596885a9f333979418b35001ccaryclark    for (int index = 0; index < count; ++index) {
918dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan& span = fTs[index];
919dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (!span.fMultiple) {
920dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
921dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
922dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int end = nextExactSpan(index, 1);
923dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(end > index + 1);
924dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkPoint& thisPt = span.fPt;
925dac1d17027dcaa5596885a9f333979418b35001ccaryclark        while (index < end - 1) {
926dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkOpSegment* other1 = span.fOther;
927dac1d17027dcaa5596885a9f333979418b35001ccaryclark            int oCnt = other1->count();
928dac1d17027dcaa5596885a9f333979418b35001ccaryclark            for (int idx2 = index + 1; idx2 < end; ++idx2) {
929dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkOpSpan& span2 = fTs[idx2];
930dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkOpSegment* other2 = span2.fOther;
931dac1d17027dcaa5596885a9f333979418b35001ccaryclark                for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
932dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    SkOpSpan& oSpan = other1->fTs[oIdx];
933dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    if (oSpan.fOther != other2) {
934dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        continue;
935dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    }
936dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    if (oSpan.fPt == thisPt) {
937dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        goto skipExactMatches;
938dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    }
939dac1d17027dcaa5596885a9f333979418b35001ccaryclark                }
940dac1d17027dcaa5596885a9f333979418b35001ccaryclark                for (int oIdx = 0; oIdx < oCnt; ++oIdx) {
941dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    SkOpSpan& oSpan = other1->fTs[oIdx];
942dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    if (oSpan.fOther != other2) {
943dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        continue;
944dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    }
945dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    if (SkDPoint::RoughlyEqual(oSpan.fPt, thisPt)) {
946dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        SkOpSpan& oSpan2 = other2->fTs[oSpan.fOtherIndex];
947dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        if (zero_or_one(span.fOtherT) || zero_or_one(oSpan.fT)
948dac1d17027dcaa5596885a9f333979418b35001ccaryclark                                || zero_or_one(span2.fOtherT) || zero_or_one(oSpan2.fT)) {
949dac1d17027dcaa5596885a9f333979418b35001ccaryclark                            return;
950dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        }
951dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        if (!way_roughly_equal(span.fOtherT, oSpan.fT)
952dac1d17027dcaa5596885a9f333979418b35001ccaryclark                                || !way_roughly_equal(span2.fOtherT, oSpan2.fT)
953dac1d17027dcaa5596885a9f333979418b35001ccaryclark                                || !way_roughly_equal(span2.fOtherT, oSpan.fOtherT)
954dac1d17027dcaa5596885a9f333979418b35001ccaryclark                                || !way_roughly_equal(span.fOtherT, oSpan2.fOtherT)) {
955dac1d17027dcaa5596885a9f333979418b35001ccaryclark                            return;
956dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        }
957dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        alignSpan(thisPt, span.fOtherT, other1, span2.fOtherT,
958dac1d17027dcaa5596885a9f333979418b35001ccaryclark                                other2, &oSpan, alignedArray);
959dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        alignSpan(thisPt, span2.fOtherT, other2, span.fOtherT,
960dac1d17027dcaa5596885a9f333979418b35001ccaryclark                                other1, &oSpan2, alignedArray);
961dac1d17027dcaa5596885a9f333979418b35001ccaryclark                        break;
962dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    }
963dac1d17027dcaa5596885a9f333979418b35001ccaryclark                }
964dac1d17027dcaa5596885a9f333979418b35001ccaryclark        skipExactMatches:
965dac1d17027dcaa5596885a9f333979418b35001ccaryclark                ;
966dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
967dac1d17027dcaa5596885a9f333979418b35001ccaryclark            ++index;
968dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
969dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
970dac1d17027dcaa5596885a9f333979418b35001ccaryclark    debugValidate();
971dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
972dac1d17027dcaa5596885a9f333979418b35001ccaryclark
973dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::alignSpan(const SkPoint& newPt, double newT, const SkOpSegment* other,
974dac1d17027dcaa5596885a9f333979418b35001ccaryclark        double otherT, const SkOpSegment* other2, SkOpSpan* oSpan,
975dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkTDArray<AlignedSpan>* alignedArray) {
976dac1d17027dcaa5596885a9f333979418b35001ccaryclark    AlignedSpan* aligned = alignedArray->append();
977dac1d17027dcaa5596885a9f333979418b35001ccaryclark    aligned->fOldPt = oSpan->fPt;
978dac1d17027dcaa5596885a9f333979418b35001ccaryclark    aligned->fPt = newPt;
979dac1d17027dcaa5596885a9f333979418b35001ccaryclark    aligned->fOldT = oSpan->fT;
980dac1d17027dcaa5596885a9f333979418b35001ccaryclark    aligned->fT = newT;
981dac1d17027dcaa5596885a9f333979418b35001ccaryclark    aligned->fSegment = this;  // OPTIMIZE: may be unused, can remove
982dac1d17027dcaa5596885a9f333979418b35001ccaryclark    aligned->fOther1 = other;
983dac1d17027dcaa5596885a9f333979418b35001ccaryclark    aligned->fOther2 = other2;
984dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(SkDPoint::RoughlyEqual(oSpan->fPt, newPt));
985dac1d17027dcaa5596885a9f333979418b35001ccaryclark    oSpan->fPt = newPt;
986dac1d17027dcaa5596885a9f333979418b35001ccaryclark//    SkASSERT(way_roughly_equal(oSpan->fT, newT));
987dac1d17027dcaa5596885a9f333979418b35001ccaryclark    oSpan->fT = newT;
988dac1d17027dcaa5596885a9f333979418b35001ccaryclark//    SkASSERT(way_roughly_equal(oSpan->fOtherT, otherT));
989dac1d17027dcaa5596885a9f333979418b35001ccaryclark    oSpan->fOtherT = otherT;
990dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
991dac1d17027dcaa5596885a9f333979418b35001ccaryclark
9924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgbool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) {
9934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool aligned = false;
9944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSpan* span = &fTs[index];
9954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSegment* other = span->fOther;
9964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int oIndex = span->fOtherIndex;
9974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSpan* oSpan = &other->fTs[oIndex];
9984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (span->fT != thisT) {
9994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        span->fT = thisT;
10004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        oSpan->fOtherT = thisT;
10014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        aligned = true;
10024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
10034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (span->fPt != thisPt) {
10044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        span->fPt = thisPt;
10054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        oSpan->fPt = thisPt;
10064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        aligned = true;
10074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
10084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    double oT = oSpan->fT;
10098cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    if (oT == 0) {
10104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return aligned;
10114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
10124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int oStart = other->nextSpan(oIndex, -1) + 1;
10134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    oSpan = &other->fTs[oStart];
10148cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    int otherIndex = oStart;
10158cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    if (oT == 1) {
10168cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        if (aligned) {
10178cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            while (oSpan->fPt == thisPt && oSpan->fT != 1) {
10188cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                oSpan->fTiny = true;
10198cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                ++oSpan;
10208cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            }
10218cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        }
10228cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        return aligned;
10238cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    }
10244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    oT = oSpan->fT;
10258cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    int oEnd = other->nextSpan(oIndex, 1);
10264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool oAligned = false;
10274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (oSpan->fPt != thisPt) {
10284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        oAligned |= other->alignSpan(oStart, oT, thisPt);
10294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
10304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (++otherIndex < oEnd) {
10314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkOpSpan* oNextSpan = &other->fTs[otherIndex];
10324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) {
10334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            oAligned |= other->alignSpan(otherIndex, oT, thisPt);
10344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
10354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
10364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (oAligned) {
10374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        other->alignSpanState(oStart, oEnd);
10384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
10394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return aligned;
10404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
10414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
10424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::alignSpanState(int start, int end) {
10434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSpan* lastSpan = &fTs[--end];
10444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool allSmall = lastSpan->fSmall;
10454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool allTiny = lastSpan->fTiny;
10464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool allDone = lastSpan->fDone;
10474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDEBUGCODE(int winding = lastSpan->fWindValue);
10484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDEBUGCODE(int oppWinding = lastSpan->fOppValue);
10494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = start;
10504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (index < end) {
10514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkOpSpan* span = &fTs[index];
10524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        span->fSmall = allSmall;
10534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        span->fTiny = allTiny;
10544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (span->fDone != allDone) {
10554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            span->fDone = allDone;
10564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            fDoneSpans += allDone ? 1 : -1;
10574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
10584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(span->fWindValue == winding);
10594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(span->fOppValue == oppWinding);
10604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        ++index;
10614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
10624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
10634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
1064dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::blindCancel(const SkCoincidence& coincidence, SkOpSegment* other) {
1065dac1d17027dcaa5596885a9f333979418b35001ccaryclark    bool binary = fOperand != other->fOperand;
1066dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int index = 0;
1067dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int last = this->count();
1068dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1069dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan& span = this->fTs[--last];
1070dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (span.fT != 1 && !span.fSmall) {
1071dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
1072dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1073dac1d17027dcaa5596885a9f333979418b35001ccaryclark        span.fCoincident = true;
1074dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (true);
1075dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int oIndex = other->count();
1076dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1077dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan& oSpan = other->fTs[--oIndex];
1078dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (oSpan.fT != 1 && !oSpan.fSmall) {
1079dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
1080dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1081dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oSpan.fCoincident = true;
1082dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (true);
1083dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1084dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan* test = &this->fTs[index];
1085dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int baseWind = test->fWindValue;
1086dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int baseOpp = test->fOppValue;
1087dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int endIndex = index;
1088dac1d17027dcaa5596885a9f333979418b35001ccaryclark        while (++endIndex <= last) {
1089dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkOpSpan* endSpan = &this->fTs[endIndex];
1090dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(endSpan->fT < 1);
1091dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) {
1092dac1d17027dcaa5596885a9f333979418b35001ccaryclark                break;
1093dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1094dac1d17027dcaa5596885a9f333979418b35001ccaryclark            endSpan->fCoincident = true;
1095dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1096dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan* oTest = &other->fTs[oIndex];
1097dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int oBaseWind = oTest->fWindValue;
1098dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int oBaseOpp = oTest->fOppValue;
1099dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int oStartIndex = oIndex;
1100dac1d17027dcaa5596885a9f333979418b35001ccaryclark        while (--oStartIndex >= 0) {
1101dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkOpSpan* oStartSpan = &other->fTs[oStartIndex];
1102dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (oStartSpan->fWindValue != oBaseWind || oStartSpan->fOppValue != oBaseOpp) {
1103dac1d17027dcaa5596885a9f333979418b35001ccaryclark                break;
1104dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1105dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oStartSpan->fCoincident = true;
1106dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1107dac1d17027dcaa5596885a9f333979418b35001ccaryclark        bool decrement = baseWind && oBaseWind;
1108dac1d17027dcaa5596885a9f333979418b35001ccaryclark        bool bigger = baseWind >= oBaseWind;
1109dac1d17027dcaa5596885a9f333979418b35001ccaryclark        do {
1110dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(test->fT < 1);
1111dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (decrement) {
1112dac1d17027dcaa5596885a9f333979418b35001ccaryclark                if (binary && bigger) {
1113dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    test->fOppValue--;
1114dac1d17027dcaa5596885a9f333979418b35001ccaryclark                } else {
1115dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    decrementSpan(test);
1116dac1d17027dcaa5596885a9f333979418b35001ccaryclark                }
1117dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1118dac1d17027dcaa5596885a9f333979418b35001ccaryclark            test->fCoincident = true;
1119dac1d17027dcaa5596885a9f333979418b35001ccaryclark            test = &fTs[++index];
1120dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (index < endIndex);
1121dac1d17027dcaa5596885a9f333979418b35001ccaryclark        do {
1122dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(oTest->fT < 1);
1123dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (decrement) {
1124dac1d17027dcaa5596885a9f333979418b35001ccaryclark                if (binary && !bigger) {
1125dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    oTest->fOppValue--;
1126dac1d17027dcaa5596885a9f333979418b35001ccaryclark                } else {
1127dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    other->decrementSpan(oTest);
1128dac1d17027dcaa5596885a9f333979418b35001ccaryclark                }
1129dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1130dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oTest->fCoincident = true;
1131dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oTest = &other->fTs[--oIndex];
1132dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (oIndex > oStartIndex);
1133dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (index <= last && oIndex >= 0);
1134dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(index > last);
1135dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(oIndex < 0);
1136dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
1137dac1d17027dcaa5596885a9f333979418b35001ccaryclark
1138dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other) {
1139dac1d17027dcaa5596885a9f333979418b35001ccaryclark    bool binary = fOperand != other->fOperand;
1140dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int index = 0;
1141dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int last = this->count();
1142dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1143dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan& span = this->fTs[--last];
1144dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (span.fT != 1 && !span.fSmall) {
1145dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
1146dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1147dac1d17027dcaa5596885a9f333979418b35001ccaryclark        span.fCoincident = true;
1148dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (true);
1149dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int oIndex = 0;
1150dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int oLast = other->count();
1151dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1152dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan& oSpan = other->fTs[--oLast];
1153dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (oSpan.fT != 1 && !oSpan.fSmall) {
1154dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
1155dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1156dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oSpan.fCoincident = true;
1157dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (true);
1158dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1159dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan* test = &this->fTs[index];
1160dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int baseWind = test->fWindValue;
1161dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int baseOpp = test->fOppValue;
1162dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int endIndex = index;
1163dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan* endSpan;
1164dac1d17027dcaa5596885a9f333979418b35001ccaryclark        while (++endIndex <= last) {
1165dac1d17027dcaa5596885a9f333979418b35001ccaryclark            endSpan = &this->fTs[endIndex];
1166dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(endSpan->fT < 1);
1167dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) {
1168dac1d17027dcaa5596885a9f333979418b35001ccaryclark                break;
1169dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1170dac1d17027dcaa5596885a9f333979418b35001ccaryclark            endSpan->fCoincident = true;
1171dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1172dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan* oTest = &other->fTs[oIndex];
1173dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int oBaseWind = oTest->fWindValue;
1174dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int oBaseOpp = oTest->fOppValue;
1175dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int oEndIndex = oIndex;
1176dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan* oEndSpan;
1177dac1d17027dcaa5596885a9f333979418b35001ccaryclark        while (++oEndIndex <= oLast) {
1178dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oEndSpan = &this->fTs[oEndIndex];
1179dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(oEndSpan->fT < 1);
1180dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (oEndSpan->fWindValue != oBaseWind || oEndSpan->fOppValue != oBaseOpp) {
1181dac1d17027dcaa5596885a9f333979418b35001ccaryclark                break;
1182dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1183dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oEndSpan->fCoincident = true;
1184dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1185dac1d17027dcaa5596885a9f333979418b35001ccaryclark        // consolidate the winding count even if done
1186dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if ((test->fWindValue || test->fOppValue) && (oTest->fWindValue || oTest->fOppValue)) {
1187dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1188dac1d17027dcaa5596885a9f333979418b35001ccaryclark                bumpCoincidentBlind(binary, index, endIndex);
1189dac1d17027dcaa5596885a9f333979418b35001ccaryclark                other->bumpCoincidentOBlind(oIndex, oEndIndex);
1190dac1d17027dcaa5596885a9f333979418b35001ccaryclark            } else {
1191dac1d17027dcaa5596885a9f333979418b35001ccaryclark                other->bumpCoincidentBlind(binary, oIndex, oEndIndex);
1192dac1d17027dcaa5596885a9f333979418b35001ccaryclark                bumpCoincidentOBlind(index, endIndex);
1193dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1194dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1195dac1d17027dcaa5596885a9f333979418b35001ccaryclark        index = endIndex;
1196dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oIndex = oEndIndex;
1197dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (index <= last && oIndex <= oLast);
1198dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(index > last);
1199dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(oIndex > oLast);
1200dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
1201dac1d17027dcaa5596885a9f333979418b35001ccaryclark
1202dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::bumpCoincidentBlind(bool binary, int index, int endIndex) {
1203dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkOpSpan& oTest = fTs[index];
1204dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int oWindValue = oTest.fWindValue;
1205dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int oOppValue = oTest.fOppValue;
1206dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (binary) {
1207dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkTSwap<int>(oWindValue, oOppValue);
1208dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1209dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1210dac1d17027dcaa5596885a9f333979418b35001ccaryclark        (void) bumpSpan(&fTs[index], oWindValue, oOppValue);
1211dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (++index < endIndex);
1212dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
1213dac1d17027dcaa5596885a9f333979418b35001ccaryclark
1214570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr,
1215570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkTArray<SkPoint, true>* outsideTs) {
1216570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int index = *indexPtr;
121707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oWindValue = oTest.fWindValue;
121807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oOppValue = oTest.fOppValue;
1219570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (binary) {
122007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkTSwap<int>(oWindValue, oOppValue);
122107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
122207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* const test = &fTs[index];
122307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* end = test;
1224570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkPoint& oStartPt = oTest.fPt;
122507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
122607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (bumpSpan(end, oWindValue, oOppValue)) {
1227570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            TrackOutside(outsideTs, oStartPt);
122807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
122907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        end = &fTs[++index];
12304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && end->fT < 1);
1231570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    *indexPtr = index;
1232570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
1233570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
1234dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) {
1235dac1d17027dcaa5596885a9f333979418b35001ccaryclark    do {
1236dac1d17027dcaa5596885a9f333979418b35001ccaryclark        zeroSpan(&fTs[index]);
1237dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (++index < endIndex);
1238dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
1239dac1d17027dcaa5596885a9f333979418b35001ccaryclark
124007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// because of the order in which coincidences are resolved, this and other
124107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// may not have the same intermediate points. Compute the corresponding
124207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// intermediate T values (using this as the master, other as the follower)
124307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// and walk other conditionally -- hoping that it catches up in the end
1244570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr,
1245570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkTArray<SkPoint, true>* oOutsidePts) {
1246570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int oIndex = *oIndexPtr;
124707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* const oTest = &fTs[oIndex];
124807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* oEnd = oTest;
1249570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkPoint& oStartPt = oTest->fPt;
12507eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    double oStartT = oTest->fT;
12514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if 0  // FIXME : figure out what disabling this breaks
12524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkPoint& startPt = test.fPt;
12534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find proper condition
12544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
1255570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        TrackOutside(oOutsidePts, startPt);
1256570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
12574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
12584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) {
125907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        zeroSpan(oEnd);
126007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        oEnd = &fTs[++oIndex];
126107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
1262570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    *oIndexPtr = oIndex;
126307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
126407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
126507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// FIXME: need to test this case:
126607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// contourA has two segments that are coincident
126707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// contourB has two segments that are coincident in the same place
126807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// each ends up with +2/0 pairs for winding count
126907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// since logic below doesn't transfer count (only increments/decrements) can this be
127007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// resolved to +4/0 ?
127107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
127207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// set spans from start to end to increment the greater by one and decrement
127307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// the lesser
1274630240d18805faf81d8e75172496ad165c2226b2caryclarkbool SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
1275570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSegment* other) {
1276570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool binary = fOperand != other->fOperand;
127707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int index = 0;
1278570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    while (startPt != fTs[index].fPt) {
1279570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(index < fTs.count());
128007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++index;
128107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
12827eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    double startT = fTs[index].fT;
12834431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) {
12847eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        --index;
12857eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
128607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oIndex = 0;
1287570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    while (startPt != other->fTs[oIndex].fPt) {
1288570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(oIndex < other->fTs.count());
128907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++oIndex;
129007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
12917eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    double oStartT = other->fTs[oIndex].fT;
12924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) {
12937eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        --oIndex;
12947eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
1295570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts;
1296570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts;
129707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* test = &fTs[index];
1298570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkPoint* testPt = &test->fPt;
12997eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    double testT = test->fT;
130007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* oTest = &other->fTs[oIndex];
1301570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkPoint* oTestPt = &oTest->fPt;
1302361b8b088589748e4b29895a4ebc5316e881e219caryclark    // paths with extreme data will fail this test and eject out of pathops altogether later on
1303361b8b088589748e4b29895a4ebc5316e881e219caryclark    // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
130407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
1305570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(test->fT < 1);
1306630240d18805faf81d8e75172496ad165c2226b2caryclark        if (oTest->fT == 1) {
1307630240d18805faf81d8e75172496ad165c2226b2caryclark            // paths with extreme data may be so mismatched that we fail here
1308630240d18805faf81d8e75172496ad165c2226b2caryclark            return false;
1309630240d18805faf81d8e75172496ad165c2226b2caryclark        }
13104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
13114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // consolidate the winding count even if done
1312570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if ((test->fWindValue == 0 && test->fOppValue == 0)
1313570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) {
1314570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkDEBUGCODE(int firstWind = test->fWindValue);
1315570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkDEBUGCODE(int firstOpp = test->fOppValue);
1316570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            do {
1317570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkASSERT(firstWind == fTs[index].fWindValue);
1318570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkASSERT(firstOpp == fTs[index].fOppValue);
1319570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                ++index;
1320570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkASSERT(index < fTs.count());
1321570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            } while (*testPt == fTs[index].fPt);
1322570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkDEBUGCODE(firstWind = oTest->fWindValue);
1323570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkDEBUGCODE(firstOpp = oTest->fOppValue);
1324570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            do {
1325570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkASSERT(firstWind == other->fTs[oIndex].fWindValue);
1326570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkASSERT(firstOpp == other->fTs[oIndex].fOppValue);
1327570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                ++oIndex;
1328570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkASSERT(oIndex < other->fTs.count());
1329570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            } while (*oTestPt == other->fTs[oIndex].fPt);
133007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        } else {
1331570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
1332570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                bumpCoincidentThis(*oTest, binary, &index, &outsidePts);
1333570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
1334570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            } else {
1335570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
1336570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                bumpCoincidentOther(*oTest, &index, &outsidePts);
1337570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
133807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
133907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        test = &fTs[index];
1340570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        testPt = &test->fPt;
13417eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        testT = test->fT;
134207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        oTest = &other->fTs[oIndex];
1343570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        oTestPt = &oTest->fPt;
13444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (endPt == *testPt || precisely_equal(endT, testT)) {
13454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
13464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
13474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org//        SkASSERT(AlmostEqualUlps(*testPt, *oTestPt));
1348570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } while (endPt != *oTestPt);
13494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // in rare cases, one may have ended before the other
13504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (endPt != *testPt && !precisely_equal(endT, testT)) {
13517eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        int lastWind = test[-1].fWindValue;
13527eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        int lastOpp = test[-1].fOppValue;
13537eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        bool zero = lastWind == 0 && lastOpp == 0;
13547eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        do {
13557eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            if (test->fWindValue || test->fOppValue) {
13567eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                test->fWindValue = lastWind;
13577eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                test->fOppValue = lastOpp;
13587eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                if (zero) {
13597eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                    test->fDone = true;
13607eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                    ++fDoneSpans;
13617eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                }
13627eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            }
13637eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            test = &fTs[++index];
13647eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            testPt = &test->fPt;
13657eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        } while (endPt != *testPt);
13664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
13674431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (endPt != *oTestPt) {
13684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // look ahead to see if zeroing more spans will allows us to catch up
13694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int oPeekIndex = oIndex;
13704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        bool success = true;
13714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkOpSpan* oPeek;
1372dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int oCount = other->count();
13734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
13744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            oPeek = &other->fTs[oPeekIndex];
1375dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (++oPeekIndex == oCount) {
13764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                success = false;
13774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
13784431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
13794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } while (endPt != oPeek->fPt);
13804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (success) {
13814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            // make sure the matching point completes the coincidence span
13824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            success = false;
13834431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            do {
13844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (oPeek->fOther == this) {
13854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    success = true;
13864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    break;
13874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
138819eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark                if (++oPeekIndex == oCount) {
138919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark                    break;
139019eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark                }
139119eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark                oPeek = &other->fTs[oPeekIndex];
13924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            } while (endPt == oPeek->fPt);
13934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
13944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (success) {
13954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            do {
13964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (!binary || test->fWindValue + oTest->fOppValue >= 0) {
13974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts);
13984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                } else {
13994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts);
14004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
14014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                oTest = &other->fTs[oIndex];
14024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                oTestPt = &oTest->fPt;
14034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            } while (endPt != *oTestPt);
14044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
14054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
1406570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int outCount = outsidePts.count();
1407570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!done() && outCount) {
1408570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        addCoinOutsides(outsidePts[0], endPt, other);
140907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
1410570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!other->done() && oOutsidePts.count()) {
1411570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        other->addCoinOutsides(oOutsidePts[0], endPt, this);
141207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
1413dac1d17027dcaa5596885a9f333979418b35001ccaryclark    setCoincidentRange(startPt, endPt, other);
1414dac1d17027dcaa5596885a9f333979418b35001ccaryclark    other->setCoincidentRange(startPt, endPt, this);
1415630240d18805faf81d8e75172496ad165c2226b2caryclark    return true;
141607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
141707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
141807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// FIXME: this doesn't prevent the same span from being added twice
141907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// fix in caller, SkASSERT here?
142065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark// FIXME: this may erroneously reject adds for cubic loops
14214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgconst SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
1422dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkPoint& pt, const SkPoint& pt2) {
142307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int tCount = fTs.count();
142407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    for (int tIndex = 0; tIndex < tCount; ++tIndex) {
142507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const SkOpSpan& span = fTs[tIndex];
142607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (!approximately_negative(span.fT - t)) {
142707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            break;
142807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
142965b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        if (span.fOther == other) {
143065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            bool tsMatch = approximately_equal(span.fT, t);
143165b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            bool otherTsMatch = approximately_equal(span.fOtherT, otherT);
143265b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            // FIXME: add cubic loop detecting logic here
143365b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            // if fLoop bit is set on span, that could be enough if addOtherT copies the bit
143465b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            // or if a new bit is added ala fOtherLoop
143565b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            if (tsMatch || otherTsMatch) {
143607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_ADD_T_PAIR
143765b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
143865b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                        __FUNCTION__, fID, t, other->fID, otherT);
143907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
144065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                return NULL;
144165b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            }
144265b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        }
144365b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    }
144465b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    int oCount = other->count();
144565b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    for (int oIndex = 0; oIndex < oCount; ++oIndex) {
144665b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        const SkOpSpan& oSpan = other->span(oIndex);
144765b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        if (!approximately_negative(oSpan.fT - otherT)) {
144865b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            break;
144965b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        }
145065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        if (oSpan.fOther == this) {
145165b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            bool otherTsMatch = approximately_equal(oSpan.fT, otherT);
145265b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            bool tsMatch = approximately_equal(oSpan.fOtherT, t);
145365b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            if (otherTsMatch || tsMatch) {
145465b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark#if DEBUG_ADD_T_PAIR
145565b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                SkDebugf("%s addTPair other duplicate this=%d %1.9g other=%d %1.9g\n",
145665b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                        __FUNCTION__, fID, t, other->fID, otherT);
145765b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark#endif
145865b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                return NULL;
145965b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            }
146007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
146107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
146207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_ADD_T_PAIR
146307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
146407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            __FUNCTION__, fID, t, other->fID, otherT);
146507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
146665b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    SkASSERT(other != this);
1467866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org    int insertedAt = addT(other, pt, t);
1468dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int otherInsertedAt = other->addT(this, pt2, otherT);
146907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    addOtherT(insertedAt, otherT, otherInsertedAt);
147007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    other->addOtherT(otherInsertedAt, t, insertedAt);
147107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    matchWindingValue(insertedAt, t, borrowWind);
147207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    other->matchWindingValue(otherInsertedAt, otherT, borrowWind);
1473dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan& span = this->fTs[insertedAt];
1474dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (pt != pt2) {
1475dac1d17027dcaa5596885a9f333979418b35001ccaryclark        span.fNear = true;
1476dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan& oSpan = other->fTs[otherInsertedAt];
1477dac1d17027dcaa5596885a9f333979418b35001ccaryclark        oSpan.fNear = true;
1478dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1479dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return &span;
148007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
148107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1482dac1d17027dcaa5596885a9f333979418b35001ccaryclarkconst SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
1483dac1d17027dcaa5596885a9f333979418b35001ccaryclark                           const SkPoint& pt) {
1484dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return addTPair(t, other, otherT, borrowWind, pt, pt);
148507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
148607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1487570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const {
1488570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkPoint midPt = ptAtT(midT);
1489570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkPathOpsBounds bounds;
1490570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY);
1491570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bounds.sort();
1492570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return bounds.almostContains(midPt);
1493570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
1494570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
149507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::betweenTs(int lesser, double testT, int greater) const {
149607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (lesser > greater) {
149707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkTSwap<int>(lesser, greater);
149807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
149907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
150007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
150107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
15024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// in extreme cases (like the buffer overflow test) return false to abort
15034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// for now, if one t value represents two different points, then the values are too extreme
15044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// to generate meaningful results
15054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgbool SkOpSegment::calcAngles() {
15064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int spanCount = fTs.count();
15074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (spanCount <= 2) {
15084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return spanCount == 2;
15094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
15104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = 1;
15114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* firstSpan = &fTs[index];
15124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int activePrior = checkSetAngle(0);
15134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* span = &fTs[0];
15144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther->multipleEnds()) {
15154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        index = findStartSpan(0);  // curve start intersects
1516361b8b088589748e4b29895a4ebc5316e881e219caryclark        if (fTs[index].fT == 0) {
1517361b8b088589748e4b29895a4ebc5316e881e219caryclark            return false;
1518361b8b088589748e4b29895a4ebc5316e881e219caryclark        }
1519dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(index > 0);
15204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (activePrior >= 0) {
15214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            addStartSpan(index);
1522570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
15234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
15244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool addEnd;
15254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int endIndex = spanCount - 1;
15264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    span = &fTs[endIndex - 1];
15274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if ((addEnd = span->fT == 1 || span->fTiny)) {  // if curve end intersects
15284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        endIndex = findEndSpan(endIndex);
1529dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(endIndex > 0);
15304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
15314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleStarts();
15324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
15334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(endIndex >= index);
15344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int prior = 0;
15354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (index < endIndex) {
15364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& fromSpan = fTs[index];  // for each intermediate intersection
15374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan* lastSpan;
15384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        span = &fromSpan;
15394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int start = index;
15404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
15414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            lastSpan = span;
15424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            span = &fTs[++index];
15434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(index < spanCount);
15444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny) {
1545570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                break;
1546570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
15474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) {
15484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                return false;
15494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
15504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } while (true);
1551dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* angle = NULL;
1552dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* priorAngle;
15534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (activePrior >= 0) {
15544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int pActive = firstActive(prior);
15554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(pActive < start);
1556dac1d17027dcaa5596885a9f333979418b35001ccaryclark            priorAngle = &fAngles.push_back();
1557dac1d17027dcaa5596885a9f333979418b35001ccaryclark            priorAngle->set(this, start, pActive);
155807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
15594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int active = checkSetAngle(start);
15604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (active >= 0) {
15614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(active < index);
1562dac1d17027dcaa5596885a9f333979418b35001ccaryclark            angle = &fAngles.push_back();
1563dac1d17027dcaa5596885a9f333979418b35001ccaryclark            angle->set(this, active, index);
156407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
15654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    #if DEBUG_ANGLE
15664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        debugCheckPointsEqualish(start, index);
15674431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    #endif
15684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        prior = start;
15694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
15704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan* startSpan = &fTs[start - 1];
1571dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (!startSpan->fSmall || isCanceled(start - 1) || startSpan->fFromAngle
1572dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    || startSpan->fToAngle) {
15734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
15744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
15754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            --start;
15764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } while (start > 0);
15774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
15784431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (activePrior >= 0) {
1579dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkASSERT(fTs[start].fFromAngle == NULL);
1580dac1d17027dcaa5596885a9f333979418b35001ccaryclark                fTs[start].fFromAngle = priorAngle;
15814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
15824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (active >= 0) {
1583dac1d17027dcaa5596885a9f333979418b35001ccaryclark                SkASSERT(fTs[start].fToAngle == NULL);
1584dac1d17027dcaa5596885a9f333979418b35001ccaryclark                fTs[start].fToAngle = angle;
15854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
15864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } while (++start < index);
15874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        activePrior = active;
158807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
15894431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (addEnd && activePrior >= 0) {
15904431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        addEndSpan(endIndex);
1591570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
15924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return true;
15934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
15944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
15954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgint SkOpSegment::checkSetAngle(int tIndex) const {
15964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* span = &fTs[tIndex];
15974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (span->fTiny /* || span->fSmall */) {
15984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        span = &fTs[++tIndex];
1599570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
16004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return isCanceled(tIndex) ? -1 : tIndex;
16014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
16024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
1603dac1d17027dcaa5596885a9f333979418b35001ccaryclark// at this point, the span is already ordered, or unorderable
16044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgint SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType) {
16054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(includeType != SkOpAngle::kUnaryXor);
16064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex);
160765b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    if (NULL == firstAngle || NULL == firstAngle->next()) {
16084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return SK_NaN32;
1609570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
1610570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // if all angles have a computed winding,
1611570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    //  or if no adjacent angles are orderable,
1612570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    //  or if adjacent orderable angles have no computed winding,
1613570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    //  there's nothing to do
1614dac1d17027dcaa5596885a9f333979418b35001ccaryclark    // if two orderable angles are adjacent, and both are next to orderable angles,
1615dac1d17027dcaa5596885a9f333979418b35001ccaryclark    //  and one has winding computed, transfer to the other
16164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* baseAngle = NULL;
1617570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool tryReverse = false;
1618570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // look for counterclockwise transfers
1619dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle* angle = firstAngle->previous();
1620dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle* next = angle->next();
1621dac1d17027dcaa5596885a9f333979418b35001ccaryclark    firstAngle = next;
162207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
1623dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* prior = angle;
1624dac1d17027dcaa5596885a9f333979418b35001ccaryclark        angle = next;
1625dac1d17027dcaa5596885a9f333979418b35001ccaryclark        next = angle->next();
1626dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(prior->next() == angle);
1627dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(angle->next() == next);
1628dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
1629dac1d17027dcaa5596885a9f333979418b35001ccaryclark            baseAngle = NULL;
16304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
16314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
1632dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int testWinding = angle->segment()->windSum(angle);
1633dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (SK_MinS32 != testWinding) {
1634dac1d17027dcaa5596885a9f333979418b35001ccaryclark            baseAngle = angle;
16354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            tryReverse = true;
16364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
16374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
16384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (baseAngle) {
16394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            ComputeOneSum(baseAngle, angle, includeType);
16404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
16414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
1642dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (next != firstAngle);
1643dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(firstAngle)) {
16444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        firstAngle = baseAngle;
16454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        tryReverse = true;
16464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
16474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (tryReverse) {
16484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        baseAngle = NULL;
1649dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* prior = firstAngle;
1650570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        do {
1651dac1d17027dcaa5596885a9f333979418b35001ccaryclark            angle = prior;
1652dac1d17027dcaa5596885a9f333979418b35001ccaryclark            prior = angle->previous();
1653dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(prior->next() == angle);
1654dac1d17027dcaa5596885a9f333979418b35001ccaryclark            next = angle->next();
1655dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (prior->unorderable() || angle->unorderable() || next->unorderable()) {
1656dac1d17027dcaa5596885a9f333979418b35001ccaryclark                baseAngle = NULL;
1657dac1d17027dcaa5596885a9f333979418b35001ccaryclark                continue;
1658dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
16594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int testWinding = angle->segment()->windSum(angle);
16604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (SK_MinS32 != testWinding) {
16614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                baseAngle = angle;
1662570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                continue;
166307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
1664570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            if (baseAngle) {
16654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                ComputeOneSumReverse(baseAngle, angle, includeType);
16664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL;
1667570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
1668dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (prior != firstAngle);
1669570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
167007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int minIndex = SkMin32(startIndex, endIndex);
167107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return windSum(minIndex);
167207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
167307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1674570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1675570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpAngle::IncludeType includeType) {
1676570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkOpSegment* baseSegment = baseAngle->segment();
1677570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
1678570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int sumSuWinding;
1679570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool binary = includeType >= SkOpAngle::kBinarySingle;
1680570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (binary) {
1681570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle);
1682570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (baseSegment->operand()) {
1683570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkTSwap<int>(sumMiWinding, sumSuWinding);
1684570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
1685570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
1686570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkOpSegment* nextSegment = nextAngle->segment();
1687570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int maxWinding, sumWinding;
1688570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkOpSpan* last;
1689570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (binary) {
1690570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        int oppMaxWinding, oppSumWinding;
1691570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1692570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1693570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1694866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org                nextAngle);
1695570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } else {
1696570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
1697570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                &maxWinding, &sumWinding);
1698866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1699570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
1700570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    nextAngle->setLastMarked(last);
1701570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
1702570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
1703570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
1704570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpAngle::IncludeType includeType) {
1705570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkOpSegment* baseSegment = baseAngle->segment();
1706570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int sumMiWinding = baseSegment->updateWinding(baseAngle);
1707570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int sumSuWinding;
1708570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool binary = includeType >= SkOpAngle::kBinarySingle;
1709570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (binary) {
1710570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        sumSuWinding = baseSegment->updateOppWinding(baseAngle);
1711570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (baseSegment->operand()) {
1712570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkTSwap<int>(sumMiWinding, sumSuWinding);
1713570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
1714570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
1715570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkOpSegment* nextSegment = nextAngle->segment();
1716570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int maxWinding, sumWinding;
1717570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkOpSpan* last;
1718570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (binary) {
1719570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        int oppMaxWinding, oppSumWinding;
1720570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1721570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
1722570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
1723866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org                nextAngle);
1724570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } else {
1725570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
1726570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                &maxWinding, &sumWinding);
1727866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle);
1728570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
1729570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    nextAngle->setLastMarked(last);
1730570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
1731570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
17328cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.orgbool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const {
17338cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    int step = index < endIndex ? 1 : -1;
17348cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    do {
17358cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        const SkOpSpan& span = this->span(index);
17368cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        if (span.fPt == pt) {
17378cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            const SkOpSpan& endSpan = this->span(endIndex);
17388cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            return span.fT == endSpan.fT && pt != endSpan.fPt;
17398cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        }
17408cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        index += step;
17418cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    } while (index != endIndex);
17428cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    return false;
17434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
17444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
1745dac1d17027dcaa5596885a9f333979418b35001ccaryclarkbool SkOpSegment::containsT(double t, const SkOpSegment* other, double otherT) const {
1746dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int count = this->count();
1747dac1d17027dcaa5596885a9f333979418b35001ccaryclark    for (int index = 0; index < count; ++index) {
1748dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkOpSpan& span = fTs[index];
1749dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (t < span.fT) {
1750dac1d17027dcaa5596885a9f333979418b35001ccaryclark            return false;
1751dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1752dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (t == span.fT) {
1753dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (other != span.fOther) {
1754dac1d17027dcaa5596885a9f333979418b35001ccaryclark                continue;
1755dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1756dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (other->fVerb != SkPath::kCubic_Verb) {
1757dac1d17027dcaa5596885a9f333979418b35001ccaryclark                return true;
1758dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1759dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (!other->fLoop) {
1760dac1d17027dcaa5596885a9f333979418b35001ccaryclark                return true;
1761dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
1762dac1d17027dcaa5596885a9f333979418b35001ccaryclark            double otherMidT = (otherT + span.fOtherT) / 2;
1763dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkPoint otherPt = other->ptAtT(otherMidT);
1764dac1d17027dcaa5596885a9f333979418b35001ccaryclark            return SkDPoint::ApproximatelyEqual(span.fPt, otherPt);
1765dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1766dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1767dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return false;
1768dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
1769dac1d17027dcaa5596885a9f333979418b35001ccaryclark
177007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT,
177107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                              bool* hitSomething, double mid, bool opp, bool current) const {
177207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar bottom = fBounds.fBottom;
177307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int bestTIndex = -1;
177407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (bottom <= *bestY) {
177507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bestTIndex;
177607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
177707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar top = fBounds.fTop;
177807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (top >= basePt.fY) {
177907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bestTIndex;
178007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
178107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fBounds.fLeft > basePt.fX) {
178207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bestTIndex;
178307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
178407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fBounds.fRight < basePt.fX) {
178507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bestTIndex;
178607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
178707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fBounds.fLeft == fBounds.fRight) {
178807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // if vertical, and directly above test point, wait for another one
178907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex;
179007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
179107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // intersect ray starting at basePt with edge
179207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkIntersections intersections;
179307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // OPTIMIZE: use specialty function that intersects ray with curve,
179407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // returning t values only for curve (we don't care about t on ray)
1795a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    intersections.allowNear(false);
1796cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
1797cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            (fPts, top, bottom, basePt.fX, false);
179807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (pts == 0 || (current && pts == 1)) {
179907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bestTIndex;
180007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
180107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (current) {
180207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkASSERT(pts > 1);
180307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        int closestIdx = 0;
180407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        double closest = fabs(intersections[0][0] - mid);
180507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        for (int idx = 1; idx < pts; ++idx) {
180607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            double test = fabs(intersections[0][idx] - mid);
180707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (closest > test) {
180807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                closestIdx = idx;
180907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                closest = test;
181007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
181107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
181207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        intersections.quickRemoveOne(closestIdx, --pts);
181307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
181407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double bestT = -1;
181507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    for (int index = 0; index < pts; ++index) {
181607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        double foundT = intersections[0][index];
181707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (approximately_less_than_zero(foundT)
181807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    || approximately_greater_than_one(foundT)) {
181907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            continue;
182007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
1821277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com        SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY;
182207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (approximately_negative(testY - *bestY)
182307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                || approximately_negative(basePt.fY - testY)) {
182407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            continue;
182507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
182607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (pts > 1 && fVerb == SkPath::kLine_Verb) {
182707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return SK_MinS32;  // if the intersection is edge on, wait for another one
182807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
182907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fVerb > SkPath::kLine_Verb) {
1830277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com            SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX;
183107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (approximately_zero(dx)) {
183207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                return SK_MinS32;  // hit vertical, wait for another one
183307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
183407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
183507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *bestY = testY;
183607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        bestT = foundT;
183707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
183807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (bestT < 0) {
183907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bestTIndex;
184007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
184107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(bestT >= 0);
184207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(bestT <= 1);
184307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int start;
184407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int end = 0;
184507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
184607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        start = end;
184707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        end = nextSpan(start, 1);
184807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } while (fTs[end].fT < bestT);
184907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // FIXME: see next candidate for a better pattern to find the next start/end pair
185007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (start + 1 < end && fTs[start].fDone) {
185107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++start;
185207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
185307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!isCanceled(start)) {
185407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *hitT = bestT;
185507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        bestTIndex = start;
185607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *hitSomething = true;
185707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
185807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return bestTIndex;
185907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
186007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
1861570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool SkOpSegment::decrementSpan(SkOpSpan* span) {
186207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(span->fWindValue > 0);
186307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (--(span->fWindValue) == 0) {
186407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (!span->fOppValue && !span->fDone) {
186507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            span->fDone = true;
186607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            ++fDoneSpans;
1867570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            return true;
186807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
186907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
1870570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return false;
187107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
187207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
187307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) {
18747eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    SkASSERT(!span->fDone || span->fTiny || span->fSmall);
187507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fWindValue += windDelta;
187607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(span->fWindValue >= 0);
187707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fOppValue += oppDelta;
187807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(span->fOppValue >= 0);
187907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fXor) {
188007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        span->fWindValue &= 1;
188107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
188207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fOppXor) {
188307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        span->fOppValue &= 1;
188407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
188507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!span->fWindValue && !span->fOppValue) {
188607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        span->fDone = true;
188707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++fDoneSpans;
188807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return true;
188907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
189007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return false;
189107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
189207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
18934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgconst SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const {
18944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* firstSpan = &thisSpan; // rewind to the start
18954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* beginSpan = fTs.begin();
18964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkPoint& testPt = thisSpan.fPt;
18974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) {
18984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        --firstSpan;
18994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
19004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return *firstSpan;
19014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
19024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
19034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgconst SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const {
19044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be small
19054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* lastSpan = &thisSpan;  // find the end
19064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkPoint& testPt = thisSpan.fPt;
19074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (lastSpan < endSpan && lastSpan[1].fPt == testPt) {
19084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        ++lastSpan;
19094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
19104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return *lastSpan;
19114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
19124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
19134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// with a loop, the comparison is move involved
19144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// scan backwards and forwards to count all matching points
19154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// (verify that there are twp scans marked as loops)
19164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// compare that against 2 matching scans for loop plus other results
19174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgbool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts) {
19184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the start
19194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan& lastSpan = this->lastSpan(thisSpan);  // find the end
19204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    double firstLoopT = -1, lastLoopT = -1;
19214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* testSpan = &firstSpan - 1;
19224431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (++testSpan <= &lastSpan) {
19234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (testSpan->fLoop) {
19244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            firstLoopT = testSpan->fT;
19254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
19264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
19274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
19284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    testSpan = &lastSpan + 1;
19294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (--testSpan >= &firstSpan) {
19304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (testSpan->fLoop) {
19314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            lastLoopT = testSpan->fT;
19324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
19334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
19344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
19354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT((firstLoopT == -1) == (lastLoopT == -1));
19364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (firstLoopT == -1) {
19374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return false;
19384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
19394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(firstLoopT < lastLoopT);
19404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    testSpan = &firstSpan - 1;
19414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    smallCounts[0] = smallCounts[1] = 0;
19424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (++testSpan <= &lastSpan) {
19434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(approximately_equal(testSpan->fT, firstLoopT) +
19444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                approximately_equal(testSpan->fT, lastLoopT) == 1);
19454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++;
19464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
19474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return true;
19484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
19494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
1950dac1d17027dcaa5596885a9f333979418b35001ccaryclarkdouble SkOpSegment::calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max,
1951dac1d17027dcaa5596885a9f333979418b35001ccaryclark        double hiEnd, const SkOpSegment* other, int thisStart) {
1952dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (max >= hiEnd) {
1953dac1d17027dcaa5596885a9f333979418b35001ccaryclark        return -1;
1954dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1955dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int end = findOtherT(hiEnd, ref);
1956dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (end < 0) {
1957dac1d17027dcaa5596885a9f333979418b35001ccaryclark        return -1;
1958dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1959dac1d17027dcaa5596885a9f333979418b35001ccaryclark    double tHi = span(end).fT;
1960dac1d17027dcaa5596885a9f333979418b35001ccaryclark    double tLo, refLo;
1961dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (thisStart >= 0) {
1962dac1d17027dcaa5596885a9f333979418b35001ccaryclark        tLo = span(thisStart).fT;
1963dac1d17027dcaa5596885a9f333979418b35001ccaryclark        refLo = min;
1964dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } else {
1965dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int start1 = findOtherT(loEnd, ref);
1966dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkASSERT(start1 >= 0);
1967dac1d17027dcaa5596885a9f333979418b35001ccaryclark        tLo = span(start1).fT;
1968dac1d17027dcaa5596885a9f333979418b35001ccaryclark        refLo = loEnd;
1969dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1970dac1d17027dcaa5596885a9f333979418b35001ccaryclark    double missingT = (max - refLo) / (hiEnd - refLo);
1971dac1d17027dcaa5596885a9f333979418b35001ccaryclark    missingT = tLo + missingT * (tHi - tLo);
1972dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return missingT;
1973dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
1974dac1d17027dcaa5596885a9f333979418b35001ccaryclark
1975dac1d17027dcaa5596885a9f333979418b35001ccaryclarkdouble SkOpSegment::calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, double max,
1976dac1d17027dcaa5596885a9f333979418b35001ccaryclark        double hiEnd, const SkOpSegment* other, int thisEnd) {
1977dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (min <= loEnd) {
1978dac1d17027dcaa5596885a9f333979418b35001ccaryclark        return -1;
1979dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1980dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int start = findOtherT(loEnd, ref);
1981dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (start < 0) {
1982dac1d17027dcaa5596885a9f333979418b35001ccaryclark        return -1;
1983dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1984dac1d17027dcaa5596885a9f333979418b35001ccaryclark    double tLo = span(start).fT;
1985dac1d17027dcaa5596885a9f333979418b35001ccaryclark    double tHi, refHi;
1986dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (thisEnd >= 0) {
1987dac1d17027dcaa5596885a9f333979418b35001ccaryclark        tHi = span(thisEnd).fT;
1988dac1d17027dcaa5596885a9f333979418b35001ccaryclark        refHi = max;
1989dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } else {
1990dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int end1 = findOtherT(hiEnd, ref);
1991dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (end1 < 0) {
1992dac1d17027dcaa5596885a9f333979418b35001ccaryclark            return -1;
1993dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
1994dac1d17027dcaa5596885a9f333979418b35001ccaryclark        tHi = span(end1).fT;
1995dac1d17027dcaa5596885a9f333979418b35001ccaryclark        refHi = hiEnd;
1996dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
1997dac1d17027dcaa5596885a9f333979418b35001ccaryclark    double missingT = (min - loEnd) / (refHi - loEnd);
1998dac1d17027dcaa5596885a9f333979418b35001ccaryclark    missingT = tLo + missingT * (tHi - tLo);
1999dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return missingT;
2000dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
2001dac1d17027dcaa5596885a9f333979418b35001ccaryclark
20024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// see if spans with two or more intersections have the same number on the other end
20034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::checkDuplicates() {
20044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
20054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
20064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index;
20074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int endIndex = 0;
20084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    bool endFound;
20094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
20104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        index = endIndex;
20114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        endIndex = nextExactSpan(index, 1);
20124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if ((endFound = endIndex < 0)) {
20134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            endIndex = count();
20144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
20154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int dupCount = endIndex - index;
20164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (dupCount < 2) {
20174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
20184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
20194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
20204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan* thisSpan = &fTs[index];
2021dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (thisSpan->fNear) {
2022dac1d17027dcaa5596885a9f333979418b35001ccaryclark                continue;
2023dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
20244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkOpSegment* other = thisSpan->fOther;
20254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int oIndex = thisSpan->fOtherIndex;
20264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int oStart = other->nextExactSpan(oIndex, -1) + 1;
20274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int oEnd = other->nextExactSpan(oIndex, 1);
20284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (oEnd < 0) {
20294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                oEnd = other->count();
20304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
20314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int oCount = oEnd - oStart;
20324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            // force the other to match its t and this pt if not on an end point
20334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (oCount != dupCount) {
20344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                MissingSpan& missing = missingSpans.push_back();
20354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fOther = NULL;
20364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
20374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fPt = thisSpan->fPt;
20384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                const SkOpSpan& oSpan = other->span(oIndex);
20394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (oCount > dupCount) {
20404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    missing.fSegment = this;
20414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    missing.fT = thisSpan->fT;
20424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    other->checkLinks(&oSpan, &missingSpans);
20434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                } else {
20444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    missing.fSegment = other;
20454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    missing.fT = oSpan.fT;
20464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    checkLinks(thisSpan, &missingSpans);
20474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
20484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (!missingSpans.back().fOther) {
20494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    missingSpans.pop_back();
20504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
20514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
20524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } while (++index < endIndex);
20534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (!endFound);
20544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int missingCount = missingSpans.count();
20554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (missingCount == 0) {
20564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return;
20574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
20584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence;
20594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (index = 0; index < missingCount; ++index)  {
20604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        MissingSpan& missing = missingSpans[index];
20614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkOpSegment* missingOther = missing.fOther;
20624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (missing.fSegment == missing.fOther) {
20634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
20644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
2065dac1d17027dcaa5596885a9f333979418b35001ccaryclark#if 0  // FIXME: this eliminates spurious data from skpwww_argus_presse_fr_41 but breaks
2066dac1d17027dcaa5596885a9f333979418b35001ccaryclark       // skpwww_fashionscandal_com_94 -- calcAngles complains, but I don't understand why
2067dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (missing.fSegment->containsT(missing.fT, missing.fOther, missing.fOtherT)) {
2068dac1d17027dcaa5596885a9f333979418b35001ccaryclark#if DEBUG_DUPLICATES
2069dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkDebugf("skip 1 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fSegment->fID,
2070dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    missing.fT, missing.fOther->fID, missing.fOtherT);
2071dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
2072dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
2073dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
2074dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (missing.fOther->containsT(missing.fOtherT, missing.fSegment, missing.fT)) {
2075dac1d17027dcaa5596885a9f333979418b35001ccaryclark#if DEBUG_DUPLICATES
2076dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkDebugf("skip 2 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fOther->fID,
2077dac1d17027dcaa5596885a9f333979418b35001ccaryclark                    missing.fOtherT, missing.fSegment->fID, missing.fT);
2078dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
2079dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
2080dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
2081dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
2082dac1d17027dcaa5596885a9f333979418b35001ccaryclark        // skip if adding would insert point into an existing coincindent span
2083dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (missing.fSegment->inCoincidentSpan(missing.fT, missingOther)
2084dac1d17027dcaa5596885a9f333979418b35001ccaryclark                && missingOther->inCoincidentSpan(missing.fOtherT, this)) {
2085dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
2086dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
2087dac1d17027dcaa5596885a9f333979418b35001ccaryclark        // skip if the created coincident spans are small
2088dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (missing.fSegment->coincidentSmall(missing.fPt, missing.fT, missingOther)
2089dac1d17027dcaa5596885a9f333979418b35001ccaryclark                && missingOther->coincidentSmall(missing.fPt, missing.fOtherT, missing.fSegment)) {
2090dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
2091dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
20924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOther,
20934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fOtherT, false, missing.fPt);
20944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (added && added->fSmall) {
20954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence);
20964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
20974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
20984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (index = 0; index < missingCount; ++index)  {
20994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        MissingSpan& missing = missingSpans[index];
21004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        missing.fSegment->fixOtherTIndex();
21014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        missing.fOther->fixOtherTIndex();
21024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
21034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (index = 0; index < missingCoincidence.count(); ++index) {
21044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        MissingSpan& missing = missingCoincidence[index];
21054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        missing.fSegment->fixOtherTIndex();
21064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
21074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
21084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
21094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
2110fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com// look to see if the curve end intersects an intermediary that intersects the other
2111fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.comvoid SkOpSegment::checkEnds() {
21124fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    debugValidate();
2113570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2114fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    int count = fTs.count();
2115fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    for (int index = 0; index < count; ++index) {
2116fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        const SkOpSpan& span = fTs[index];
2117570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        double otherT = span.fOtherT;
2118570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (otherT != 0 && otherT != 1) { // only check ends
2119fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            continue;
2120fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        }
2121570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        const SkOpSegment* other = span.fOther;
2122570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        // peek start/last describe the range of spans that match the other t of this span
2123fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        int peekStart = span.fOtherIndex;
2124570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT)
2125570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            ;
2126570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        int otherCount = other->fTs.count();
2127fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        int peekLast = span.fOtherIndex;
2128570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
2129570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            ;
2130570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do
2131fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            continue;
2132fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        }
2133570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        // t start/last describe the range of spans that match the t of this span
2134fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        double t = span.fT;
2135a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        double tBottom = -1;
2136a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        int tStart = -1;
2137a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        int tLast = count;
2138a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        bool lastSmall = false;
2139a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        double afterT = t;
2140a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        for (int inner = 0; inner < count; ++inner) {
2141a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            double innerT = fTs[inner].fT;
2142a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            if (innerT <= t && innerT > tBottom) {
2143a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                if (innerT < t || !lastSmall) {
2144a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    tStart = inner - 1;
2145a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                }
2146a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                tBottom = innerT;
2147a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            }
2148a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            if (innerT > afterT) {
2149a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                if (t == afterT && lastSmall) {
2150a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    afterT = innerT;
2151a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                } else {
2152a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    tLast = inner;
2153a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    break;
2154a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                }
2155a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            }
2156a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            lastSmall = innerT <= t ? fTs[inner].fSmall : false;
2157fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        }
2158fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com        for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
2159570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            if (peekIndex == span.fOtherIndex) {  // skip the other span pointed to by this span
2160fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com                continue;
2161fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            }
2162fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            const SkOpSpan& peekSpan = other->fTs[peekIndex];
2163fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            SkOpSegment* match = peekSpan.fOther;
21647eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            if (match->done()) {
21657eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                continue;  // if the edge has already been eaten (likely coincidence), ignore it
21667eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            }
2167fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            const double matchT = peekSpan.fOtherT;
2168570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            // see if any of the spans match the other spans
2169570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) {
2170fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com                const SkOpSpan& tSpan = fTs[tIndex];
2171570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                if (tSpan.fOther == match) {
2172570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    if (tSpan.fOtherT == matchT) {
21737eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                        goto nextPeekIndex;
2174570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    }
2175570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    double midT = (tSpan.fOtherT + matchT) / 2;
2176570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) {
21777eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                        goto nextPeekIndex;
2178570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    }
2179fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com                }
2180fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            }
2181570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            if (missingSpans.count() > 0) {
2182570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                const MissingSpan& lastMissing = missingSpans.back();
2183866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org                if (lastMissing.fT == t
2184570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                        && lastMissing.fOther == match
2185570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                        && lastMissing.fOtherT == matchT) {
2186570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    SkASSERT(lastMissing.fPt == peekSpan.fPt);
2187570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    continue;
2188570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                }
2189570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
2190570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#if DEBUG_CHECK_ENDS
2191570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n",
2192570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY);
2193570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#endif
2194fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            // this segment is missing a entry that the other contains
2195fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com            // remember so we can add the missing one and recompute the indices
21967eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            {
21977eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                MissingSpan& missing = missingSpans.push_back();
21987eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
21997eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                missing.fT = t;
220065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                SkASSERT(this != match);
22017eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                missing.fOther = match;
22027eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                missing.fOtherT = matchT;
22037eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                missing.fPt = peekSpan.fPt;
22047eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            }
22057eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            break;
22067eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.comnextPeekIndex:
22077eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com            ;
22087eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        }
2209fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    }
2210570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (missingSpans.count() == 0) {
22117eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        debugValidate();
22124fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        return;
22134fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    }
22144fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    debugValidate();
2215570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int missingCount = missingSpans.count();
2216fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    for (int index = 0; index < missingCount; ++index)  {
2217570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        MissingSpan& missing = missingSpans[index];
22184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (this != missing.fOther) {
22194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
22204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
2221fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    }
22224fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    fixOtherTIndex();
2223570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
2224570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    // avoid this
22254fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    for (int index = 0; index < missingCount; ++index)  {
2226866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        missingSpans[index].fOther->fixOtherTIndex();
2227fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com    }
22284fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com    debugValidate();
2229fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com}
2230fa2aeee27af27f2934ee52a9732148f66481fb03caryclark@google.com
22314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::checkLinks(const SkOpSpan* base,
22324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkTArray<MissingSpan, true>* missingSpans) const {
22334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* first = fTs.begin();
22344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* last = fTs.end() - 1;
22354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(base >= first && last >= base);
22364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSegment* other = base->fOther;
22374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* oFirst = other->fTs.begin();
22384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* oLast = other->fTs.end() - 1;
22394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex];
22404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* test = base;
22414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* missing = NULL;
22424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (test > first && (--test)->fPt == base->fPt) {
224365b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        if (this == test->fOther) {
224465b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            continue;
224565b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        }
22464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
22474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
22484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    test = base;
22494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (test < last && (++test)->fPt == base->fPt) {
225065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        SkASSERT(this != test->fOther);
22514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans);
22524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
22534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
22544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
22554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// see if spans with two or more intersections all agree on common t and point values
22564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::checkMultiples() {
22574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
22584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index;
22594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int end = 0;
22604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (fTs[++end].fT == 0)
22614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        ;
22624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (fTs[end].fT < 1) {
22634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int start = index = end;
22644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        end = nextExactSpan(index, 1);
22654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (end <= index) {
22664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return;  // buffer overflow example triggers this
22674431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
22684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (index + 1 == end) {
22694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
22704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
22714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // force the duplicates to agree on t and pt if not on the end
2272dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan& span = fTs[index];
2273dac1d17027dcaa5596885a9f333979418b35001ccaryclark        double thisT = span.fT;
2274dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkPoint& thisPt = span.fPt;
2275dac1d17027dcaa5596885a9f333979418b35001ccaryclark        span.fMultiple = true;
22764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        bool aligned = false;
22774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        while (++index < end) {
22784431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            aligned |= alignSpan(index, thisT, thisPt);
22794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
22804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (aligned) {
22814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            alignSpanState(start, end);
22824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
2283dac1d17027dcaa5596885a9f333979418b35001ccaryclark        fMultiples = true;
22844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
22854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
22864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
22874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
22884431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
22894431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingPtr,
22904431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkTArray<MissingSpan, true>* missingSpans) {
22914431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(oSpan->fPt == test->fPt);
22924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* oTest = oSpan;
22934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (oTest > oFirst && (--oTest)->fPt == test->fPt) {
22944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
22954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return;
22964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
22974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
22984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    oTest = oSpan;
22994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (oTest < oLast && (++oTest)->fPt == test->fPt) {
23004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) {
23014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return;
23024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
23034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
23044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (*missingPtr) {
23054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        missingSpans->push_back();
23064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
23074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    MissingSpan& lastMissing = missingSpans->back();
23084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (*missingPtr) {
23094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        lastMissing = missingSpans->end()[-2];
23104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
23114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    *missingPtr = test;
23124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    lastMissing.fOther = test->fOther;
23134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    lastMissing.fOtherT = test->fOtherT;
23144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
23154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
2316570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool SkOpSegment::checkSmall(int index) const {
2317570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (fTs[index].fSmall) {
231807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return true;
231907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
2320570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    double tBase = fTs[index].fT;
2321570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    while (index > 0 && precisely_negative(tBase - fTs[--index].fT))
2322570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        ;
2323570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return fTs[index].fSmall;
2324570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
2325570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
23264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// a pair of curves may turn into coincident lines -- small may be a hint that that happened
23274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// if a cubic contains a loop, the counts must be adjusted
23284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::checkSmall() {
23294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
23304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* beginSpan = fTs.begin();
23314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* thisSpan = beginSpan - 1;
23324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be small
23334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (++thisSpan < endSpan) {
23344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (!thisSpan->fSmall) {
23354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
23364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
23374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (!thisSpan->fWindValue) {
23384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
23394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
23404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& firstSpan = this->firstSpan(*thisSpan);
23414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& lastSpan = this->lastSpan(*thisSpan);
23425e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        const SkOpSpan* nextSpan = &firstSpan + 1;
23434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        ptrdiff_t smallCount = &lastSpan - &firstSpan + 1;
23444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(1 <= smallCount && smallCount < count());
23455e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        if (smallCount <= 1 && !nextSpan->fSmall) {
23464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(1 == smallCount);
23474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            checkSmallCoincidence(firstSpan, NULL);
23484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
23494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
23504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // at this point, check for missing computed intersections
23514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkPoint& testPt = firstSpan.fPt;
23524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        thisSpan = &firstSpan - 1;
23534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkOpSegment* other = NULL;
23544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        while (++thisSpan <= &lastSpan) {
23554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            other = thisSpan->fOther;
23564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (other != this) {
23574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
23584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
23594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
23604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(other != this);
23614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int oIndex = thisSpan->fOtherIndex;
23624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& oSpan = other->span(oIndex);
23634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& oFirstSpan = other->firstSpan(oSpan);
23644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& oLastSpan = other->lastSpan(oSpan);
23654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1;
23664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (fLoop) {
23674431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int smallCounts[2];
23684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(!other->fLoop);  // FIXME: we need more complicated logic for pair of loops
23694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (calcLoopSpanCount(*thisSpan, smallCounts)) {
23704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (smallCounts[0] && oCount != smallCounts[0]) {
23714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
23724431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
23734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (smallCounts[1] && oCount != smallCounts[1]) {
23744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
23754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
23764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                goto nextSmallCheck;
23774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
23784431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
23794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (other->fLoop) {
23804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            int otherCounts[2];
23814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) {
23824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (otherCounts[0] && otherCounts[0] != smallCount) {
23834431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
23844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
23854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (otherCounts[1] && otherCounts[1] != smallCount) {
23864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkASSERT(0);  // FIXME: need a working test case to properly code & debug
23874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
23884431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                goto nextSmallCheck;
23894431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
23904431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
23914431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (oCount != smallCount) {  // check if number of pts in this match other
23924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            MissingSpan& missing = missingSpans.push_back();
23934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            missing.fOther = NULL;
23944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
23954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            missing.fPt = testPt;
23964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan& oSpan = other->span(oIndex);
23974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (oCount > smallCount) {
23984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fSegment = this;
23994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fT = thisSpan->fT;
24004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                other->checkLinks(&oSpan, &missingSpans);
24014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            } else {
24024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fSegment = other;
24034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fT = oSpan.fT;
24044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                checkLinks(thisSpan, &missingSpans);
24054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
24064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (!missingSpans.back().fOther || missing.fSegment->done()) {
24074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missingSpans.pop_back();
24084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
24094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgnextSmallCheck:
24114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        thisSpan = &lastSpan;
24124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
24134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int missingCount = missingSpans.count();
24144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int index = 0; index < missingCount; ++index)  {
24154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        MissingSpan& missing = missingSpans[index];
24164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkOpSegment* missingOther = missing.fOther;
24174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // note that add t pair may edit span arrays, so prior pointers to spans are no longer valid
24184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOtherT, false,
24194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fPt)) {
24204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
24214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24228cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, missing.fSegment);
24234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& otherSpan = missingOther->span(otherTIndex);
24244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (otherSpan.fSmall) {
24254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan* nextSpan = &otherSpan;
24264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            do {
24274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                ++nextSpan;
24284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            } while (nextSpan->fSmall);
2429630240d18805faf81d8e75172496ad165c2226b2caryclark            SkAssertResult(missing.fSegment->addTCoincident(missing.fPt, nextSpan->fPt,
2430630240d18805faf81d8e75172496ad165c2226b2caryclark                    nextSpan->fT, missingOther));
24314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } else if (otherSpan.fT > 0) {
24324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan* priorSpan = &otherSpan;
24334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            do {
24344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                --priorSpan;
24354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            } while (priorSpan->fT == otherSpan.fT);
24364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (priorSpan->fSmall) {
24374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missingOther);
24384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
24394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
24414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to
24424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // avoid this
24434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int index = 0; index < missingCount; ++index)  {
24444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        MissingSpan& missing = missingSpans[index];
24454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        missing.fSegment->fixOtherTIndex();
24464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        missing.fOther->fixOtherTIndex();
24474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
24484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
24494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
24504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
24514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::checkSmallCoincidence(const SkOpSpan& span,
24524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkTArray<MissingSpan, true>* checkMultiple) {
24534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(span.fSmall);
24548cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    if (0 && !span.fWindValue) {
24558cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        return;
24568cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    }
24574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(&span < fTs.end() - 1);
24584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* next = &span + 1;
24594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(!next->fSmall || checkMultiple);
24604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (checkMultiple) {
24614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        while (next->fSmall) {
24624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            ++next;
24634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(next < fTs.end());
24644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
24664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSegment* other = span.fOther;
24674431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (other != next->fOther) {
24684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (!checkMultiple) {
24694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return;
24704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan* test = next + 1;
24724431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (test == fTs.end()) {
24734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return;
24744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) {
24764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return;
24774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24784431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        next = test;
24794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
24804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(span.fT < next->fT);
24814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int oStartIndex = other->findExactT(span.fOtherT, this);
24824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int oEndIndex = other->findExactT(next->fOtherT, this);
24834431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // FIXME: be overly conservative by limiting this to the caller that allows multiple smalls
24844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath::kLine_Verb) {
24854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkPoint mid = ptAtT((span.fT + next->fT) / 2);
24864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& oSpanStart = other->fTs[oStartIndex];
24874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& oSpanEnd = other->fTs[oEndIndex];
24884431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2);
24894431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
24904431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return;
24914431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
24924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
24934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // FIXME: again, be overly conservative to avoid breaking existing tests
24944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex]
24954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            : other->fTs[oEndIndex];
24964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (checkMultiple && !oSpan.fSmall) {
24974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return;
24984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
249965b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark//    SkASSERT(oSpan.fSmall);
25004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (oStartIndex < oEndIndex) {
2501630240d18805faf81d8e75172496ad165c2226b2caryclark        SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, other));
25024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
25034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        addTCancel(span.fPt, next->fPt, other);
25044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
25054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (!checkMultiple) {
25064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return;
25074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
25084431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // check to see if either segment is coincident with a third segment -- if it is, and if
25094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // the opposite segment is not already coincident with the third, make it so
25104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // OPTIMIZE: to make this check easier, add coincident and cancel could set a coincident bit
25114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (span.fWindValue != 1 || span.fOppValue != 0) {
25124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org//        start here;
25134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // iterate through the spans, looking for the third coincident case
25144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // if we find one, we need to return state to the caller so that the indices can be fixed
25154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        // this also suggests that all of this function is fragile since it relies on a valid index
25164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
25174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // probably should make this a common function rather than copy/paste code
25184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) {
25194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan* oTest = &oSpan;
25204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        while (--oTest >= other->fTs.begin()) {
25214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
25224431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
25234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
25244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkOpSegment* testOther = oTest->fOther;
25254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(testOther != this);
25264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            // look in both directions to see if there is a coincident span
25274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            const SkOpSpan* tTest = testOther->fTs.begin();
25284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            for (int testIndex = 0; testIndex < testOther->count(); ++testIndex) {
25294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (tTest->fPt != span.fPt) {
25304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    ++tTest;
25314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    continue;
25324431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
25334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (testOther->verb() != SkPath::kLine_Verb
25344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                        || other->verb() != SkPath::kLine_Verb) {
25354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkPoint mid = ptAtT((span.fT + next->fT) / 2);
25364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2);
25374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    if (!SkDPoint::ApproximatelyEqual(mid, oMid)) {
25384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                        continue;
25394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    }
2540a1ed7aec95eb8c77d1a39834fea476780007cadeskia.committer@gmail.com                }
25414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_CONCIDENT
25424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, testOther->fID,
25434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                        oTest->fOtherT, tTest->fT);
25444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
25454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (tTest->fT < oTest->fOtherT) {
2546630240d18805faf81d8e75172496ad165c2226b2caryclark                    SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, testOther));
25474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                } else {
25484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    addTCancel(span.fPt, next->fPt, testOther);
25494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
25504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                MissingSpan missing;
25514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                missing.fSegment = testOther;
25524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                checkMultiple->push_back(missing);
25534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
25544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
25554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
25564431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        oTest = &oSpan;
25574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        while (++oTest < other->fTs.end()) {
25584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) {
25594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
25604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
25614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
25624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
25634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
25644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
25654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
2566570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com// if pair of spans on either side of tiny have the same end point and mid point, mark
2567570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com// them as parallel
2568570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::checkTiny() {
2569570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans;
2570570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkOpSpan* thisSpan = fTs.begin() - 1;
2571570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    const SkOpSpan* endSpan = fTs.end() - 1;  // last can't be tiny
2572570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    while (++thisSpan < endSpan) {
2573570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (!thisSpan->fTiny) {
2574570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            continue;
2575570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
2576570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSpan* nextSpan = thisSpan + 1;
2577570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        double thisT = thisSpan->fT;
2578570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        double nextT = nextSpan->fT;
2579570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (thisT == nextT) {
2580570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            continue;
2581570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
2582570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(thisT < nextT);
2583570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkASSERT(thisSpan->fPt == nextSpan->fPt);
2584570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSegment* thisOther = thisSpan->fOther;
2585570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSegment* nextOther = nextSpan->fOther;
2586570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        int oIndex = thisSpan->fOtherIndex;
2587570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        for (int oStep = -1; oStep <= 1; oStep += 2) {
2588570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            int oEnd = thisOther->nextExactSpan(oIndex, oStep);
2589570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            if (oEnd < 0) {
2590570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                continue;
2591570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
2592570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            const SkOpSpan& oSpan = thisOther->span(oEnd);
2593570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            int nIndex = nextSpan->fOtherIndex;
2594570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            for (int nStep = -1; nStep <= 1; nStep += 2) {
2595570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                int nEnd = nextOther->nextExactSpan(nIndex, nStep);
2596570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                if (nEnd < 0) {
2597570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    continue;
2598570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                }
2599570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                const SkOpSpan& nSpan = nextOther->span(nEnd);
2600570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                if (oSpan.fPt != nSpan.fPt) {
2601570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    continue;
2602570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                }
2603570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2;
2604570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                const SkPoint& oPt = thisOther->ptAtT(oMidT);
2605570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2;
2606570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                const SkPoint& nPt = nextOther->ptAtT(nMidT);
2607570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                if (!AlmostEqualUlps(oPt, nPt)) {
2608570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    continue;
2609570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                }
2610570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#if DEBUG_CHECK_TINY
2611570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID,
2612570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    thisOther->fID, nextOther->fID);
2613570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#endif
2614570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                // this segment is missing a entry that the other contains
2615570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                // remember so we can add the missing one and recompute the indices
2616570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                MissingSpan& missing = missingSpans.push_back();
2617570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                SkDEBUGCODE(sk_bzero(&missing, sizeof(missing)));
2618570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                missing.fSegment = thisOther;
2619570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                missing.fT = thisSpan->fOtherT;
262065b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark                SkASSERT(this != nextOther);
2621570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                missing.fOther = nextOther;
2622570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                missing.fOtherT = nextSpan->fOtherT;
2623570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                missing.fPt = thisSpan->fPt;
2624570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
2625570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
2626570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
2627570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int missingCount = missingSpans.count();
2628570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (!missingCount) {
2629570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        return;
2630570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
2631570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    for (int index = 0; index < missingCount; ++index)  {
2632570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        MissingSpan& missing = missingSpans[index];
26334431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (missing.fSegment != missing.fOther) {
26344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false,
26354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    missing.fPt);
26364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
2637570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
26384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // OPTIMIZE: consolidate to avoid multiple calls to fix index
2639570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    for (int index = 0; index < missingCount; ++index)  {
2640570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        MissingSpan& missing = missingSpans[index];
2641570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        missing.fSegment->fixOtherTIndex();
2642570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        missing.fOther->fixOtherTIndex();
264307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
264407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
264507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
2646dac1d17027dcaa5596885a9f333979418b35001ccaryclarkbool SkOpSegment::coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other) const {
2647dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int count = this->count();
2648dac1d17027dcaa5596885a9f333979418b35001ccaryclark    for (int index = 0; index < count; ++index) {
2649dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkOpSpan& span = this->span(index);
2650dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (span.fOther != other) {
2651dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
2652dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
2653dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (span.fPt == pt) {
2654dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
2655dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
2656dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (!AlmostEqualUlps(span.fPt, pt)) {
2657dac1d17027dcaa5596885a9f333979418b35001ccaryclark            continue;
2658dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
2659dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (fVerb != SkPath::kCubic_Verb) {
2660dac1d17027dcaa5596885a9f333979418b35001ccaryclark            return true;
2661dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
2662dac1d17027dcaa5596885a9f333979418b35001ccaryclark        double tInterval = t - span.fT;
2663dac1d17027dcaa5596885a9f333979418b35001ccaryclark        double tMid = t - tInterval / 2;
2664dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkDPoint midPt = dcubic_xy_at_t(fPts, tMid);
2665dac1d17027dcaa5596885a9f333979418b35001ccaryclark        return midPt.approximatelyEqual(xyAtT(t));
2666dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
2667dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return false;
2668dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
2669dac1d17027dcaa5596885a9f333979418b35001ccaryclark
2670a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.combool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart,
2671a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) const {
2672a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    SkASSERT(span->fT == 0 || span->fT == 1);
2673a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    SkASSERT(span->fOtherT == 0 || span->fOtherT == 1);
2674a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    const SkOpSpan* otherSpan = &other->span(oEnd);
2675a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    double refT = otherSpan->fT;
2676a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    const SkPoint& refPt = otherSpan->fPt;
2677a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0);
2678a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    do {
2679a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        const SkOpSegment* match = span->fOther;
2680a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        if (match == otherSpan->fOther) {
2681a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            // find start of respective spans and see if both have winding
2682a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            int startIndex, endIndex;
2683a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            if (span->fOtherT == 1) {
2684a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                endIndex = span->fOtherIndex;
2685a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                startIndex = match->nextExactSpan(endIndex, -1);
2686a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            } else {
2687a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                startIndex = span->fOtherIndex;
2688a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                endIndex = match->nextExactSpan(startIndex, 1);
2689a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            }
2690a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            const SkOpSpan& startSpan = match->span(startIndex);
2691a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            if (startSpan.fWindValue != 0) {
2692a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                // draw ray from endSpan.fPt perpendicular to end tangent and measure distance
2693a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                // to other segment.
2694a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                const SkOpSpan& endSpan = match->span(endIndex);
2695a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                SkDLine ray;
2696a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                SkVector dxdy;
2697a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                if (span->fOtherT == 1) {
2698a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    ray.fPts[0].set(startSpan.fPt);
2699a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    dxdy = match->dxdy(startIndex);
2700a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                } else {
2701a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    ray.fPts[0].set(endSpan.fPt);
2702a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    dxdy = match->dxdy(endIndex);
2703a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                }
2704a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY;
2705a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX;
2706a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                SkIntersections i;
2707a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])(other->pts(), ray);
2708a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                for (int index = 0; index < roots; ++index) {
2709a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    if (ray.fPts[0].approximatelyEqual(i.pt(index))) {
2710a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                        double matchMidT = (match->span(startIndex).fT
2711a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                                + match->span(endIndex).fT) / 2;
2712a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                        SkPoint matchMidPt = match->ptAtT(matchMidT);
2713a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                        double otherMidT = (i[0][index] + other->span(oStart).fT) / 2;
2714a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                        SkPoint otherMidPt = other->ptAtT(otherMidT);
2715a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                        if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt)) {
2716a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                            *startPt = startSpan.fPt;
2717a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                            *endPt = endSpan.fPt;
2718a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                            *endT = endSpan.fT;
2719a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                            return true;
2720a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                        }
2721a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                    }
2722a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com                }
2723a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            }
2724a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            return false;
2725a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        }
2726a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        if (otherSpan == lastSpan) {
2727a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            break;
2728a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        }
2729a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        otherSpan += step;
2730a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    } while (otherSpan->fT == refT || otherSpan->fPt == refPt);
2731a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return false;
2732a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com}
2733a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
27344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgint SkOpSegment::findEndSpan(int endIndex) const {
27354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* span = &fTs[--endIndex];
27364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkPoint& lastPt = span->fPt;
27374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    double endT = span->fT;
27384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
27394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        span = &fTs[--endIndex];
27404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == endT || span->fTiny));
27414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return endIndex + 1;
27424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
27434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
274407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com/*
274507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com The M and S variable name parts stand for the operators.
274607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com   Mi stands for Minuend (see wiki subtraction, analogous to difference)
274707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com   Su stands for Subtrahend
274807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com The Opp variable name part designates that the value is for the Opposite operator.
274907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com Opposite values result from combining coincident spans.
275007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com */
275107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
275207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                                     bool* unsortable, SkPathOp op, const int xorMiMask,
275307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                                     const int xorSuMask) {
275407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const int startIndex = *nextStart;
275507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const int endIndex = *nextEnd;
275607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex != endIndex);
275707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDEBUGCODE(const int count = fTs.count());
275807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2759dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int step = SkSign32(endIndex - startIndex);
2760dac1d17027dcaa5596885a9f333979418b35001ccaryclark    *nextStart = startIndex;
2761dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSegment* other = isSimple(nextStart, &step);
2762dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (other)
2763dac1d17027dcaa5596885a9f333979418b35001ccaryclark    {
276407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // mark the smaller of startIndex, endIndex done, and all adjacent
276507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // spans with the same T value (but not 'other' spans)
276607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
276707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDebugf("%s simple\n", __FUNCTION__);
276807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
276907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        int min = SkMin32(startIndex, endIndex);
277007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fTs[min].fDone) {
277107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return NULL;
277207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
277307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markDoneBinary(min);
277407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        double startT = other->fTs[*nextStart].fT;
277507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *nextEnd = *nextStart;
277607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        do {
277707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            *nextEnd += step;
2778570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
277907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2780cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
278107e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com            *unsortable = true;
2782cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            return NULL;
2783cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        }
278407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return other;
278507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
2786dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const int end = nextExactSpan(startIndex, step);
2787dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(end >= 0);
278807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex - endIndex != 0);
278907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
27904431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // more than one viable candidate -- measure angles to find best
27914431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
27924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp);
2793570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool sortable = calcWinding != SK_NaN32;
27944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (!sortable) {
27957eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        *unsortable = true;
27968cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        markDoneBinary(SkMin32(startIndex, endIndex));
27977eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return NULL;
27987eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
27994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* angle = spanToAngle(end, startIndex);
28004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (angle->unorderable()) {
280107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *unsortable = true;
28028cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        markDoneBinary(SkMin32(startIndex, endIndex));
280307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
280407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
28054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_SORT
28064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDebugf("%s\n", __FUNCTION__);
28074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    angle->debugLoop();
280807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
280907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int sumMiWinding = updateWinding(endIndex, startIndex);
28108cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    if (sumMiWinding == SK_MinS32) {
28118cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        *unsortable = true;
28128cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        markDoneBinary(SkMin32(startIndex, endIndex));
28138cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        return NULL;
28148cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    }
281507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int sumSuWinding = updateOppWinding(endIndex, startIndex);
281607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (operand()) {
281707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkTSwap<int>(sumMiWinding, sumSuWinding);
281807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
28194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* nextAngle = angle->next();
282007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const SkOpAngle* foundAngle = NULL;
282107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool foundDone = false;
282207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // iterate through the angle, and compute everyone's winding
282307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSegment* nextSegment;
282407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int activeCount = 0;
282507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
282607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        nextSegment = nextAngle->segment();
282707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(),
28284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                nextAngle->end(), op, &sumMiWinding, &sumSuWinding);
282907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (activeAngle) {
283007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            ++activeCount;
283107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (!foundAngle || (foundDone && activeCount & 1)) {
2832cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com                if (nextSegment->isTiny(nextAngle)) {
283307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    *unsortable = true;
28348cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                    markDoneBinary(SkMin32(startIndex, endIndex));
283507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    return NULL;
283607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                }
283707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                foundAngle = nextAngle;
2838570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                foundDone = nextSegment->done(nextAngle);
283907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
284007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
284107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (nextSegment->done()) {
284207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            continue;
284307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
2844570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (nextSegment->isTiny(nextAngle)) {
284507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            continue;
284607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
2847570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (!activeAngle) {
2848dac1d17027dcaa5596885a9f333979418b35001ccaryclark            (void) nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end());
2849570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
2850570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSpan* last = nextAngle->lastMarked();
285107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (last) {
28524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
285307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            *chase->append() = last;
285407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
2855570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
2856570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2857570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    last->fSmall);
285807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
285907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
28604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while ((nextAngle = nextAngle->next()) != angle);
28614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_ANGLE
28624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (foundAngle) {
28634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        foundAngle->debugSameAs(foundAngle);
28644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
28654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
28664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
286707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    markDoneBinary(SkMin32(startIndex, endIndex));
286807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!foundAngle) {
286907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
287007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
287107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *nextStart = foundAngle->start();
287207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *nextEnd = foundAngle->end();
287307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    nextSegment = foundAngle->segment();
287407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
287507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
287607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
287707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com #endif
287807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return nextSegment;
287907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
288007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
288107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart,
288207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                                          int* nextEnd, bool* unsortable) {
288307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const int startIndex = *nextStart;
288407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const int endIndex = *nextEnd;
288507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex != endIndex);
288607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDEBUGCODE(const int count = fTs.count());
288707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
2888dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int step = SkSign32(endIndex - startIndex);
2889dac1d17027dcaa5596885a9f333979418b35001ccaryclark    *nextStart = startIndex;
2890dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSegment* other = isSimple(nextStart, &step);
2891dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (other)
2892dac1d17027dcaa5596885a9f333979418b35001ccaryclark    {
289307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // mark the smaller of startIndex, endIndex done, and all adjacent
289407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // spans with the same T value (but not 'other' spans)
289507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
289607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDebugf("%s simple\n", __FUNCTION__);
289707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
289807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        int min = SkMin32(startIndex, endIndex);
289907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fTs[min].fDone) {
290007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return NULL;
290107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
290207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markDoneUnary(min);
290307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        double startT = other->fTs[*nextStart].fT;
290407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *nextEnd = *nextStart;
290507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        do {
290607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            *nextEnd += step;
2907570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
290807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
2909570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (other->isTiny(SkMin32(*nextStart, *nextEnd))) {
2910570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            *unsortable = true;
2911570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            return NULL;
2912570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
291307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return other;
291407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
2915dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const int end = nextExactSpan(startIndex, step);
2916dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(end >= 0);
291707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex - endIndex != 0);
291807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
29194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // more than one viable candidate -- measure angles to find best
29204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
29214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding);
2922570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool sortable = calcWinding != SK_NaN32;
292307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!sortable) {
292407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *unsortable = true;
29258cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        markDoneUnary(SkMin32(startIndex, endIndex));
292607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
292707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
29284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* angle = spanToAngle(end, startIndex);
29294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_SORT
29304431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDebugf("%s\n", __FUNCTION__);
29314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    angle->debugLoop();
293207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
293307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int sumWinding = updateWinding(endIndex, startIndex);
29344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* nextAngle = angle->next();
293507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const SkOpAngle* foundAngle = NULL;
293607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool foundDone = false;
293707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSegment* nextSegment;
293807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int activeCount = 0;
293907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
294007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        nextSegment = nextAngle->segment();
294107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
29424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                &sumWinding);
294307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (activeAngle) {
294407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            ++activeCount;
294507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (!foundAngle || (foundDone && activeCount & 1)) {
2946cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com                if (nextSegment->isTiny(nextAngle)) {
294707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    *unsortable = true;
29488cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                    markDoneUnary(SkMin32(startIndex, endIndex));
294907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    return NULL;
295007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                }
295107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                foundAngle = nextAngle;
295207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                foundDone = nextSegment->done(nextAngle);
295307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
295407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
295507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (nextSegment->done()) {
295607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            continue;
295707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
2958570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (nextSegment->isTiny(nextAngle)) {
295907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            continue;
296007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
2961570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        if (!activeAngle) {
2962570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end());
2963570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
2964570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        SkOpSpan* last = nextAngle->lastMarked();
296507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (last) {
29664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last));
296707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            *chase->append() = last;
296807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
2969570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__,
2970570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum,
2971570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                    last->fSmall);
297207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
297307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
29744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while ((nextAngle = nextAngle->next()) != angle);
297507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    markDoneUnary(SkMin32(startIndex, endIndex));
297607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!foundAngle) {
297707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
297807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
297907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *nextStart = foundAngle->start();
298007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *nextEnd = foundAngle->end();
298107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    nextSegment = foundAngle->segment();
298207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
298307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
298407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
298507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com #endif
298607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return nextSegment;
298707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
298807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
298907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) {
299007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const int startIndex = *nextStart;
299107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const int endIndex = *nextEnd;
299207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex != endIndex);
299307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDEBUGCODE(int count = fTs.count());
2994570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0);
299507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int step = SkSign32(endIndex - startIndex);
29964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// Detect cases where all the ends canceled out (e.g.,
2997dac1d17027dcaa5596885a9f333979418b35001ccaryclark// there is no angle) and therefore there's only one valid connection
2998dac1d17027dcaa5596885a9f333979418b35001ccaryclark    *nextStart = startIndex;
2999dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSegment* other = isSimple(nextStart, &step);
3000dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (other)
3001dac1d17027dcaa5596885a9f333979418b35001ccaryclark    {
300207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
300307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDebugf("%s simple\n", __FUNCTION__);
300407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
300507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        int min = SkMin32(startIndex, endIndex);
300607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fTs[min].fDone) {
300707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return NULL;
300807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
300907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markDone(min, 1);
301007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        double startT = other->fTs[*nextStart].fT;
301107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        // FIXME: I don't know why the logic here is difference from the winding case
301207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDEBUGCODE(bool firstLoop = true;)
301307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if ((approximately_less_than_zero(startT) && step < 0)
301407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                || (approximately_greater_than_one(startT) && step > 0)) {
301507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            step = -step;
301607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDEBUGCODE(firstLoop = false;)
301707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
301807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        do {
301907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            *nextEnd = *nextStart;
302007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            do {
302107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                *nextEnd += step;
3022570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            } while (precisely_zero(startT - other->fTs[*nextEnd].fT));
302307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) {
302407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                break;
302507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
302607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkASSERT(firstLoop);
302707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDEBUGCODE(firstLoop = false;)
302807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            step = -step;
302907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        } while (true);
303007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count());
303107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return other;
303207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
303307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(startIndex - endIndex != 0);
30344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
30354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // parallel block above with presorted version
3036dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int end = nextExactSpan(startIndex, step);
3037dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(end >= 0);
30384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* angle = spanToAngle(end, startIndex);
30394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(angle);
30404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_SORT
30414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDebugf("%s\n", __FUNCTION__);
30424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    angle->debugLoop();
3043570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#endif
30444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* nextAngle = angle->next();
304507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const SkOpAngle* foundAngle = NULL;
304607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool foundDone = false;
304707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSegment* nextSegment;
304807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int activeCount = 0;
304907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
305007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        nextSegment = nextAngle->segment();
305107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++activeCount;
305207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (!foundAngle || (foundDone && activeCount & 1)) {
3053cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            if (nextSegment->isTiny(nextAngle)) {
305407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                *unsortable = true;
305507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                return NULL;
305607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
305707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            foundAngle = nextAngle;
30584431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (!(foundDone = nextSegment->done(nextAngle))) {
30594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
30604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
306107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
30624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        nextAngle = nextAngle->next();
30634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (nextAngle != angle);
306407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    markDone(SkMin32(startIndex, endIndex), 1);
306507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!foundAngle) {
306607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
306707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
306807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *nextStart = foundAngle->start();
306907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *nextEnd = foundAngle->end();
307007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    nextSegment = foundAngle->segment();
307107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING
307207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n",
307307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd);
307407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com #endif
307507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return nextSegment;
307607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
307707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
30784431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgint SkOpSegment::findStartSpan(int startIndex) const {
30794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = startIndex;
30804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpSpan* span = &fTs[index];
30814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkPoint& firstPt = span->fPt;
30824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    double firstT = span->fT;
3083dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkOpSpan* prior;
30844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
3085dac1d17027dcaa5596885a9f333979418b35001ccaryclark        prior = span;
3086dac1d17027dcaa5596885a9f333979418b35001ccaryclark        span = &fTs[++index];
3087dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } while (SkDPoint::ApproximatelyEqual(span->fPt, firstPt)
3088dac1d17027dcaa5596885a9f333979418b35001ccaryclark            && (span->fT == firstT || prior->fTiny));
30894431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return index;
309007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
309107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
30924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgint SkOpSegment::findExactT(double t, const SkOpSegment* match) const {
3093a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    int count = this->count();
3094a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    for (int index = 0; index < count; ++index) {
3095a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        const SkOpSpan& span = fTs[index];
3096a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        if (span.fT == t && span.fOther == match) {
3097a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            return index;
3098a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        }
3099a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    }
3100a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    SkASSERT(0);
3101a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return -1;
3102a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com}
3103a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
3104dac1d17027dcaa5596885a9f333979418b35001ccaryclarkint SkOpSegment::findOtherT(double t, const SkOpSegment* match) const {
3105dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int count = this->count();
3106dac1d17027dcaa5596885a9f333979418b35001ccaryclark    for (int index = 0; index < count; ++index) {
3107dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkOpSpan& span = fTs[index];
3108dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (span.fOtherT == t && span.fOther == match) {
3109dac1d17027dcaa5596885a9f333979418b35001ccaryclark            return index;
3110dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
3111dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
3112dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return -1;
3113dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
3114dac1d17027dcaa5596885a9f333979418b35001ccaryclark
31158cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.orgint SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const {
31164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int count = this->count();
31175e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    // prefer exact matches over approximate matches
31185e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    for (int index = 0; index < count; ++index) {
31195e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        const SkOpSpan& span = fTs[index];
31205e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        if (span.fT == t && span.fOther == match) {
31215e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark            return index;
31225e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        }
31235e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    }
31244431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int index = 0; index < count; ++index) {
31254431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& span = fTs[index];
31264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (approximately_equal_orderable(span.fT, t) && span.fOther == match) {
31274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return index;
31284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
31294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
31308cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    // Usually, the pair of ts are an exact match. It's possible that the t values have
31318cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    // been adjusted to make multiple intersections align. In this rare case, look for a
31328cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    // matching point / match pair instead.
31338cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    for (int index = 0; index < count; ++index) {
31348cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        const SkOpSpan& span = fTs[index];
31358cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        if (span.fPt == pt && span.fOther == match) {
31368cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            return index;
31378cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        }
31388cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    }
31394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(0);
31404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return -1;
31414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
314207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
31438cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.orgSkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable,
31448cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        bool firstPass) {
314507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // iterate through T intersections and return topmost
314607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // topmost tangent from y-min to first pt is closer to horizontal
314707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(!done());
314807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int firstT = -1;
31498cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    /* SkPoint topPt = */ activeLeftTop(&firstT);
315007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (firstT < 0) {
31518cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        *unsortable = !firstPass;
315207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        firstT = 0;
315307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        while (fTs[firstT].fDone) {
315407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkASSERT(firstT < fTs.count());
315507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            ++firstT;
315607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
315707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *tIndexPtr = firstT;
315807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *endIndexPtr = nextExactSpan(firstT, 1);
315907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return this;
316007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
316107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // sort the edges to find the leftmost
316207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int step = 1;
31634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int end;
31644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) {
316507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        step = -1;
316607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        end = nextSpan(firstT, step);
316707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkASSERT(end != -1);
316807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
316907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // if the topmost T is not on end, or is three-way or more, find left
317007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // look for left-ness from tLeft to firstT (matching y of other)
317107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(firstT - end != 0);
31724431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpAngle* markAngle = spanToAngle(firstT, end);
31734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (!markAngle) {
3174dac1d17027dcaa5596885a9f333979418b35001ccaryclark        markAngle = addSingletonAngles(step);
31754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
31764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    markAngle->markStops();
3177e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark    const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
3178e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            : markAngle->findFirst();
31794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (!baseAngle) {
31804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return NULL;  // nothing to do
3181570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
318207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar top = SK_ScalarMax;
31834431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpAngle* firstAngle = NULL;
31844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    const SkOpAngle* angle = baseAngle;
31854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
31864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (!angle->unorderable()) {
31874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkOpSegment* next = angle->segment();
31884431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkPathOpsBounds bounds;
31894431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            next->subDivideBounds(angle->end(), angle->start(), &bounds);
31904431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (approximately_greater(top, bounds.fTop)) {
31914431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                top = bounds.fTop;
31924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                firstAngle = angle;
31934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
319407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
31954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        angle = angle->next();
31964431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (angle != baseAngle);
31974431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(firstAngle);
31984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_SORT
31994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDebugf("%s\n", __FUNCTION__);
32004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    firstAngle->debugLoop();
320107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
320207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // skip edges that have already been processed
32034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    angle = firstAngle;
32048cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkOpSegment* leftSegment = NULL;
32058cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    bool looped = false;
320607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
32078cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        *unsortable = angle->unorderable();
32088cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        if (firstPass || !*unsortable) {
32098cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            leftSegment = angle->segment();
32108cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            *tIndexPtr = angle->end();
32118cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            *endIndexPtr = angle->start();
32128cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) {
32138cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                break;
32148cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            }
32158cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        }
32164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        angle = angle->next();
32178cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        looped = true;
32188cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    } while (angle != firstAngle);
32198cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    if (angle == firstAngle && looped) {
32208cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        return NULL;
32218cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    }
322207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (leftSegment->verb() >= SkPath::kQuad_Verb) {
322307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const int tIndex = *tIndexPtr;
322407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const int endIndex = *endIndexPtr;
3225e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        bool swap;
3226e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        if (!leftSegment->clockwise(tIndex, endIndex, &swap)) {
322707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    #if DEBUG_SWAP_TOP
32288cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org            SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n",
32298cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                    __FUNCTION__,
32308cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                    swap, leftSegment->debugInflections(tIndex, endIndex),
323107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    leftSegment->serpentine(tIndex, endIndex),
323207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    leftSegment->controlsContainedByEnds(tIndex, endIndex),
323307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                    leftSegment->monotonicInY(tIndex, endIndex));
323407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    #endif
323507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (swap) {
323607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
323707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // sorted but merely the first not already processed (i.e., not done)
323807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                SkTSwap(*tIndexPtr, *endIndexPtr);
323907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
324007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
324107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
324207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny);
324307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return leftSegment;
324407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
324507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
32464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgint SkOpSegment::firstActive(int tIndex) const {
32474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (fTs[tIndex].fTiny) {
32484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(!isCanceled(tIndex));
32494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        ++tIndex;
32504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
32514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return tIndex;
32524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
32534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
325407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// FIXME: not crazy about this
325507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// when the intersections are performed, the other index is into an
325607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// incomplete array. As the array grows, the indices become incorrect
325707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// while the following fixes the indices up again, it isn't smart about
325807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// skipping segments whose indices are already correct
325907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// assuming we leave the code that wrote the index in the first place
3260570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com// FIXME: if called after remove, this needs to correct tiny
326107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::fixOtherTIndex() {
326207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int iCount = fTs.count();
326307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    for (int i = 0; i < iCount; ++i) {
326407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkOpSpan& iSpan = fTs[i];
326507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        double oT = iSpan.fOtherT;
326607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkOpSegment* other = iSpan.fOther;
326707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        int oCount = other->fTs.count();
32684fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        SkDEBUGCODE(iSpan.fOtherIndex = -1);
326907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        for (int o = 0; o < oCount; ++o) {
327007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkOpSpan& oSpan = other->fTs[o];
327107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) {
327207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                iSpan.fOtherIndex = o;
32734fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com                oSpan.fOtherIndex = i;
327407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                break;
327507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
327607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
32774fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        SkASSERT(iSpan.fOtherIndex >= 0);
327807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
327907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
328007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
3281dac1d17027dcaa5596885a9f333979418b35001ccaryclarkbool SkOpSegment::inCoincidentSpan(double t, const SkOpSegment* other) const {
3282dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int foundEnds = 0;
3283dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int count = this->count();
3284dac1d17027dcaa5596885a9f333979418b35001ccaryclark    for (int index = 0; index < count; ++index) {
3285dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkOpSpan& span = this->span(index);
3286dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (span.fCoincident) {
3287dac1d17027dcaa5596885a9f333979418b35001ccaryclark            foundEnds |= (span.fOther == other) << ((t > span.fT) + (t >= span.fT));
3288dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
3289dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
3290dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(foundEnds != 7);
3291dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return foundEnds == 0x3 || foundEnds == 0x5 || foundEnds == 0x6;  // two bits set
3292dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
3293dac1d17027dcaa5596885a9f333979418b35001ccaryclark
329407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) {
329507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fDoneSpans = 0;
329607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fOperand = operand;
329707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fXor = evenOdd;
329807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fPts = pts;
329907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fVerb = verb;
3300dac1d17027dcaa5596885a9f333979418b35001ccaryclark    fLoop = fMultiples = fSmall = fTiny = false;
330107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
330207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
33034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType) {
330407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int local = spanSign(start, end);
33054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (angleIncludeType == SkOpAngle::kBinarySingle) {
33064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int oppLocal = oppSign(start, end);
33074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        (void) markAndChaseWinding(start, end, local, oppLocal);
330807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // OPTIMIZATION: the reverse mark and chase could skip the first marking
33094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        (void) markAndChaseWinding(end, start, local, oppLocal);
33104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
33114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        (void) markAndChaseWinding(start, end, local);
33124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // OPTIMIZATION: the reverse mark and chase could skip the first marking
33134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        (void) markAndChaseWinding(end, start, local);
33144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
331507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
331607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
331707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com/*
331807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comwhen we start with a vertical intersect, we try to use the dx to determine if the edge is to
331907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comthe left or the right of vertical. This determines if we need to add the span's
332007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comsign or not. However, this isn't enough.
332107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comIf the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
332207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comIf there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
332307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comfrom has the same x direction as this span, the winding should change. If the dx is opposite, then
332407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comthe same winding is shared by both.
332507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com*/
332607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx,
332707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                              int oppWind, SkScalar hitOppDx) {
332807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(hitDx || !winding);
3329277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com    SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
333007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(dx);
333107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int windVal = windValue(SkMin32(start, end));
333207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING_AT_T
3333dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, debugID(), winding,
333407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
333507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
33364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int sideWind = winding + (dx < 0 ? windVal : -windVal);
33374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (abs(winding) < abs(sideWind)) {
33384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        winding = sideWind;
333907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
334007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDEBUGCODE(int oppLocal = oppSign(start, end));
334107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(hitOppDx || !oppWind || !oppLocal);
334207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oppWindVal = oppValue(SkMin32(start, end));
334307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!oppWind) {
334407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        oppWind = dx < 0 ? oppWindVal : -oppWindVal;
334507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } else if (hitOppDx * dx >= 0) {
334607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
334707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (abs(oppWind) < abs(oppSideWind)) {
334807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            oppWind = oppSideWind;
334907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
335007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
3351dac1d17027dcaa5596885a9f333979418b35001ccaryclark#if DEBUG_WINDING_AT_T
3352dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
3353dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
335407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    (void) markAndChaseWinding(start, end, winding, oppWind);
33557eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    // OPTIMIZATION: the reverse mark and chase could skip the first marking
33567eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    (void) markAndChaseWinding(end, start, winding, oppWind);
335707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
335807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
33594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgbool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const {
33604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (!baseAngle->inLoop()) {
33614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return false;
33624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
33634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = *indexPtr;
3364dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle* from = fTs[index].fFromAngle;
3365dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle* to = fTs[index].fToAngle;
33664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    while (++index < spanCount) {
3367dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* nextFrom = fTs[index].fFromAngle;
3368dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* nextTo = fTs[index].fToAngle;
3369dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (from != nextFrom || to != nextTo) {
33704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            break;
33714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
33724431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
33734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    *indexPtr = index;
33744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return true;
33754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
33764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
337707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// OPTIMIZE: successive calls could start were the last leaves off
337807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// or calls could specialize to walk forwards or backwards
33797eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.combool SkOpSegment::isMissing(double startT, const SkPoint& pt) const {
33804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int tCount = fTs.count();
33814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int index = 0; index < tCount; ++index) {
33827eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        const SkOpSpan& span = fTs[index];
33837eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        if (approximately_zero(startT - span.fT) && pt == span.fPt) {
338407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return false;
338507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
338607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
338707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return true;
338807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
338907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
3390dac1d17027dcaa5596885a9f333979418b35001ccaryclark
3391dac1d17027dcaa5596885a9f333979418b35001ccaryclarkSkOpSegment* SkOpSegment::isSimple(int* end, int* step) {
3392dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return nextChase(end, step, NULL, NULL);
33934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
33944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
3395a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.combool SkOpSegment::isTiny(const SkOpAngle* angle) const {
3396a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    int start = angle->start();
3397a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    int end = angle->end();
3398a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
3399a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return mSpan.fTiny;
3400a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com}
3401a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
3402a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.combool SkOpSegment::isTiny(int index) const {
3403a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return fTs[index].fTiny;
3404a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com}
3405a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
3406a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com// look pair of active edges going away from coincident edge
3407a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com// one of them should be the continuation of other
3408a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com// if both are active, look to see if they both the connect to another coincident pair
34094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org// if at least one is a line, then make the pair coincident
3410a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com// if neither is a line, test for coincidence
34118cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.orgbool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt,
34128cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        int step, bool cancel) {
34138cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    int otherTIndex = other->findT(otherT, otherPt, this);
3414a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    int next = other->nextExactSpan(otherTIndex, step);
34154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int otherMin = SkMin32(otherTIndex, next);
3416a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    int otherWind = other->span(otherMin).fWindValue;
3417a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    if (otherWind == 0) {
3418a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        return false;
3419a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    }
3420a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    SkASSERT(next >= 0);
3421866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org    int tIndex = 0;
3422866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org    do {
3423866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        SkOpSpan* test = &fTs[tIndex];
3424866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        SkASSERT(test->fT == 0);
3425866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        if (test->fOther == other || test->fOtherT != 1) {
3426866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org            continue;
3427866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        }
3428866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        SkPoint startPt, endPt;
3429866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        double endT;
3430866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt, &endPt, &endT)) {
3431866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org            SkOpSegment* match = test->fOther;
3432866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org            if (cancel) {
3433866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org                match->addTCancel(startPt, endPt, other);
3434866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org            } else {
3435630240d18805faf81d8e75172496ad165c2226b2caryclark                SkAssertResult(match->addTCoincident(startPt, endPt, endT, other));
3436a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com            }
3437866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org            return true;
3438866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        }
3439866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org    } while (fTs[++tIndex].fT == 0);
3440a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    return false;
3441a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com}
3442a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
344307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// this span is excluded by the winding rule -- chase the ends
344407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// as long as they are unambiguous to mark connections as done
344507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// and give them the same winding value
344607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
344707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) {
344807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int step = SkSign32(endIndex - index);
344907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int min = SkMin32(index, endIndex);
345007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    markDoneBinary(min);
3451dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan* last = NULL;
345207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSegment* other = this;
3453dac1d17027dcaa5596885a9f333979418b35001ccaryclark    while ((other = other->nextChase(&index, &step, &min, &last))) {
345407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (other->done()) {
3455dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(!last);
3456dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
345707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
345807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        other->markDoneBinary(min);
345907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
346007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return last;
346107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
346207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
346307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) {
346407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int step = SkSign32(endIndex - index);
346507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int min = SkMin32(index, endIndex);
346607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    markDoneUnary(min);
3467dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan* last = NULL;
346807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSegment* other = this;
3469dac1d17027dcaa5596885a9f333979418b35001ccaryclark    while ((other = other->nextChase(&index, &step, &min, &last))) {
347007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (other->done()) {
3471dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(!last);
3472dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
347307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
347407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        other->markDoneUnary(min);
347507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
347607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return last;
347707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
347807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
34794431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgSkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding) {
348007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int index = angle->start();
348107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int endIndex = angle->end();
348207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int step = SkSign32(endIndex - index);
348307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int min = SkMin32(index, endIndex);
348407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    markWinding(min, winding);
3485dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan* last = NULL;
348607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSegment* other = this;
3487dac1d17027dcaa5596885a9f333979418b35001ccaryclark    while ((other = other->nextChase(&index, &step, &min, &last))) {
348807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (other->fTs[min].fWindSum != SK_MinS32) {
348919eb3b2f0aa6dce5c0335230a8930e90733e5d5dcaryclark//            SkASSERT(other->fTs[min].fWindSum == winding);
3490dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(!last);
3491dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
349207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
349307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        other->markWinding(min, winding);
349407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
349507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return last;
349607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
349707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
34984431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgSkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding) {
34994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int min = SkMin32(index, endIndex);
35004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int step = SkSign32(endIndex - index);
35014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    markWinding(min, winding);
3502dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan* last = NULL;
35034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkOpSegment* other = this;
3504dac1d17027dcaa5596885a9f333979418b35001ccaryclark    while ((other = other->nextChase(&index, &step, &min, &last))) {
35054431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (other->fTs[min].fWindSum != SK_MinS32) {
35064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop);
3507dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(!last);
3508dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
35094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
35104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        other->markWinding(min, winding);
35114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
35124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return last;
35134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
35144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
351507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) {
351607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int min = SkMin32(index, endIndex);
351707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int step = SkSign32(endIndex - index);
351807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    markWinding(min, winding, oppWinding);
3519dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan* last = NULL;
352007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSegment* other = this;
3521dac1d17027dcaa5596885a9f333979418b35001ccaryclark    while ((other = other->nextChase(&index, &step, &min, &last))) {
352207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (other->fTs[min].fWindSum != SK_MinS32) {
3523da085e6ab3b17f16a69a35c2417bebabeb5e3494caryclark#ifdef SK_DEBUG
3524dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (!other->fTs[min].fLoop) {
3525dac1d17027dcaa5596885a9f333979418b35001ccaryclark                if (fOperand == other->fOperand) {
3526dac1d17027dcaa5596885a9f333979418b35001ccaryclark// FIXME: this is probably a bug -- rects4 asserts here
3527dac1d17027dcaa5596885a9f333979418b35001ccaryclark//                    SkASSERT(other->fTs[min].fWindSum == winding);
3528dac1d17027dcaa5596885a9f333979418b35001ccaryclark// FIXME: this is probably a bug -- rects3 asserts here
3529dac1d17027dcaa5596885a9f333979418b35001ccaryclark//                    SkASSERT(other->fTs[min].fOppSum == oppWinding);
3530dac1d17027dcaa5596885a9f333979418b35001ccaryclark                } else {
353165b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark// FIXME: this is probably a bug -- issue414409b asserts here
353265b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark//                    SkASSERT(other->fTs[min].fWindSum == oppWinding);
3533dac1d17027dcaa5596885a9f333979418b35001ccaryclark// FIXME: this is probably a bug -- skpwww_joomla_org_23 asserts here
3534dac1d17027dcaa5596885a9f333979418b35001ccaryclark//                    SkASSERT(other->fTs[min].fOppSum == winding);
3535dac1d17027dcaa5596885a9f333979418b35001ccaryclark                }
3536dac1d17027dcaa5596885a9f333979418b35001ccaryclark            }
3537dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(!last);
3538dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
3539dac1d17027dcaa5596885a9f333979418b35001ccaryclark            break;
3540dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
3541dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (fOperand == other->fOperand) {
3542dac1d17027dcaa5596885a9f333979418b35001ccaryclark            other->markWinding(min, winding, oppWinding);
3543dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } else {
3544dac1d17027dcaa5596885a9f333979418b35001ccaryclark            other->markWinding(min, oppWinding, winding);
354507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
354607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
354707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return last;
354807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
354907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
355007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) {
355107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int start = angle->start();
355207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int end = angle->end();
355307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return markAndChaseWinding(start, end, winding, oppWinding);
355407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
355507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
3556866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.orgSkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) {
355707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(angle->segment() == this);
355807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (UseInnerWinding(maxWinding, sumWinding)) {
355907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        maxWinding = sumWinding;
356007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
3561866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org    SkOpSpan* last = markAndChaseWinding(angle, maxWinding);
3562570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#if DEBUG_WINDING
3563570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (last) {
35647eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        SkDebugf("%s last id=%d windSum=", __FUNCTION__,
35657eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                last->fOther->fTs[last->fOtherIndex].fOther->debugID());
35667eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        SkPathOpsDebug::WindingPrintf(last->fWindSum);
35677eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        SkDebugf(" small=%d\n", last->fSmall);
3568570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
3569570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#endif
357007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return last;
357107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
357207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
357307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
3574866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org                                 int oppSumWinding, const SkOpAngle* angle) {
357507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(angle->segment() == this);
357607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (UseInnerWinding(maxWinding, sumWinding)) {
357707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        maxWinding = sumWinding;
357807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
357907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
358007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        oppMaxWinding = oppSumWinding;
358107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
3582866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org    SkOpSpan* last = markAndChaseWinding(angle, maxWinding, oppMaxWinding);
3583570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#if DEBUG_WINDING
3584570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (last) {
35857eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        SkDebugf("%s last id=%d windSum=", __FUNCTION__,
35867eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                last->fOther->fTs[last->fOtherIndex].fOther->debugID());
35877eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        SkPathOpsDebug::WindingPrintf(last->fWindSum);
35887eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        SkDebugf(" small=%d\n", last->fSmall);
3589570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
3590570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#endif
359107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return last;
359207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
359307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
359407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// FIXME: this should also mark spans with equal (x,y)
359507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// This may be called when the segment is already marked done. While this
359607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// wastes time, it shouldn't do any more than spin through the T spans.
359707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// OPTIMIZATION: abort on first done found (assuming that this code is
359807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// always called to mark segments done).
359907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markDone(int index, int winding) {
360007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com  //  SkASSERT(!done());
360107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(winding);
360207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double referenceT = fTs[index].fT;
360307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = index;
360407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
360507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneDone(__FUNCTION__, lesser, winding);
360607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
360707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
360807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneDone(__FUNCTION__, index, winding);
360907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
36104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
361107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
361207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
361307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markDoneBinary(int index) {
361407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double referenceT = fTs[index].fT;
361507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = index;
361607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
361707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneDoneBinary(__FUNCTION__, lesser);
361807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
361907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
362007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneDoneBinary(__FUNCTION__, index);
362107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
36224431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
362307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
362407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
362507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markDoneUnary(int index) {
362607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double referenceT = fTs[index].fT;
362707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = index;
362807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
362907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneDoneUnary(__FUNCTION__, lesser);
363007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
363107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
363207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneDoneUnary(__FUNCTION__, index);
363307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
36344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
363507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
363607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
363707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) {
363807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* span = markOneWinding(funName, tIndex, winding);
36394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (!span || span->fDone) {
364007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return;
364107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
364207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fDone = true;
364307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fDoneSpans++;
364407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
364507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
364607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) {
364707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* span = verifyOneWinding(funName, tIndex);
364807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!span) {
364907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return;
365007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
36514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(!span->fDone);
365207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fDone = true;
365307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fDoneSpans++;
365407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
365507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
365607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) {
365707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan* span = verifyOneWindingU(funName, tIndex);
365807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (!span) {
365907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return;
366007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
36614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (span->fWindSum == SK_MinS32) {
36624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkDebugf("%s uncomputed\n", __FUNCTION__);
36634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
36644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkASSERT(!span->fDone);
366507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fDone = true;
366607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    fDoneSpans++;
366707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
366807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
366907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) {
367007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan& span = fTs[tIndex];
36714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (span.fDone && !span.fSmall) {
367207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
367307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
367407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_MARK_DONE
367507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    debugShowNewWinding(funName, span, winding);
367607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
367707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
36788cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#if DEBUG_LIMIT_WIND_SUM
36798cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
36808cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#endif
368107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span.fWindSum = winding;
368207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return &span;
368307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
368407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
368507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding,
368607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                                      int oppWinding) {
368707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan& span = fTs[tIndex];
36887eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    if (span.fDone && !span.fSmall) {
368907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
369007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
369107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_MARK_DONE
369207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    debugShowNewWinding(funName, span, winding, oppWinding);
369307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
369407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
36958cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#if DEBUG_LIMIT_WIND_SUM
36968cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM);
36978cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#endif
369807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span.fWindSum = winding;
369907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
37008cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#if DEBUG_LIMIT_WIND_SUM
37018cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM);
37028cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#endif
370307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span.fOppSum = oppWinding;
37044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
370507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return &span;
370607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
370707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
370807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
3709e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclarkbool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const {
371007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(fVerb != SkPath::kLine_Verb);
371107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkPoint edge[4];
371207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    subDivide(tStart, tEnd, edge);
3713cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    int points = SkPathOpsVerbToPoints(fVerb);
3714cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY);
3715e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark    bool sumSet = false;
371607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fVerb == SkPath::kCubic_Verb) {
3717e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        SkDCubic cubic;
3718e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        cubic.set(edge);
3719e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        double inflectionTs[2];
3720e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        int inflections = cubic.findInflections(inflectionTs);
3721e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        // FIXME: this fixes cubicOp114 and breaks cubicOp58d
3722e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        // the trouble is that cubics with inflections confuse whether the curve breaks towards
3723e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        // or away, which in turn is used to determine if it is on the far right or left.
3724e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        // Probably a totally different approach is in order. At one time I tried to project a
3725e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        // horizontal ray to determine winding, but was confused by how to map the vertically
3726e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        // oriented winding computation over.
3727e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        if (0 && inflections) {
3728e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            double tLo = this->span(tStart).fT;
3729e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            double tHi = this->span(tEnd).fT;
3730e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            double tLoStart = tLo;
3731e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            for (int index = 0; index < inflections; ++index) {
3732e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                if (between(tLo, inflectionTs[index], tHi)) {
3733e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                    tLo = inflectionTs[index];
3734e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                }
3735e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            }
3736e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            if (tLo != tLoStart && tLo != tHi) {
3737e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                SkDPoint sub[2];
3738e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                sub[0] = cubic.ptAtT(tLo);
3739e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                sub[1].set(edge[3]);
3740e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                SkDPoint ctrl[2];
3741e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl);
3742e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                edge[0] = sub[0].asSkPoint();
3743e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                edge[1] = ctrl[0].asSkPoint();
3744e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                edge[2] = ctrl[1].asSkPoint();
3745e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY);
3746e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            }
3747e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        }
374807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY);
374907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (edge[1].fY < lesser && edge[2].fY < lesser) {
375007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }};
375107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }};
375207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (SkIntersections::Test(tangent1, tangent2)) {
375307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT);
375407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY);
375507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY);
3756e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark                sumSet = true;
375707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
375807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
375907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
3760e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark    if (!sumSet) {
3761e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        for (int idx = 0; idx < points; ++idx){
3762e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark            sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
3763e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        }
3764e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark    }
3765e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark    if (fVerb == SkPath::kCubic_Verb) {
3766e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        SkDCubic cubic;
3767e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        cubic.set(edge);
3768e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark         *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine();
3769e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark    } else {
3770e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        SkDQuad quad;
3771e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        quad.set(edge);
3772e4097e3a0b10bb0047a45b6949ca01826f0807a7caryclark        *swap = sum > 0 && !quad.monotonicInY();
377307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
377407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return sum <= 0;
377507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
377607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
377707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::monotonicInY(int tStart, int tEnd) const {
37788cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkASSERT(fVerb != SkPath::kLine_Verb);
377907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fVerb == SkPath::kQuad_Verb) {
378007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
378107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return dst.monotonicInY();
378207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
378307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(fVerb == SkPath::kCubic_Verb);
378407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
378507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return dst.monotonicInY();
378607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
378707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
378807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::serpentine(int tStart, int tEnd) const {
378907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fVerb != SkPath::kCubic_Verb) {
379007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return false;
379107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
379207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT);
379307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return dst.serpentine();
379407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
379507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
379607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) {
379707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan& span = fTs[tIndex];
379807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (span.fDone) {
379907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
380007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
380107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_MARK_DONE
380207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum);
380307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
3804866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// If the prior angle in the sort is unorderable, the winding sum may not be computable.
3805866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// To enable the assert, the 'prior is unorderable' state could be
3806866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// piped down to this test, but not sure it's worth it.
3807866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// (Once the sort order is stored in the span, this test may be feasible.)
3808866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org//    SkASSERT(span.fWindSum != SK_MinS32);
3809866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org//    SkASSERT(span.fOppSum != SK_MinS32);
381007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return &span;
381107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
381207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
381307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comSkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) {
381407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpSpan& span = fTs[tIndex];
381507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (span.fDone) {
381607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return NULL;
381707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
381807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_MARK_DONE
381907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    debugShowNewWinding(funName, span, span.fWindSum);
382007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
3821866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// If the prior angle in the sort is unorderable, the winding sum may not be computable.
3822866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// To enable the assert, the 'prior is unorderable' state could be
3823866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// piped down to this test, but not sure it's worth it.
3824866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org// (Once the sort order is stored in the span, this test may be feasible.)
3825866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org//    SkASSERT(span.fWindSum != SK_MinS32);
382607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return &span;
382707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
382807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
382907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markWinding(int index, int winding) {
383007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com//    SkASSERT(!done());
383107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(winding);
383207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double referenceT = fTs[index].fT;
383307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = index;
383407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
383507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneWinding(__FUNCTION__, lesser, winding);
383607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
383707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
383807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneWinding(__FUNCTION__, index, winding);
383907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com   } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
38404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
384107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
384207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
384307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::markWinding(int index, int winding, int oppWinding) {
384407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com//    SkASSERT(!done());
384507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(winding || oppWinding);
384607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double referenceT = fTs[index].fT;
384707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = index;
384807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
384907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
385007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
385107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    do {
385207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        markOneWinding(__FUNCTION__, index, winding, oppWinding);
385307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com   } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
38544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
385507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
385607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
385707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) {
385807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int nextDoorWind = SK_MaxS32;
385907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int nextOppWind = SK_MaxS32;
38604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // prefer exact matches
386107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (tIndex > 0) {
386207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const SkOpSpan& below = fTs[tIndex - 1];
38634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (below.fT == t) {
38644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            nextDoorWind = below.fWindValue;
38654431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            nextOppWind = below.fOppValue;
38664431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
38674431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
38684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
38694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& above = fTs[tIndex + 1];
38704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (above.fT == t) {
38714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            nextDoorWind = above.fWindValue;
38724431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            nextOppWind = above.fOppValue;
38734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
38744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
38754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (nextDoorWind == SK_MaxS32 && tIndex > 0) {
38764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        const SkOpSpan& below = fTs[tIndex - 1];
387707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (approximately_negative(t - below.fT)) {
387807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            nextDoorWind = below.fWindValue;
387907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            nextOppWind = below.fOppValue;
388007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
388107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
388207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) {
388307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const SkOpSpan& above = fTs[tIndex + 1];
388407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (approximately_negative(above.fT - t)) {
388507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            nextDoorWind = above.fWindValue;
388607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            nextOppWind = above.fOppValue;
388707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
388807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
388907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) {
389007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const SkOpSpan& below = fTs[tIndex - 1];
389107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        nextDoorWind = below.fWindValue;
389207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        nextOppWind = below.fOppValue;
389307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
389407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (nextDoorWind != SK_MaxS32) {
389507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkOpSpan& newSpan = fTs[tIndex];
389607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        newSpan.fWindValue = nextDoorWind;
389707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        newSpan.fOppValue = nextOppWind;
389807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (!nextDoorWind && !nextOppWind && !newSpan.fDone) {
389907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            newSpan.fDone = true;
390007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            ++fDoneSpans;
390107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
390207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
390307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
390407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
390507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.combool SkOpSegment::nextCandidate(int* start, int* end) const {
390607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (fTs[*end].fDone) {
390707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fTs[*end].fT == 1) {
390807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return false;
390907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
391007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        ++(*end);
391107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
391207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *start = *end;
391307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *end = nextExactSpan(*start, 1);
391407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return true;
391507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
391607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
3917dac1d17027dcaa5596885a9f333979418b35001ccaryclarkstatic SkOpSegment* set_last(SkOpSpan** last, SkOpSpan* endSpan) {
3918dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (last && !endSpan->fSmall) {
3919dac1d17027dcaa5596885a9f333979418b35001ccaryclark        *last = endSpan;
3920dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
3921dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return NULL;
3922dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
3923dac1d17027dcaa5596885a9f333979418b35001ccaryclark
3924dac1d17027dcaa5596885a9f333979418b35001ccaryclarkSkOpSegment* SkOpSegment::nextChase(int* indexPtr, int* stepPtr, int* minPtr, SkOpSpan** last) {
3925dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int origIndex = *indexPtr;
3926dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int step = *stepPtr;
3927dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int end = nextExactSpan(origIndex, step);
392807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(end >= 0);
3929dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSpan& endSpan = fTs[end];
3930dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpAngle* angle = step > 0 ? endSpan.fFromAngle : endSpan.fToAngle;
3931dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int foundIndex;
3932dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int otherEnd;
3933dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkOpSegment* other;
3934dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (angle == NULL) {
3935dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (endSpan.fT != 0 && endSpan.fT != 1) {
3936dac1d17027dcaa5596885a9f333979418b35001ccaryclark            return NULL;
3937dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
3938dac1d17027dcaa5596885a9f333979418b35001ccaryclark        other = endSpan.fOther;
3939dac1d17027dcaa5596885a9f333979418b35001ccaryclark        foundIndex = endSpan.fOtherIndex;
3940dac1d17027dcaa5596885a9f333979418b35001ccaryclark        otherEnd = other->nextExactSpan(foundIndex, step);
3941dac1d17027dcaa5596885a9f333979418b35001ccaryclark    } else {
3942dac1d17027dcaa5596885a9f333979418b35001ccaryclark        int loopCount = angle->loopCount();
3943dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (loopCount > 2) {
3944dac1d17027dcaa5596885a9f333979418b35001ccaryclark            return set_last(last, &endSpan);
3945dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
3946dac1d17027dcaa5596885a9f333979418b35001ccaryclark        const SkOpAngle* next = angle->next();
394765b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        if (NULL == next) {
394865b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark            return NULL;
394965b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        }
3950dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (angle->sign() != next->sign()) {
3951dac1d17027dcaa5596885a9f333979418b35001ccaryclark#if DEBUG_WINDING
3952dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkDebugf("%s mismatched signs\n", __FUNCTION__);
3953dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
3954dac1d17027dcaa5596885a9f333979418b35001ccaryclark        //    return set_last(last, &endSpan);
3955dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
3956dac1d17027dcaa5596885a9f333979418b35001ccaryclark        other = next->segment();
3957dac1d17027dcaa5596885a9f333979418b35001ccaryclark        foundIndex = end = next->start();
3958dac1d17027dcaa5596885a9f333979418b35001ccaryclark        otherEnd = next->end();
3959570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
3960dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int foundStep = foundIndex < otherEnd ? 1 : -1;
3961dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (*stepPtr != foundStep) {
3962dac1d17027dcaa5596885a9f333979418b35001ccaryclark        return set_last(last, &endSpan);
396307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
3964dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(*indexPtr >= 0);
396565b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    if (otherEnd < 0) {
396665b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark        return NULL;
396765b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark    }
396865b427cff9cd34a06ff060d65d00cc3615d8fd94caryclark//    SkASSERT(otherEnd >= 0);
3969dac1d17027dcaa5596885a9f333979418b35001ccaryclark#if 1
3970dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int origMin = origIndex + (step < 0 ? step : 0);
3971dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkOpSpan& orig = this->span(origMin);
3972dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
3973dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int foundMin = SkMin32(foundIndex, otherEnd);
3974dac1d17027dcaa5596885a9f333979418b35001ccaryclark#if 1
3975dac1d17027dcaa5596885a9f333979418b35001ccaryclark    const SkOpSpan& found = other->span(foundMin);
3976dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (found.fWindValue != orig.fWindValue || found.fOppValue != orig.fOppValue) {
3977dac1d17027dcaa5596885a9f333979418b35001ccaryclark          return set_last(last, &endSpan);
3978dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
3979dac1d17027dcaa5596885a9f333979418b35001ccaryclark#endif
3980dac1d17027dcaa5596885a9f333979418b35001ccaryclark    *indexPtr = foundIndex;
3981dac1d17027dcaa5596885a9f333979418b35001ccaryclark    *stepPtr = foundStep;
3982dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (minPtr) {
3983dac1d17027dcaa5596885a9f333979418b35001ccaryclark        *minPtr = foundMin;
3984a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com    }
398507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return other;
398607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
398707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
398807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// This has callers for two different situations: one establishes the end
398907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// of the current span, and one establishes the beginning of the next span
399007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// (thus the name). When this is looking for the end of the current span,
399107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// coincidence is found when the beginning Ts contain -step and the end
399207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// contains step. When it is looking for the beginning of the next, the
399307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// first Ts found can be ignored and the last Ts should contain -step.
399407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// OPTIMIZATION: probably should split into two functions
399507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::nextSpan(int from, int step) const {
399607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const SkOpSpan& fromSpan = fTs[from];
399707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int count = fTs.count();
399807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int to = from;
399907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (step > 0 ? ++to < count : --to >= 0) {
400007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const SkOpSpan& span = fTs[to];
400107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (approximately_zero(span.fT - fromSpan.fT)) {
400207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            continue;
400307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
400407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return to;
400507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
400607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return -1;
400707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
400807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
400907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// FIXME
401007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// this returns at any difference in T, vs. a preset minimum. It may be
401107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com// that all callers to nextSpan should use this instead.
401207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::nextExactSpan(int from, int step) const {
401307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int to = from;
4014570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (step < 0) {
4015570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        const SkOpSpan& fromSpan = fTs[from];
4016570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        while (--to >= 0) {
4017570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            const SkOpSpan& span = fTs[to];
4018570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) {
4019570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                continue;
4020570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
4021570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            return to;
4022570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
4023570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    } else {
4024570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        while (fTs[from].fTiny) {
4025570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            from++;
4026570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        }
4027570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        const SkOpSpan& fromSpan = fTs[from];
4028570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        int count = fTs.count();
4029570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        while (++to < count) {
4030570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            const SkOpSpan& span = fTs[to];
4031570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            if (precisely_negative(span.fT - fromSpan.fT)) {
4032570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com                continue;
4033570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            }
4034570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            return to;
403507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
403607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
403707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return -1;
403807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
403907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
4040dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::pinT(const SkPoint& pt, double* t) {
4041dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (pt == fPts[0]) {
4042dac1d17027dcaa5596885a9f333979418b35001ccaryclark        *t = 0;
4043dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
4044dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int count = SkPathOpsVerbToPoints(fVerb);
4045dac1d17027dcaa5596885a9f333979418b35001ccaryclark    if (pt == fPts[count]) {
4046dac1d17027dcaa5596885a9f333979418b35001ccaryclark        *t = 1;
4047dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
4048dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
4049dac1d17027dcaa5596885a9f333979418b35001ccaryclark
40505e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclarkbool SkOpSegment::reversePoints(const SkPoint& p1, const SkPoint& p2) const {
40515e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    SkASSERT(p1 != p2);
40525e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    int spanCount = count();
40535e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    int p1IndexMin = -1;
40545e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    int p2IndexMax = spanCount;
40555e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    for (int index = 0; index < spanCount; ++index) {
40565e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        const SkOpSpan& span = fTs[index];
40575e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        if (span.fPt == p1) {
40585e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark            if (p1IndexMin < 0) {
40595e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark                p1IndexMin = index;
40605e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark            }
40615e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        } else if (span.fPt == p2) {
40625e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark            p2IndexMax = index;
40635e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark        }
40645e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    }
40655e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark    return p1IndexMin > p2IndexMax;
40665e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark}
40675e27e0eb1d1d4c7674e221d3ba3314500ea0b97acaryclark
4068dac1d17027dcaa5596885a9f333979418b35001ccaryclarkvoid SkOpSegment::setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt,
4069dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSegment* other) {
4070dac1d17027dcaa5596885a9f333979418b35001ccaryclark    int count = this->count();
4071dac1d17027dcaa5596885a9f333979418b35001ccaryclark    for (int index = 0; index < count; ++index) {
4072dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpSpan &span = fTs[index];
4073dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if ((startPt == span.fPt || endPt == span.fPt) && other == span.fOther) {
4074dac1d17027dcaa5596885a9f333979418b35001ccaryclark            span.fCoincident = true;
4075dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
4076dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
4077dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
4078dac1d17027dcaa5596885a9f333979418b35001ccaryclark
407907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
408007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) {
408107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int deltaSum = spanSign(index, endIndex);
408207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oppDeltaSum = oppSign(index, endIndex);
408307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (operand()) {
408407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *maxWinding = *sumSuWinding;
408507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *sumWinding = *sumSuWinding -= deltaSum;
408607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *oppMaxWinding = *sumMiWinding;
408707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *oppSumWinding = *sumMiWinding -= oppDeltaSum;
408807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } else {
408907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *maxWinding = *sumMiWinding;
409007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *sumWinding = *sumMiWinding -= deltaSum;
409107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *oppMaxWinding = *sumSuWinding;
409207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *oppSumWinding = *sumSuWinding -= oppDeltaSum;
409307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
40948cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#if DEBUG_LIMIT_WIND_SUM
40958cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
40968cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM);
40978cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#endif
4098570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
4099570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
4100570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding,
4101570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        int* maxWinding, int* sumWinding) {
4102570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int deltaSum = spanSign(index, endIndex);
4103570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    *maxWinding = *sumMiWinding;
4104570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    *sumWinding = *sumMiWinding -= deltaSum;
41058cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#if DEBUG_LIMIT_WIND_SUM
41068cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM);
41078cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org#endif
410807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
410907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
41104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::sortAngles() {
41114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int spanCount = fTs.count();
41124431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (spanCount <= 2) {
41134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return;
41144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
41154431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index = 0;
41164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    do {
4117dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* fromAngle = fTs[index].fFromAngle;
4118dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* toAngle = fTs[index].fToAngle;
4119dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (!fromAngle && !toAngle) {
41204431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            index += 1;
41214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
41224431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
41234431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkOpAngle* baseAngle = NULL;
4124dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (fromAngle) {
4125dac1d17027dcaa5596885a9f333979418b35001ccaryclark            baseAngle = fromAngle;
41264431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (inLoop(baseAngle, spanCount, &index)) {
41274431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                continue;
41284431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
41294431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
4130cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com#if DEBUG_ANGLE
41314431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        bool wroteAfterHeader = false;
4132cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com#endif
4133dac1d17027dcaa5596885a9f333979418b35001ccaryclark        if (toAngle) {
41344431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (!baseAngle) {
41354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                baseAngle = toAngle;
41364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (inLoop(baseAngle, spanCount, &index)) {
41374431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    continue;
41384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
41394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            } else {
41404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                SkDEBUGCODE(int newIndex = index);
41414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex == index);
41424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_ANGLE
41434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
41444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                        index);
41454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                wroteAfterHeader = true;
41464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
41474431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                baseAngle->insert(toAngle);
414807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
414907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
4150dac1d17027dcaa5596885a9f333979418b35001ccaryclark        SkOpAngle* nextFrom, * nextTo;
41514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        int firstIndex = index;
41524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        do {
41534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkOpSpan& span = fTs[index];
41544431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkOpSegment* other = span.fOther;
41554431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            SkOpSpan& oSpan = other->fTs[span.fOtherIndex];
4156dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkOpAngle* oAngle = oSpan.fFromAngle;
4157dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (oAngle) {
4158570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#if DEBUG_ANGLE
41594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (!wroteAfterHeader) {
41604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
41614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                            index);
41624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    wroteAfterHeader = true;
41634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
4164570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#endif
41658cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                if (!oAngle->loopContains(*baseAngle)) {
41668cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                    baseAngle->insert(oAngle);
41678cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                }
41684431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
4169dac1d17027dcaa5596885a9f333979418b35001ccaryclark            oAngle = oSpan.fToAngle;
4170dac1d17027dcaa5596885a9f333979418b35001ccaryclark            if (oAngle) {
41714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_ANGLE
41724431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (!wroteAfterHeader) {
41734431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT,
41744431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                            index);
41754431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    wroteAfterHeader = true;
41764431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
41774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
41788cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                if (!oAngle->loopContains(*baseAngle)) {
41798cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                    baseAngle->insert(oAngle);
41808cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org                }
41814431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
41824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            if (++index == spanCount) {
41834431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                break;
41844431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
4185dac1d17027dcaa5596885a9f333979418b35001ccaryclark            nextFrom = fTs[index].fFromAngle;
4186dac1d17027dcaa5596885a9f333979418b35001ccaryclark            nextTo = fTs[index].fToAngle;
4187dac1d17027dcaa5596885a9f333979418b35001ccaryclark        } while (fromAngle == nextFrom && toAngle == nextTo);
41884431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (baseAngle && baseAngle->loopCount() == 1) {
41894431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            index = firstIndex;
41904431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            do {
41914431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                SkOpSpan& span = fTs[index];
4192dac1d17027dcaa5596885a9f333979418b35001ccaryclark                span.fFromAngle = span.fToAngle = NULL;
41934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                if (++index == spanCount) {
41944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                    break;
41954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                }
4196dac1d17027dcaa5596885a9f333979418b35001ccaryclark                nextFrom = fTs[index].fFromAngle;
4197dac1d17027dcaa5596885a9f333979418b35001ccaryclark                nextTo = fTs[index].fToAngle;
4198dac1d17027dcaa5596885a9f333979418b35001ccaryclark            } while (fromAngle == nextFrom && toAngle == nextTo);
41994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            baseAngle = NULL;
42004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
42014431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_SORT
42024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkASSERT(!baseAngle || baseAngle->loopCount() > 1);
42034431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
42044431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } while (index < spanCount);
4205570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
4206570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
4207cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com// return true if midpoints were computed
4208cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.combool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const {
4209cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    SkASSERT(start != end);
421007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    edge[0] = fTs[start].fPt;
4211cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    int points = SkPathOpsVerbToPoints(fVerb);
4212cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    edge[points] = fTs[end].fPt;
4213cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    if (fVerb == SkPath::kLine_Verb) {
4214cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        return false;
4215cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    }
4216cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    double startT = fTs[start].fT;
4217cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    double endT = fTs[end].fT;
4218cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
4219cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        // don't compute midpoints if we already have them
422007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (fVerb == SkPath::kQuad_Verb) {
4221cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            edge[1] = fPts[1];
4222cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            return false;
422307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
4224cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        SkASSERT(fVerb == SkPath::kCubic_Verb);
4225cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        if (start < end) {
4226cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            edge[1] = fPts[1];
4227cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            edge[2] = fPts[2];
4228cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            return false;
4229cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        }
4230cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        edge[1] = fPts[2];
4231cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        edge[2] = fPts[1];
4232cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        return false;
4233cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    }
4234cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }};
4235cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    if (fVerb == SkPath::kQuad_Verb) {
4236cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint();
4237cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    } else {
4238cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        SkASSERT(fVerb == SkPath::kCubic_Verb);
4239cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        SkDPoint ctrl[2];
4240cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl);
4241cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        edge[1] = ctrl[0].asSkPoint();
4242cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        edge[2] = ctrl[1].asSkPoint();
424307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
4244cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    return true;
4245cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com}
4246cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com
4247cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com// return true if midpoints were computed
4248cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.combool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const {
4249cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    SkASSERT(start != end);
4250cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    (*result)[0].set(fTs[start].fPt);
4251cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    int points = SkPathOpsVerbToPoints(fVerb);
4252cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    (*result)[points].set(fTs[end].fPt);
4253cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    if (fVerb == SkPath::kLine_Verb) {
4254cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        return false;
4255cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    }
4256cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    double startT = fTs[start].fT;
4257cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    double endT = fTs[end].fT;
4258cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) {
4259cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        // don't compute midpoints if we already have them
4260cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        if (fVerb == SkPath::kQuad_Verb) {
4261cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            (*result)[1].set(fPts[1]);
4262cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            return false;
4263cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        }
4264cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        SkASSERT(fVerb == SkPath::kCubic_Verb);
4265cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        if (start < end) {
4266cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            (*result)[1].set(fPts[1]);
4267cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            (*result)[2].set(fPts[2]);
4268cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com            return false;
4269cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        }
4270cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        (*result)[1].set(fPts[2]);
4271cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        (*result)[2].set(fPts[1]);
4272cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        return false;
4273cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    }
4274cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    if (fVerb == SkPath::kQuad_Verb) {
4275cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT);
4276cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    } else {
4277cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        SkASSERT(fVerb == SkPath::kCubic_Verb);
4278cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com        SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]);
4279cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    }
4280cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com    return true;
428107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
428207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
428307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const {
428407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkPoint edge[4];
428507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    subDivide(start, end, edge);
4286277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com    (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
428707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
428807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
4289570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt,
4290570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        const SkPoint& startPt) {
4291570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int outCount = outsidePts->count();
4292570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
4293570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        outsidePts->push_back(endPt);
4294570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        outsidePts->push_back(startPt);
4295570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
4296570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
4297570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
4298570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) {
4299570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int outCount = outsidePts->count();
4300570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) {
4301570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        outsidePts->push_back(startPt);
430207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
430307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
430407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
430507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::undoneSpan(int* start, int* end) {
43064431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int tCount = fTs.count();
43074431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int index;
430807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    for (index = 0; index < tCount; ++index) {
430907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (!fTs[index].fDone) {
431007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            break;
431107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
431207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
431307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(index < tCount - 1);
431407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *start = index;
431507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    double startT = fTs[index].fT;
431607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    while (approximately_negative(fTs[++index].fT - startT))
431707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkASSERT(index < tCount);
431807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(index < tCount);
431907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    *end = index;
432007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
432107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
432207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::updateOppWinding(int index, int endIndex) const {
432307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = SkMin32(index, endIndex);
432407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oppWinding = oppSum(lesser);
432507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int oppSpanWinding = oppSign(index, endIndex);
432607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding)
432707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            && oppWinding != SK_MaxS32) {
432807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        oppWinding -= oppSpanWinding;
432907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
433007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return oppWinding;
433107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
433207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
433307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::updateOppWinding(const SkOpAngle* angle) const {
433407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int startIndex = angle->start();
433507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int endIndex = angle->end();
433607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return updateOppWinding(endIndex, startIndex);
433707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
433807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
433907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
434007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int startIndex = angle->start();
434107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int endIndex = angle->end();
434207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return updateOppWinding(startIndex, endIndex);
434307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
434407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
434507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::updateWinding(int index, int endIndex) const {
434607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int lesser = SkMin32(index, endIndex);
434707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int winding = windSum(lesser);
43488cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    if (winding == SK_MinS32) {
43498cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org        return winding;
43508cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org    }
435107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int spanWinding = spanSign(index, endIndex);
4352570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (winding && UseInnerWinding(winding - spanWinding, winding)
4353570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            && winding != SK_MaxS32) {
435407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        winding -= spanWinding;
435507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
435607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return winding;
435707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
435807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
435907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::updateWinding(const SkOpAngle* angle) const {
436007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int startIndex = angle->start();
436107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int endIndex = angle->end();
436207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return updateWinding(endIndex, startIndex);
436307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
436407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
4365570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comint SkOpSegment::updateWindingReverse(int index, int endIndex) const {
4366570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int lesser = SkMin32(index, endIndex);
4367570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int winding = windSum(lesser);
4368570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int spanWinding = spanSign(endIndex, index);
4369570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    if (winding && UseInnerWindingReverse(winding - spanWinding, winding)
4370570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            && winding != SK_MaxS32) {
4371570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com        winding -= spanWinding;
4372570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
4373570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return winding;
4374570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
4375570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
437607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
437707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int startIndex = angle->start();
437807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int endIndex = angle->end();
4379570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return updateWindingReverse(endIndex, startIndex);
4380570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
4381570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
4382570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com// OPTIMIZATION: does the following also work, and is it any faster?
4383570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com// return outerWinding * innerWinding > 0
4384570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com//      || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0)))
4385570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
4386570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkASSERT(outerWinding != SK_MaxS32);
4387570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkASSERT(innerWinding != SK_MaxS32);
4388570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int absOut = abs(outerWinding);
4389570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int absIn = abs(innerWinding);
4390570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
4391570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return result;
4392570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com}
4393570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
4394570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) {
4395570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkASSERT(outerWinding != SK_MaxS32);
4396570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    SkASSERT(innerWinding != SK_MaxS32);
4397570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int absOut = abs(outerWinding);
4398570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    int absIn = abs(innerWinding);
4399570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    bool result = absOut == absIn ? true : absOut < absIn;
4400570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    return result;
440107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
440207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
440307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const {
440407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (approximately_zero(tHit - t(tIndex))) {  // if we hit the end of a span, disregard
440507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return SK_MinS32;
440607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
440707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex);
440807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(winding != SK_MinS32);
440907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex);
441007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING_AT_T
4411dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __FUNCTION__,
4412dac1d17027dcaa5596885a9f333979418b35001ccaryclark            debugID(), crossOpp, tHit, t(tIndex), winding, windVal);
441307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
441407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // see if a + change in T results in a +/- change in X (compute x'(T))
4415277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com    *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX;
441607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
441707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        *dx = fPts[2].fX - fPts[1].fX - *dx;
441807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
441907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (*dx == 0) {
442007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING_AT_T
442107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDebugf(" dx=0 winding=SK_MinS32\n");
442207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
442307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return SK_MinS32;
442407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
4425a4aced47281e085201a356ce888b92138846e9f6skia.committer@gmail.com    if (windVal < 0) {  // reverse sign if opp contour traveled in reverse
442607e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com            *dx = -*dx;
442707e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    }
442807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (winding * *dx > 0) {  // if same signs, result is negative
442907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        winding += *dx > 0 ? -windVal : windVal;
443007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
443107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if DEBUG_WINDING_AT_T
443207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
443307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#endif
443407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return winding;
443507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
443607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
443707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comint SkOpSegment::windSum(const SkOpAngle* angle) const {
443807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int start = angle->start();
443907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int end = angle->end();
444007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int index = SkMin32(start, end);
444107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return windSum(index);
444207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
444307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
444407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comvoid SkOpSegment::zeroSpan(SkOpSpan* span) {
4445a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com    SkASSERT(span->fWindValue > 0 || span->fOppValue != 0);
444607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fWindValue = 0;
444707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fOppValue = 0;
44487eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    if (span->fTiny || span->fSmall) {
44497eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return;
44507eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    }
445107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkASSERT(!span->fDone);
445207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    span->fDone = true;
445307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    ++fDoneSpans;
445407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
4455