1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2012 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#ifndef SkOpSpan_DEFINED
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define SkOpSpan_DEFINED
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathOpsDebug.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathOpsTypes.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPoint.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkArenaAlloc;
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpAngle;
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpContour;
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpGlobalState;
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpSegment;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpSpanBase;
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpSpan;
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkPathOpsBounds;
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// subset of op span used by terminal span (when t is equal to one)
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpPtT {
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    enum {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kIsAlias = 1,
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kIsDuplicate = 1
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* active() const;
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // please keep in sync with debugAddOpp()
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void addOpp(SkOpPtT* opp, SkOpPtT* oppPrev) {
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpPtT* oldNext = this->fNext;
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this != opp);
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->fNext = opp;
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(oppPrev != oldNext);
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        oppPrev->fNext = oldNext;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool alias() const;
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool coincident() const { return fCoincident; }
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool contains(const SkOpPtT* ) const;
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool contains(const SkOpSegment*, const SkPoint& ) const;
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool contains(const SkOpSegment*, double t) const;
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* contains(const SkOpSegment* ) const;
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpContour* contour() const;
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int debugID() const {
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SkDEBUGRELEASE(fID, -1);
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugAddOpp(const SkOpPtT* opp, const SkOpPtT* oppPrev) const;
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* debugAngle(int id) const;
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpCoincidence* debugCoincidence() const;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool debugContains(const SkOpPtT* ) const;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* debugContains(const SkOpSegment* check) const;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpContour* debugContour(int id) const;
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* debugEnder(const SkOpPtT* end) const;
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int debugLoopLimit(bool report) const;
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool debugMatchID(int id) const;
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* debugOppPrev(const SkOpPtT* opp) const;
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* debugPtT(int id) const;
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugResetCoinT() const;
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* debugSegment(int id) const;
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugSetCoinT(int ) const;
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* debugSpan(int id) const;
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugValidate() const;
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool deleted() const {
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fDeleted;
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool duplicate() const {
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fDuplicatePt;
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dump() const;  // available to testing only
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpAll() const;
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpBase() const;
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* find(const SkOpSegment* ) const;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpGlobalState* globalState() const;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void init(SkOpSpanBase* , double t, const SkPoint& , bool dup);
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void insert(SkOpPtT* span) {
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(span != this);
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        span->fNext = fNext;
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fNext = span;
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* next() const {
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fNext;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* next() {
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fNext;
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool onEnd() const;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // returns nullptr if this is already in the opp ptT loop
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* oppPrev(const SkOpPtT* opp) const {
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // find the fOpp ptr to opp
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpPtT* oppPrev = opp->fNext;
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (oppPrev == this) {
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return nullptr;
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (oppPrev->fNext != opp) {
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            oppPrev = oppPrev->fNext;
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppPrev == this) {
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return nullptr;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return oppPrev;
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static bool Overlaps(const SkOpPtT* s1, const SkOpPtT* e1, const SkOpPtT* s2,
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* e2, const SkOpPtT** sOut, const SkOpPtT** eOut) {
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* start1 = s1->fT < e1->fT ? s1 : e1;
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* start2 = s2->fT < e2->fT ? s2 : e2;
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *sOut = between(s1->fT, start2->fT, e1->fT) ? start2
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                : between(s2->fT, start1->fT, e2->fT) ? start1 : nullptr;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* end1 = s1->fT < e1->fT ? e1 : s1;
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* end2 = s2->fT < e2->fT ? e2 : s2;
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *eOut = between(s1->fT, end2->fT, e1->fT) ? end2
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                : between(s2->fT, end1->fT, e2->fT) ? end1 : nullptr;
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (*sOut == *eOut) {
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(start1->fT >= end2->fT || start2->fT >= end1->fT);
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!*sOut || *sOut != *eOut);
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return *sOut && *eOut;
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool ptAlreadySeen(const SkOpPtT* head) const;
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* prev();
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment() const;
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSegment* segment();
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setCoincident() const {
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOPASSERT(!fDeleted);
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincident = true;
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setDeleted();
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setSpan(const SkOpSpanBase* span) {
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fSpan = const_cast<SkOpSpanBase*>(span);
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* span() const {
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fSpan;
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* span() {
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fSpan;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* starter(const SkOpPtT* end) const {
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fT < end->fT ? this : end;
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double fT;
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint fPt;   // cache of point value at this t
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* fSpan;  // contains winding data
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* fNext;  // intersection on opposite curve or alias on this curve
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool fDeleted;  // set if removed from span list
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool fDuplicatePt;  // set if identical pt is somewhere in the next loop
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // below mutable since referrer is otherwise always const
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    mutable bool fCoincident;  // set if at some point a coincident span pointed here
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(int fID);
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpSpanBase {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* active();
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void addOpp(SkOpSpanBase* opp);
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void bumpSpanAdds() {
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++fSpanAdds;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool chased() const {
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fChased;
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void checkForCollapsedCoincidence();
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* coinEnd() const {
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fCoinEnd;
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool collapsed(double s, double e) const;
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool contains(const SkOpSpanBase* ) const;
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* contains(const SkOpSegment* ) const;
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool containsCoinEnd(const SkOpSpanBase* coin) const {
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this != coin);
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* next = this;
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((next = next->fCoinEnd) != this) {
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (next == coin) {
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return true;
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool containsCoinEnd(const SkOpSegment* ) const;
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpContour* contour() const;
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int debugBumpCount() {
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SkDEBUGRELEASE(++fCount, -1);
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int debugID() const {
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SkDEBUGRELEASE(fID, -1);
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugAddOpp(SkPathOpsDebug::GlitchLog* , const SkOpSpanBase* opp) const;
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool debugAlignedEnd(double t, const SkPoint& pt) const;
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool debugAlignedInner() const;
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* debugAngle(int id) const;
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog* ) const;
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpCoincidence* debugCoincidence() const;
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool debugCoinEndLoopCheck() const;
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpContour* debugContour(int id) const;
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool debugDeleted() const { return fDebugDeleted; }
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugInsertCoinEnd(SkPathOpsDebug::GlitchLog* ,
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            const SkOpSpanBase* ) const;
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugMergeMatches(SkPathOpsDebug::GlitchLog* log,
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                           const SkOpSpanBase* opp) const;
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* debugPtT(int id) const;
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugResetCoinT() const;
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* debugSegment(int id) const;
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugSetCoinT(int ) const;
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugSetDeleted() { fDebugDeleted = true; }
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* debugSpan(int id) const;
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* debugStarter(SkOpSpanBase const** endPtr) const;
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpGlobalState* globalState() const;
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugValidate() const;
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool deleted() const {
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fPtT.deleted();
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dump() const;  // available to testing only
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpCoin() const;
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpAll() const;
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpBase() const;
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpHead() const;
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool final() const {
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fPtT.fT == 1;
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpAngle* fromAngle() const {
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fFromAngle;
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void initBase(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt);
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Please keep this in sync with debugInsertCoinEnd()
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void insertCoinEnd(SkOpSpanBase* coin) {
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (containsCoinEnd(coin)) {
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(coin->containsCoinEnd(this));
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        debugValidate();
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this != coin);
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSpanBase* coinNext = coin->fCoinEnd;
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coin->fCoinEnd = this->fCoinEnd;
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->fCoinEnd = coinNext;
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        debugValidate();
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void merge(SkOpSpan* span);
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void mergeMatches(SkOpSpanBase* opp);
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* prev() const {
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fPrev;
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* prev() {
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fPrev;
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPoint& pt() const {
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fPtT.fPt;
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT() const {
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return &fPtT;
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* ptT() {
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return &fPtT;
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSegment* segment() const {
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fSegment;
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setAligned() {
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fAligned = true;
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setChased(bool chased) {
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fChased = chased;
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setFromAngle(SkOpAngle* angle) {
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFromAngle = angle;
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setPrev(SkOpSpan* prev) {
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPrev = prev;
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool simple() const {
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPtT.debugValidate();
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fPtT.next()->next() == &fPtT;
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int spanAddsCount() const {
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fSpanAdds;
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* starter(const SkOpSpanBase* end) const {
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* result = t() < end->t() ? this : end;
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return result->upCast();
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* starter(SkOpSpanBase* end) {
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this->segment() == end->segment());
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSpanBase* result = t() < end->t() ? this : end;
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return result->upCast();
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* starter(SkOpSpanBase** endPtr) {
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSpanBase* end = *endPtr;
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this->segment() == end->segment());
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSpanBase* result;
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (t() < end->t()) {
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result = this;
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result = end;
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            *endPtr = this;
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return result->upCast();
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int step(const SkOpSpanBase* end) const {
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return t() < end->t() ? 1 : -1;
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double t() const {
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fPtT.fT;
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void unaligned() {
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fAligned = false;
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* upCast() {
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (SkOpSpan*) this;
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* upCast() const {
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOPASSERT(!final());
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return (const SkOpSpan*) this;
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* upCastable() {
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return final() ? nullptr : upCast();
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* upCastable() const {
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return final() ? nullptr : upCast();
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void alignInner();
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:  // no direct access to internals to avoid treating a span base as a span
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT fPtT;  // list of points and t values associated with the start of this span
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSegment* fSegment;  // segment that contains this span
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* fCoinEnd;  // linked list of coincident spans that end here (may point to itself)
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpAngle* fFromAngle;  // points to next angle from span start to end
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* fPrev;  // previous intersection point
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fSpanAdds;  // number of times intersections have been added to span
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool fAligned;
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool fChased;  // set after span has been added to chase array
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(int fCount);  // number of pt/t pairs added
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(int fID);
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(bool fDebugDeleted);  // set when span was merged with another span
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkOpSpan : public SkOpSpanBase {
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool alreadyAdded() const {
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fAlreadyAdded) {
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fAlreadyAdded = true;
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool clearCoincident() {
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fCoincident == this) {
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincident = this;
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int computeWindSum();
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool containsCoincidence(const SkOpSegment* ) const;
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool containsCoincidence(const SkOpSpan* coin) const {
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this != coin);
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpan* next = this;
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((next = next->fCoincident) != this) {
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (next == coin) {
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return true;
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool debugCoinLoopCheck() const;
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* , const SkOpSpan* ) const;
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* ,
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                const SkOpSegment* , bool flipped, bool ordered) const;
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpCoin() const;
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool dumpSpan() const;
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool done() const {
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fDone;
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void init(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt);
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool insertCoincidence(const SkOpSegment* , bool flipped, bool ordered);
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Please keep this in sync with debugInsertCoincidence()
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void insertCoincidence(SkOpSpan* coin) {
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (containsCoincidence(coin)) {
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(coin->containsCoincidence(this));
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        debugValidate();
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this != coin);
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSpan* coinNext = coin->fCoincident;
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coin->fCoincident = this->fCoincident;
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->fCoincident = coinNext;
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        debugValidate();
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isCanceled() const {
478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fWindValue == 0 && fOppValue == 0;
480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isCoincident() const {
483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fCoincident != this;
485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* next() const {
488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fNext;
490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int oppSum() const {
493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fOppSum;
495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int oppValue() const {
498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fOppValue;
500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void release(const SkOpPtT* );
503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPtT* setCoinStart(SkOpSpan* oldCoinStart, SkOpSegment* oppSegment);
505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setDone(bool done) {
507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDone = done;
509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setNext(SkOpSpanBase* nextT) {
512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fNext = nextT;
514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setOppSum(int oppSum);
517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setOppValue(int oppValue) {
519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fOppSum == SK_MinS32);
521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOPASSERT(!oppValue || !fDone);
522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fOppValue = oppValue;
523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setToAngle(SkOpAngle* angle) {
526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fToAngle = angle;
528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setWindSum(int windSum);
531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void setWindValue(int windValue) {
533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(windValue >= 0);
535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fWindSum == SK_MinS32);
536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOPASSERT(!windValue || !fDone);
537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fWindValue = windValue;
538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool sortableTop(SkOpContour* );
541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpAngle* toAngle() const {
543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fToAngle;
545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int windSum() const {
548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!final());
549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fWindSum;
550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int windValue() const {
553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOPASSERT(!final());
554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return fWindValue;
555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:  // no direct access to internals to avoid treating a span base as a span
558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* fCoincident;  // linked list of spans coincident with this one (may point to itself)
559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpAngle* fToAngle;  // points to next angle from span start to end
560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* fNext;  // next intersection point
561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fWindSum;  // accumulated from contours surrounding this one.
562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fOppSum;  // for binary operators: the opposite winding sum
563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fWindValue;  // 0 == canceled; 1 == normal; >1 == coincident
564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fOppValue;  // normally 0 -- when binary coincident edges combine, opp value goes here
565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int fTopTTry; // specifies direction and t value to try next
566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool fDone;  // if set, this span to next higher T has been processed
567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    mutable bool fAlreadyAdded;
568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
571