1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2014 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpCoincidence.h"
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpContour.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpSegment.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathWriter.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpPtT::alias() const {
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return this->span()->ptT() != this;
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpPtT* SkOpPtT::active() const {
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fDeleted) {
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return this;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stopPtT = ptT;
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((ptT = ptT->next()) != stopPtT) {
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT->fSpan == fSpan && !ptT->fDeleted) {
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return ptT;
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(0);  // should never return deleted
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return this;
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpPtT::contains(const SkOpPtT* check) const {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOPASSERT(this != check);
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stopPtT = ptT;
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((ptT = ptT->next()) != stopPtT) {
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT == check) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const {
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->segment() != segment);
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stopPtT = ptT;
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((ptT = ptT->next()) != stopPtT) {
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT->fPt == pt && ptT->segment() == segment) {
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpPtT::contains(const SkOpSegment* segment, double t) const {
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stopPtT = ptT;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((ptT = ptT->next()) != stopPtT) {
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT->fT == t && ptT->segment() == segment) {
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) const {
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->segment() != check);
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stopPtT = ptT;
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((ptT = ptT->next()) != stopPtT) {
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT->segment() == check && !ptT->deleted()) {
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return ptT;
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return nullptr;
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpContour* SkOpPtT::contour() const {
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return segment()->contour();
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const {
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stopPtT = ptT;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT->segment() == segment && !ptT->deleted()) {
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return ptT;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT = ptT->fNext;
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (stopPtT != ptT);
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    SkASSERT(0);
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return nullptr;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpGlobalState* SkOpPtT::globalState() const {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return contour()->globalState();
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) {
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fT = t;
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPt = pt;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSpan = span;
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fNext = this;
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDuplicatePt = duplicate;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDeleted = false;
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCoincident = false;
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fID = span->globalState()->nextPtTID());
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpPtT::onEnd() const {
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* span = this->span();
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (span->ptT() != this) {
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment = this->segment();
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return span == segment->head() || span == segment->tail();
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpPtT::ptAlreadySeen(const SkOpPtT* check) const {
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (this != check) {
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (this->fPt == check->fPt) {
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        check = check->fNext;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpPtT* SkOpPtT::prev() {
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* result = this;
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* next = this;
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((next = next->fNext) != this) {
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result = next;
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(result->fNext == this);
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpSegment* SkOpPtT::segment() const {
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return span()->segment();
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpSegment* SkOpPtT::segment() {
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return span()->segment();
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpPtT::setDeleted() {
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this);
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOPASSERT(!fDeleted);
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDeleted = true;
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::addOpp(SkOpSpanBase* opp) {
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!oppPrev) {
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->mergeMatches(opp);
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->ptT()->addOpp(opp->ptT(), oppPrev);
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->checkForCollapsedCoincidence();
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpSpanBase::collapsed(double s, double e) const {
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* start = &fPtT;
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* walk = start;
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double min = walk->fT;
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double max = min;
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment = this->segment();
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((walk = walk->next()) != start) {
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (walk->segment() != segment) {
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        min = SkTMin(min, walk->fT);
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        max = SkTMax(max, walk->fT);
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (between(min, s, max) && between(min, e, max)) {
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpSpanBase::contains(const SkOpSpanBase* span) const {
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* start = &fPtT;
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* check = &span->fPtT;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOPASSERT(start != check);
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* walk = start;
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((walk = walk->next()) != start) {
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (walk == check) {
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const {
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* start = &fPtT;
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* walk = start;
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((walk = walk->next()) != start) {
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (walk->deleted()) {
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (walk->segment() == segment && walk->span()->ptT() == walk) {
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return walk;
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return nullptr;
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const {
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->segment() != segment);
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* next = this;
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((next = next->fCoinEnd) != this) {
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (next->segment() == segment) {
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpContour* SkOpSpanBase::contour() const {
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return segment()->contour();
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpGlobalState* SkOpSpanBase::globalState() const {
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return contour()->globalState();
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSegment = segment;
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPtT.init(this, t, pt, false);
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCoinEnd = this;
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFromAngle = nullptr;
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPrev = prev;
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSpanAdds = 0;
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fAligned = true;
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fChased = false;
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fCount = 1);
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fID = globalState()->nextSpanID());
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fDebugDeleted = false);
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// this pair of spans share a common t value or point; merge them and eliminate duplicates
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// this does not compute the best t or pt value; this merely moves all data into a single list
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::merge(SkOpSpan* span) {
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* spanPtT = span->ptT();
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->t() != spanPtT->fT);
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!zero_or_one(spanPtT->fT));
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    span->release(this->ptT());
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->contains(span)) {
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOPASSERT(0);  // check to see if this ever happens -- should have been found earlier
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;  // merge is already in the ptT loop
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* remainder = spanPtT->next();
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->ptT()->insert(spanPtT);
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (remainder != spanPtT) {
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpPtT* next = remainder->next();
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpPtT* compare = spanPtT->next();
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (compare != spanPtT) {
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpPtT* nextC = compare->next();
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) {
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                goto tryNextRemainder;
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            compare = nextC;
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        spanPtT->insert(remainder);
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobottryNextRemainder:
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        remainder = next;
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSpanAdds += span->fSpanAdds;
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpSpanBase* SkOpSpanBase::active() {
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* result = fPrev ? fPrev->next() : upCast()->next()->prev();
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this == result || fDebugDeleted);
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// please keep in sync with debugCheckForCollapsedCoincidence()
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::checkForCollapsedCoincidence() {
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpCoincidence* coins = this->globalState()->coincidence();
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (coins->isEmpty()) {
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// the insert above may have put both ends of a coincident run in the same span
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// for each coincident ptT in loop; see if its opposite in is also in the loop
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// this implementation is the motivation for marking that a ptT is referenced by a coincident span
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* head = this->ptT();
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* test = head;
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!test->coincident()) {
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coins->markCollapsed(test);
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((test = test->next()) != head);
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coins->releaseDeleted();
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// please keep in sync with debugMergeMatches()
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Look to see if pt-t linked list contains same segment more than once
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// if so, and if each pt-t is directly pointed to by spans in that segment,
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// merge them
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// keep the points, but remove spans so that the segment doesn't have 2 or more
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// spans pointing to the same pt-t loop at different loop elements
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) {
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* test = &fPtT;
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* testNext;
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stop = test;
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        testNext = test->next();
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (test->deleted()) {
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSpanBase* testBase = test->span();
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(testBase->ptT() == test);
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSegment* segment = test->segment();
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (segment->done()) {
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpPtT* inner = opp->ptT();
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* innerStop = inner;
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (inner->segment() != segment) {
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (inner->deleted()) {
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSpanBase* innerBase = inner->span();
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(innerBase->ptT() == inner);
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // when the intersection is first detected, the span base is marked if there are
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // more than one point in the intersection.
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!zero_or_one(inner->fT)) {
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                innerBase->upCast()->release(test);
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkOPASSERT(inner->fT != test->fT);
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!zero_or_one(test->fT)) {
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    testBase->upCast()->release(inner);
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    segment->markAllDone();  // mark segment as collapsed
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkDEBUGCODE(testBase->debugSetDeleted());
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    test->setDeleted();
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkDEBUGCODE(innerBase->debugSetDeleted());
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    inner->setDeleted();
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG   // assert if another undeleted entry points to segment
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* debugInner = inner;
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while ((debugInner = debugInner->next()) != innerStop) {
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (debugInner->segment() != segment) {
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (debugInner->deleted()) {
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkOPASSERT(0);
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while ((inner = inner->next()) != innerStop);
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((test = testNext) != stop);
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->checkForCollapsedCoincidence();
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkOpSpan::computeWindSum() {
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpGlobalState* globals = this->globalState();
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpContour* contourHead = globals->contourHead();
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int windTry = 0;
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ;
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return this->windSum();
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->segment() != segment);
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* next = fCoincident;
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (next->segment() == segment) {
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((next = next->fCoincident) != this);
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return false;
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) {
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(t != 1);
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    initBase(segment, prev, t, pt);
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCoincident = this;
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fToAngle = nullptr;
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWindSum = fOppSum = SK_MinS32;
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWindValue = 1;
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fOppValue = 0;
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTopTTry = 0;
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fChased = fDone = false;
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    segment->bumpCount();
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fAlreadyAdded = false;
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Please keep this in sync with debugInsertCoincidence()
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped, bool ordered) {
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->containsCoincidence(segment)) {
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* next = &fPtT;
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((next = next->next()) != &fPtT) {
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (next->segment() == segment) {
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSpan* span;
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSpanBase* base = next->span();
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!ordered) {
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* spanEndPtT = fNext->contains(segment);
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!spanEndPtT);
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpSpanBase* spanEnd = spanEndPtT->span();
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT());
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!start->span()->upCastable());
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                span = const_cast<SkOpSpan*>(start->span()->upCast());
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (flipped) {
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                span = base->prev();
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!span);
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!base->upCastable());
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                span = base->upCast();
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->insertCoincidence(span);
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment...
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpan::release(const SkOpPtT* kept) {
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fDebugDeleted = true);
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOPASSERT(kept->span() != this);
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!final());
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* prev = this->prev();
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(prev);
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* next = this->next();
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(next);
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    prev->setNext(next);
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    next->setPrev(prev);
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->segment()->release(this);
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpCoincidence* coincidence = this->globalState()->coincidence();
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (coincidence) {
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coincidence->fixUp(this->ptT(), kept);
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->ptT()->setDeleted();
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* stopPtT = this->ptT();
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* testPtT = stopPtT;
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* keptSpan = kept->span();
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (this == testPtT->span()) {
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            testPtT->setSpan(keptSpan);
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((testPtT = testPtT->next()) != stopPtT);
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpan::setOppSum(int oppSum) {
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!final());
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fOppSum != SK_MinS32 && fOppSum != oppSum) {
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->globalState()->setWindingFailed();
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fOppSum = oppSum;
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpan::setWindSum(int windSum) {
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!final());
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fWindSum != SK_MinS32 && fWindSum != windSum) {
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->globalState()->setWindingFailed();
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM);
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWindSum = windSum;
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
478