1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2013 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
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMutex.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpCoincidence.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpContour.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOSFile.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPath.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathOpsDebug.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkString.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_DUMP_VERIFY
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkPathOpsDebug::gDumpOp;  // set to true to write op to file before a crash
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkPathOpsDebug::gVerifyOp;  // set to true to compare result against regions
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkPathOpsDebug::gRunFail;  // set to true to check for success on tests known to fail
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkPathOpsDebug::gVeryVerbose;  // set to true to run extensive checking tests
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#undef FAIL_IF
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define FAIL_IF(cond, coin) \
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, coin); } while (false)
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#undef FAIL_WITH_NULL_IF
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define FAIL_WITH_NULL_IF(cond, span) \
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, span); } while (false)
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#undef RETURN_FALSE_IF
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define RETURN_FALSE_IF(cond, span) \
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         do { if (cond) log->record(SkPathOpsDebug::kReturnFalse_Glitch, span); \
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         } while (false)
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass SkCoincidentSpans;
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_SORT
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkPathOpsDebug::gSortCount;
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_ACTIVE_OP
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor", "rdiff"};
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined SK_DEBUG || !FORCE_RELEASE
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"};
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkPathOpsDebug::gContourID = 0;
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkPathOpsDebug::gSegmentID = 0;
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray,
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* span) {
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < chaseArray.count(); ++index) {
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* entry = chaseArray[index];
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (entry == span) {
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#endif
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_ACTIVE_SPANS
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkString SkPathOpsDebug::gActiveSpans;
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumChangedDict;
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumVisitedDict;
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const int kGlitchType_Count = SkPathOpsDebug::kUnalignedTail_Glitch + 1;
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SpanGlitch {
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* fBase;
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* fSuspect;
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* fSegment;
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* fOppSegment;
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* fCoinSpan;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* fEndSpan;
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* fOppSpan;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* fOppEndSpan;
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double fStartT;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double fEndT;
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double fOppStartT;
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double fOppEndT;
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint fPt;
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPathOpsDebug::GlitchType fType;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void dumpType() const;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkPathOpsDebug::GlitchLog {
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void init(const SkOpGlobalState* state) {
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fGlobalState = state;
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SpanGlitch* recordCommon(GlitchType type) {
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = fGlitches.push();
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = nullptr;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fSuspect = nullptr;
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fSegment = nullptr;
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppSegment = nullptr;
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fCoinSpan = nullptr;
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndSpan = nullptr;
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppSpan = nullptr;
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppEndSpan = nullptr;
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fStartT = SK_ScalarNaN;
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndT = SK_ScalarNaN;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppStartT = SK_ScalarNaN;
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppEndT = SK_ScalarNaN;
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fPt = { SK_ScalarNaN, SK_ScalarNaN };
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fType = type;
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return glitch;
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpSpanBase* base,
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* suspect = NULL) {
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = base;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fSuspect = suspect;
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpSpanBase* base,
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* ptT) {
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = base;
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fCoinSpan = ptT;
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkCoincidentSpans* coin,
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkCoincidentSpans* opp = NULL) {
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fCoinSpan = coin->coinPtTStart();
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndSpan = coin->coinPtTEnd();
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (opp) {
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            glitch->fOppSpan = opp->coinPtTStart();
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            glitch->fOppEndSpan = opp->coinPtTEnd();
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpSpanBase* base,
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSegment* seg, double t, SkPoint pt) {
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = base;
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fSegment = seg;
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fStartT = t;
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fPt = pt;
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpSpanBase* base, double t,
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkPoint pt) {
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = base;
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fStartT = t;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fPt = pt;
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkCoincidentSpans* coin,
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* coinSpan, const SkOpPtT* endSpan) {
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fCoinSpan = coin->coinPtTStart();
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndSpan = coin->coinPtTEnd();
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndSpan = endSpan;
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppSpan = coinSpan;
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppEndSpan = endSpan;
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkCoincidentSpans* coin,
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* base) {
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = base;
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fCoinSpan = coin->coinPtTStart();
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndSpan = coin->coinPtTEnd();
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpPtT* ptTS, const SkOpPtT* ptTE,
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* oPtTS, const SkOpPtT* oPtTE) {
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fCoinSpan = ptTS;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndSpan = ptTE;
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppSpan = oPtTS;
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppEndSpan = oPtTE;
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpSegment* seg, double startT,
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double endT, const SkOpSegment* oppSeg, double oppStartT, double oppEndT) {
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fSegment = seg;
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fStartT = startT;
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndT = endT;
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppSegment = oppSeg;
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppStartT = oppStartT;
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fOppEndT = oppEndT;
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpSegment* seg,
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpan* span) {
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fSegment = seg;
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = span;
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, double t, const SkOpSpanBase* span) {
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fStartT = t;
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fBase = span;
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkOpSegment* seg) {
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fSegment = seg;
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void record(GlitchType type, const SkCoincidentSpans* coin,
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* ptT) {
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SpanGlitch* glitch = recordCommon(type);
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fCoinSpan = coin->coinPtTStart();
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        glitch->fEndSpan = ptT;
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTDArray<SpanGlitch> fGlitches;
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpGlobalState* fGlobalState;
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::CoinDict::add(const SkPathOpsDebug::CoinDict& dict) {
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count = dict.fDict.count();
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < count; ++index) {
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->add(dict.fDict[index]);
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::CoinDict::add(const CoinDictEntry& key) {
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count = fDict.count();
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < count; ++index) {
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        CoinDictEntry* entry = &fDict[index];
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (entry->fIteration == key.fIteration && entry->fLineNumber == key.fLineNumber) {
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(!strcmp(entry->fFunctionName, key.fFunctionName));
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (entry->fGlitchType == kUninitialized_Glitch) {
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                entry->fGlitchType = key.fGlitchType;
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *fDict.append() = key;
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void missing_coincidence(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) {
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpContour* contour = contourList;
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // bool result = false;
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /* result |= */ contour->debugMissingCoincidence(glitches);
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((contour = contour->next()));
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void move_multiples(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) {
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpContour* contour = contourList;
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (contour->debugMoveMultiples(glitches), false) {
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((contour = contour->next()));
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void move_nearby(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) {
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpContour* contour = contourList;
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        contour->debugMoveNearby(glitches);
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((contour = contour->next()));
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpGlobalState::debugAddToCoinChangedDict() {
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPathOpsDebug::CheckHealth(fContourHead);
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // see if next coincident operation makes a change; if so, record it
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPathOpsDebug::GlitchLog glitches;
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* funcName = fCoinDictEntry.fFunctionName;
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!strcmp("calc_angles", funcName)) {
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ;
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("missing_coincidence", funcName)) {
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        missing_coincidence(&glitches, fContourHead);
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("move_multiples", funcName)) {
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        move_multiples(&glitches, fContourHead);
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("move_nearby", funcName)) {
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        move_nearby(&glitches, fContourHead);
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("addExpanded", funcName)) {
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincidence->debugAddExpanded(&glitches);
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("addMissing", funcName)) {
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool added;
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincidence->debugAddMissing(&glitches, &added);
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("addEndMovedSpans", funcName)) {
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincidence->debugAddEndMovedSpans(&glitches);
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("correctEnds", funcName)) {
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincidence->debugCorrectEnds(&glitches);
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("expand", funcName)) {
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincidence->debugExpand(&glitches);
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("findOverlaps", funcName)) {
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ;
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("mark", funcName)) {
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoincidence->debugMark(&glitches);
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (!strcmp("apply", funcName)) {
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ;
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(0);   // add missing case
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (glitches.fGlitches.count()) {
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCoinDictEntry.fGlitchType = glitches.fGlitches[0].fType;
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCoinChangedDict.add(fCoinDictEntry);
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::ShowActiveSpans(SkOpContourHead* contourList) {
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_ACTIVE_SPANS
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkString str;
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpContour* contour = contourList;
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        contour->debugShowActiveSpans(&str);
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((contour = contour->next()));
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!gActiveSpans.equals(str)) {
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* s = str.c_str();
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* end;
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((end = strchr(s, '\n'))) {
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%.*s", end - s + 1, s);
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            s = end + 1;
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gActiveSpans.set(str);
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE || DEBUG_COIN
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList) {
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    contourList->globalState()->debugSetCheckHealth(true);
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    GlitchLog glitches;
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpContour* contour = contourList;
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpCoincidence* coincidence = contour->globalState()->coincidence();
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coincidence->debugCheckValid(&glitches); // don't call validate; spans may be inconsistent
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        contour->debugCheckHealth(&glitches);
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        contour->debugMissingCoincidence(&glitches);
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((contour = contour->next()));
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool added;
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coincidence->debugAddMissing(&glitches, &added);
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coincidence->debugExpand(&glitches);
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coincidence->debugAddExpanded(&glitches);
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coincidence->debugMark(&glitches);
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    unsigned mask = 0;
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < glitches.fGlitches.count(); ++index) {
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SpanGlitch& glitch = glitches.fGlitches[index];
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        mask |= 1 << glitch.fType;
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < kGlitchType_Count; ++index) {
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf(mask & (1 << index) ? "x" : "-");
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" %s\n", contourList->globalState()->debugCoinDictEntry().fFunctionName);
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < glitches.fGlitches.count(); ++index) {
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SpanGlitch& glitch = glitches.fGlitches[index];
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%02d: ", index);
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fBase) {
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" seg/base=%d/%d", glitch.fBase->segment()->debugID(),
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitch.fBase->debugID());
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fSuspect) {
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" seg/base=%d/%d", glitch.fSuspect->segment()->debugID(),
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitch.fSuspect->debugID());
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fSegment) {
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" segment=%d", glitch.fSegment->debugID());
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fCoinSpan) {
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" coinSeg/Span/PtT=%d/%d/%d", glitch.fCoinSpan->segment()->debugID(),
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitch.fCoinSpan->span()->debugID(), glitch.fCoinSpan->debugID());
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fEndSpan) {
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" endSpan=%d", glitch.fEndSpan->debugID());
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fOppSpan) {
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" oppSeg/Span/PtT=%d/%d/%d", glitch.fOppSpan->segment()->debugID(),
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitch.fOppSpan->span()->debugID(), glitch.fOppSpan->debugID());
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fOppEndSpan) {
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" oppEndSpan=%d", glitch.fOppEndSpan->debugID());
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!SkScalarIsNaN(glitch.fStartT)) {
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" startT=%g", glitch.fStartT);
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!SkScalarIsNaN(glitch.fEndT)) {
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" endT=%g", glitch.fEndT);
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (glitch.fOppSegment) {
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" segment=%d", glitch.fOppSegment->debugID());
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!SkScalarIsNaN(glitch.fOppStartT)) {
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" oppStartT=%g", glitch.fOppStartT);
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!SkScalarIsNaN(glitch.fOppEndT)) {
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" oppEndT=%g", glitch.fOppEndT);
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!SkScalarIsNaN(glitch.fPt.fX) || !SkScalarIsNaN(glitch.fPt.fY)) {
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(" pt=%g,%g", glitch.fPt.fX, glitch.fPt.fY);
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        DumpGlitchType(glitch.fType);
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("\n");
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    contourList->globalState()->debugSetCheckHealth(false);
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if 01 && DEBUG_ACTIVE_SPANS
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    SkDebugf("active after %s:\n", id);
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ShowActiveSpans(contourList);
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::DumpGlitchType(GlitchType glitchType) {
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (glitchType) {
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddCorruptCoin_Glitch: SkDebugf(" AddCorruptCoin"); break;
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddExpandedCoin_Glitch: SkDebugf(" AddExpandedCoin"); break;
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddExpandedFail_Glitch: SkDebugf(" AddExpandedFail"); break;
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddIfCollapsed_Glitch: SkDebugf(" AddIfCollapsed"); break;; break;
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddIfMissingCoin_Glitch: SkDebugf(" AddIfMissingCoin"); break;
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddMissingCoin_Glitch: SkDebugf(" AddMissingCoin"); break;
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddMissingExtend_Glitch: SkDebugf(" AddMissingExtend"); break;
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kAddOrOverlap_Glitch: SkDebugf(" AAddOrOverlap"); break;
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kCollapsedCoin_Glitch: SkDebugf(" CollapsedCoin"); break;
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kCollapsedDone_Glitch: SkDebugf(" CollapsedDone"); break;
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kCollapsedOppValue_Glitch: SkDebugf(" CollapsedOppValue"); break;
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kCollapsedSpan_Glitch: SkDebugf(" CollapsedSpan"); break;
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kCollapsedWindValue_Glitch: SkDebugf(" CollapsedWindValue"); break;
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kCorrectEnd_Glitch: SkDebugf(" CorrectEnd"); break;
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kDeletedCoin_Glitch: SkDebugf(" DeletedCoin"); break;
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kExpandCoin_Glitch: SkDebugf(" ExpandCoin"); break;
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kFail_Glitch: SkDebugf(" Fail"); break;
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMarkCoinEnd_Glitch: SkDebugf(" MarkCoinEnd"); break;
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMarkCoinInsert_Glitch: SkDebugf(" MarkCoinInsert"); break;
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMarkCoinMissing_Glitch: SkDebugf(" MarkCoinMissing"); break;
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMarkCoinStart_Glitch: SkDebugf(" MarkCoinStart"); break;
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMergeMatches_Glitch: SkDebugf(" MergeMatches"); break;
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMissingCoin_Glitch: SkDebugf(" MissingCoin"); break;
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMissingDone_Glitch: SkDebugf(" MissingDone"); break;
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMissingIntersection_Glitch: SkDebugf(" MissingIntersection"); break;
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMoveMultiple_Glitch: SkDebugf(" MoveMultiple"); break;
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMoveNearbyClearAll_Glitch: SkDebugf(" MoveNearbyClearAll"); break;
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMoveNearbyClearAll2_Glitch: SkDebugf(" MoveNearbyClearAll2"); break;
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMoveNearbyMerge_Glitch: SkDebugf(" MoveNearbyMerge"); break;
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMoveNearbyMergeFinal_Glitch: SkDebugf(" MoveNearbyMergeFinal"); break;
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMoveNearbyRelease_Glitch: SkDebugf(" MoveNearbyRelease"); break;
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kMoveNearbyReleaseFinal_Glitch: SkDebugf(" MoveNearbyReleaseFinal"); break;
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kReleasedSpan_Glitch: SkDebugf(" ReleasedSpan"); break;
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kReturnFalse_Glitch: SkDebugf(" ReturnFalse"); break;
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kUnaligned_Glitch: SkDebugf(" Unaligned"); break;
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kUnalignedHead_Glitch: SkDebugf(" UnalignedHead"); break;
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kUnalignedTail_Glitch: SkDebugf(" UnalignedTail"); break;
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case kUninitialized_Glitch: break;
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default: SkASSERT(0);
478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined SK_DEBUG || !FORCE_RELEASE
483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) {
484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t len = strlen(str);
485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool num = false;
486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (size_t idx = 0; idx < len; ++idx) {
487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (num && str[idx] == 'e') {
488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (len + 2 >= bufferLen) {
489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return;
490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            memmove(&str[idx + 2], &str[idx + 1], len - idx);
492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str[idx] = '*';
493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str[idx + 1] = '^';
494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++len;
495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        num = str[idx] >= '0' && str[idx] <= '9';
497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkPathOpsDebug::ValidWind(int wind) {
501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF;
502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::WindingPrintf(int wind) {
505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (wind == SK_MinS32) {
506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("?");
507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", wind);
509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif //  defined SK_DEBUG || !FORCE_RELEASE
512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_SHOW_TEST_NAME
515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid* SkPathOpsDebug::CreateNameStr() { return new char[DEBUG_FILENAME_STRING_LENGTH]; }
516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::DeleteNameStr(void* v) { delete[] reinterpret_cast<char*>(v); }
518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::BumpTestName(char* test) {
520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    char* num = test + strlen(test);
521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (num[-1] >= '0' && num[-1] <= '9') {
522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        --num;
523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (num[0] == '\0') {
525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int dec = atoi(num);
528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (dec == 0) {
529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ++dec;
532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SK_SNPRINTF(num, DEBUG_FILENAME_STRING_LENGTH - (num - test), "%d", dec);
533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void show_function_header(const char* functionName) {
537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName);
538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (strcmp("skphealth_com76", functionName) == 0) {
539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("found it\n");
540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const char* gOpStrs[] = {
544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kDifference_SkPathOp",
545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kIntersect_SkPathOp",
546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kUnion_SkPathOp",
547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kXOR_PathOp",
548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kReverseDifference_SkPathOp",
549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst char* SkPathOpsDebug::OpStr(SkPathOp op) {
552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return gOpStrs[op];
553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) {
556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("    testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]);
557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("}\n");
558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSK_DECLARE_STATIC_MUTEX(gTestMutex);
561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp,
563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* testName) {
564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkAutoMutexAcquire ac(gTestMutex);
565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    show_function_header(testName);
566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ShowOnePath(a, "path", true);
567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ShowOnePath(b, "pathB", true);
568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    show_op(shapeOp, "path", "pathB");
569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathOpsTypes.h"
572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkIntersectionHelper.h"
573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkIntersections.h"
574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSK_DECLARE_STATIC_MUTEX(gCoinDictMutex);
578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpGlobalState::debugAddToGlobalCoinDicts() {
580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkAutoMutexAcquire ac(&gCoinDictMutex);
581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPathOpsDebug::gCoinSumChangedDict.add(fCoinChangedDict);
582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPathOpsDebug::gCoinSumVisitedDict.add(fCoinVisitedDict);
583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_T_SECT_LOOP_COUNT
588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpGlobalState::debugAddLoopCount(SkIntersections* i, const SkIntersectionHelper& wt,
589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkIntersectionHelper& wn) {
590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) {
591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkIntersections::DebugLoop looper = (SkIntersections::DebugLoop) index;
592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fDebugLoopCount[index] >= i->debugLoopCount(looper)) {
593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugLoopCount[index] = i->debugLoopCount(looper);
596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstVerb[index * 2] = wt.segment()->verb();
597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstVerb[index * 2 + 1] = wn.segment()->verb();
598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sk_bzero(&fDebugWorstPts[index * 8], sizeof(SkPoint) * 8);
599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        memcpy(&fDebugWorstPts[index * 2 * 4], wt.pts(),
600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                (SkPathOpsVerbToPoints(wt.segment()->verb()) + 1) * sizeof(SkPoint));
601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        memcpy(&fDebugWorstPts[(index * 2 + 1) * 4], wn.pts(),
602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                (SkPathOpsVerbToPoints(wn.segment()->verb()) + 1) * sizeof(SkPoint));
603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstWeight[index * 2] = wt.weight();
604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstWeight[index * 2 + 1] = wn.weight();
605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    i->debugResetLoopCount();
607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpGlobalState::debugDoYourWorst(SkOpGlobalState* local) {
610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) {
611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fDebugLoopCount[index] >= local->fDebugLoopCount[index]) {
612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugLoopCount[index] = local->fDebugLoopCount[index];
615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstVerb[index * 2] = local->fDebugWorstVerb[index * 2];
616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstVerb[index * 2 + 1] = local->fDebugWorstVerb[index * 2 + 1];
617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        memcpy(&fDebugWorstPts[index * 2 * 4], &local->fDebugWorstPts[index * 2 * 4],
618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                sizeof(SkPoint) * 8);
619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstWeight[index * 2] = local->fDebugWorstWeight[index * 2];
620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugWorstWeight[index * 2 + 1] = local->fDebugWorstWeight[index * 2 + 1];
621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    local->debugResetLoopCounts();
623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void dump_curve(SkPath::Verb verb, const SkPoint& pts, float weight) {
626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!verb) {
627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* verbs[] = { "", "line", "quad", "conic", "cubic" };
630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("%s: {{", verbs[verb]);
631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int ptCount = SkPathOpsVerbToPoints(verb);
632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index <= ptCount; ++index) {
633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDPoint::Dump((&pts)[index]);
634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (index < ptCount - 1) {
635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(", ");
636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("}");
639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (weight != 1) {
640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf(", ");
641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (weight == floorf(weight)) {
642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%.0f", weight);
643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%1.9gf", weight);
645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("}\n");
648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpGlobalState::debugLoopReport() {
651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* loops[] = { "iterations", "coinChecks", "perpCalcs" };
652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("\n");
653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) {
654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%s: %d\n", loops[index], fDebugLoopCount[index]);
655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dump_curve(fDebugWorstVerb[index * 2], fDebugWorstPts[index * 2 * 4],
656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fDebugWorstWeight[index * 2]);
657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dump_curve(fDebugWorstVerb[index * 2 + 1], fDebugWorstPts[(index * 2 + 1) * 4],
658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fDebugWorstWeight[index * 2 + 1]);
659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpGlobalState::debugResetLoopCounts() {
663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount));
664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_bzero(fDebugWorstVerb, sizeof(fDebugWorstVerb));
665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_bzero(fDebugWorstPts, sizeof(fDebugWorstPts));
666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_bzero(fDebugWorstWeight, sizeof(fDebugWorstWeight));
667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpGlobalState::DebugRunFail() {
671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return SkPathOpsDebug::gRunFail;
672fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
673fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
674fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// this is const so it can be called by const methods that overwise don't alter state
675fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_VALIDATE || DEBUG_COIN
676fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpGlobalState::debugSetPhase(const char* funcName  DEBUG_COIN_DECLARE_PARAMS()) const {
677fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    auto writable = const_cast<SkOpGlobalState*>(this);
678fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_VALIDATE
679fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    writable->setPhase(phase);
680fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
681fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
682fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPathOpsDebug::CoinDictEntry* entry = &writable->fCoinDictEntry;
683fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    writable->fPreviousFuncName = entry->fFunctionName;
684fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    entry->fIteration = iteration;
685fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    entry->fLineNumber = lineNo;
686fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    entry->fGlitchType = SkPathOpsDebug::kUninitialized_Glitch;
687fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    entry->fFunctionName = funcName;
688fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    writable->fCoinVisitedDict.add(*entry);
689fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    writable->debugAddToCoinChangedDict();
690fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
691fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
692fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
693fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
694fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_T_SECT_LOOP_COUNT
695fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkIntersections::debugBumpLoopCount(DebugLoop index) {
696fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDebugLoopCount[index]++;
697fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
698fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
699fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkIntersections::debugLoopCount(DebugLoop index) const {
700fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fDebugLoopCount[index];
701fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
702fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
703fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkIntersections::debugResetLoopCount() {
704fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount));
705fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
706fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
707fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
708fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathOpsConic.h"
709fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPathOpsCubic.h"
710fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
711fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkDCubic SkDQuad::debugToCubic() const {
712fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDCubic cubic;
713fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    cubic[0] = fPts[0];
714fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    cubic[2] = fPts[1];
715fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    cubic[3] = fPts[2];
716fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3;
717fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3;
718fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3;
719fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    cubic[2].fY = (cubic[3].fY + cubic[2].fY * 2) / 3;
720fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return cubic;
721fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
722fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
723fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkDQuad::debugSet(const SkDPoint* pts) {
724fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(fPts, pts, sizeof(fPts));
725fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fDebugGlobalState = nullptr);
726fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
727fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
728fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkDCubic::debugSet(const SkDPoint* pts) {
729fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memcpy(fPts, pts, sizeof(fPts));
730fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(fDebugGlobalState = nullptr);
731fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
732fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
733fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkDConic::debugSet(const SkDPoint* pts, SkScalar weight) {
734fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPts.debugSet(pts);
735fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWeight = weight;
736fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
737fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
738fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkDRect::debugInit() {
739fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fLeft = fTop = fRight = fBottom = SK_ScalarNaN;
740fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
741fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
742fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpAngle.h"
743fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpSegment.h"
744fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
745fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
746fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commented-out lines keep this in sync with addT()
747fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const SkOpPtT* SkOpSegment::debugAddT(double t, SkPathOpsDebug::GlitchLog* log) const {
748fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
749fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint pt = this->ptAtT(t);
750fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* span = &fHead;
751fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
752fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* result = span->ptT();
753fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (t == result->fT || this->match(result, this, t, pt)) {
754fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//             span->bumpSpanAdds();
755fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             return result;
756fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
757fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (t < result->fT) {
758fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpan* prev = result->span()->prev();
759fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FAIL_WITH_NULL_IF(!prev, span);
760fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // marks in global state that new op span has been allocated
761fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->globalState()->setAllocatedOpSpan();
762fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//             span->init(this, prev, t, pt);
763fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->debugValidate();
764fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// #if DEBUG_ADD_T
765fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//             SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
766fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                     span->segment()->debugID(), span->debugID());
767fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// #endif
768fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//             span->bumpSpanAdds();
769fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return nullptr;
770fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
771fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_WITH_NULL_IF(span != &fTail, span);
772fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((span = span->upCast()->next()));
773fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(0);
774fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return nullptr;  // we never get here, but need this to satisfy compiler
775fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
776fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
777fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
778fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_ANGLE
779fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugCheckAngleCoin() const {
780fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* base = &fHead;
781fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* span;
782fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
783fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpAngle* angle = base->fromAngle();
784fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (angle && angle->debugCheckCoincidence()) {
785fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            angle->debugCheckNearCoincidence();
786fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
787fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (base->final()) {
788fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             break;
789fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
790fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        span = base->upCast();
791fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        angle = span->toAngle();
792fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (angle && angle->debugCheckCoincidence()) {
793fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            angle->debugCheckNearCoincidence();
794fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
795fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((base = span->next()));
796fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
797fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
798fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
799fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
800fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// this mimics the order of the checks in handle coincidence
801fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugCheckHealth(SkPathOpsDebug::GlitchLog* glitches) const {
802fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugMoveMultiples(glitches);
803fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugMoveNearby(glitches);
804fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugMissingCoincidence(glitches);
805fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
806fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
807fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commented-out lines keep this in sync with clearAll()
808fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugClearAll(SkPathOpsDebug::GlitchLog* glitches) const {
809fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* span = &fHead;
810fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
811fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->debugClearOne(span, glitches);
812fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((span = span->next()->upCastable()));
813fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->globalState()->coincidence()->debugRelease(glitches, this);
814fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
815fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
816fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commented-out lines keep this in sync with clearOne()
817fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugClearOne(const SkOpSpan* span, SkPathOpsDebug::GlitchLog* glitches) const {
818fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (span->windValue()) glitches->record(SkPathOpsDebug::kCollapsedWindValue_Glitch, span);
819fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (span->oppValue()) glitches->record(SkPathOpsDebug::kCollapsedOppValue_Glitch, span);
820fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!span->done()) glitches->record(SkPathOpsDebug::kCollapsedDone_Glitch, span);
821fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
822fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
823fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
824fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOpAngle* SkOpSegment::debugLastAngle() {
825fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpAngle* result = nullptr;
826fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* span = this->head();
827fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
828fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (span->toAngle()) {
829fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(!result);
830fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result = span->toAngle();
831fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
832fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((span = span->next()->upCastable()));
833fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(result);
834fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
835fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
836fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
837fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
838fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commented-out lines keep this in sync with ClearVisited
839fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::DebugClearVisited(const SkOpSpanBase* span) {
840fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // reset visited flag back to false
841fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
842fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
843fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((ptT = ptT->next()) != stopPtT) {
844fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSegment* opp = ptT->segment();
845fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            opp->resetDebugVisited();
846fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
847fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (!span->final() && (span = span->upCast()->next()));
848fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
849fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
850fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
851fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
852fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commented-out lines keep this in sync with missingCoincidence()
853fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// look for pairs of undetected coincident curves
854fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// assumes that segments going in have visited flag clear
855fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Even though pairs of curves correct detect coincident runs, a run may be missed
856fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// if the coincidence is a product of multiple intersections. For instance, given
857fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// curves A, B, and C:
858fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
859fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// the end of C that the intersection is replaced with the end of C.
860fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Even though A-B correctly do not detect an intersection at point 2,
861fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// the resulting run from point 1 to point 2 is coincident on A and B.
862fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const {
863fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->done()) {
864fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
865fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
866fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* prior = nullptr;
867fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* spanBase = &fHead;
868fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    bool result = false;
869fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
870fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
871fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(ptT->span() == spanBase);
872fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((ptT = ptT->next()) != spanStopPtT) {
873fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT->deleted()) {
874fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
875fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
876fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSegment* opp = ptT->span()->segment();
877fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (opp->done()) {
878fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
879fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
880fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
881fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!opp->debugVisited()) {
882fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
883fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
884fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (spanBase == &fHead) {
885fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
886fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
887fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT->segment() == this) {
888fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
889fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
890fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpan* span = spanBase->upCastable();
891fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // FIXME?: this assumes that if the opposite segment is coincident then no more
892fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // coincidence needs to be detected. This may not be true.
893fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (span && span->segment() != opp && span->containsCoincidence(opp)) {  // debug has additional condition since it may be called before inner duplicate points have been deleted
894fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
895fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
896fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (spanBase->segment() != opp && spanBase->containsCoinEnd(opp)) {  // debug has additional condition since it may be called before inner duplicate points have been deleted
897fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
898fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
899fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* priorPtT = nullptr, * priorStopPtT;
900fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // find prior span containing opp segment
901fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSegment* priorOpp = nullptr;
902fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpan* priorTest = spanBase->prev();
903fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while (!priorOpp && priorTest) {
904fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                priorStopPtT = priorPtT = priorTest->ptT();
905fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                while ((priorPtT = priorPtT->next()) != priorStopPtT) {
906fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (priorPtT->deleted()) {
907fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        continue;
908fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
909fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    const SkOpSegment* segment = priorPtT->span()->segment();
910fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (segment == opp) {
911fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        prior = priorTest;
912fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        priorOpp = opp;
913fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        break;
914fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
915fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
916fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                priorTest = priorTest->prev();
917fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
918fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!priorOpp) {
919fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
920fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
921fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (priorPtT == ptT) {
922fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
923fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
924fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* oppStart = prior->ptT();
925fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* oppEnd = spanBase->ptT();
926fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool swapped = priorPtT->fT > ptT->fT;
927fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (swapped) {
928fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(priorPtT, ptT);
929fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(oppStart, oppEnd);
930fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
931fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpCoincidence* coincidence = this->globalState()->coincidence();
932fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
933fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* rootPtT = ptT->span()->ptT();
934fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* rootOppStart = oppStart->span()->ptT();
935fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
936fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (coincidence->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
937fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                goto swapBack;
938fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
939fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
940fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // mark coincidence
941fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_VERBOSE
942fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
943fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                         rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
944fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                         rootOppEnd->debugID());
945fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
946fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                log->record(SkPathOpsDebug::kMissingCoin_Glitch, priorPtT, ptT, oppStart, oppEnd);
947fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                //   coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
948fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // }
949fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
950fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
951fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
952fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // result = true;
953fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
954fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    swapBack:
955fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (swapped) {
956fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(priorPtT, ptT);
957fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
958fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
959fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
960fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugClearVisited(&fHead);
961fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
962fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
963fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
964fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commented-out lines keep this in sync with moveMultiples()
965fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// if a span has more than one intersection, merge the other segments' span as needed
966fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugMoveMultiples(SkPathOpsDebug::GlitchLog* glitches) const {
967fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
968fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* test = &fHead;
969fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
970fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int addCount = test->spanAddsCount();
971fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//        SkASSERT(addCount >= 1);
972fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (addCount <= 1) {
973fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
974fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
975fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* startPtT = test->ptT();
976fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* testPtT = startPtT;
977fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {  // iterate through all spans associated with start
978fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* oppSpan = testPtT->span();
979fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppSpan->spanAddsCount() == addCount) {
980fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
981fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
982fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppSpan->deleted()) {
983fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
984fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
985fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSegment* oppSegment = oppSpan->segment();
986fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppSegment == this) {
987fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
988fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
989fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // find range of spans to consider merging
990fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* oppPrev = oppSpan;
991fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* oppFirst = oppSpan;
992fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while ((oppPrev = oppPrev->prev())) {
993fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
994fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
995fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
996fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (oppPrev->spanAddsCount() == addCount) {
997fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
998fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
999fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (oppPrev->deleted()) {
1000fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
1001fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1002fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oppFirst = oppPrev;
1003fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1004fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* oppNext = oppSpan;
1005fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* oppLast = oppSpan;
1006fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
1007fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!roughly_equal(oppNext->t(), oppSpan->t())) {
1008fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
1009fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1010fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (oppNext->spanAddsCount() == addCount) {
1011fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
1012fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1013fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (oppNext->deleted()) {
1014fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
1015fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1016fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oppLast = oppNext;
1017fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1018fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppFirst == oppLast) {
1019fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
1020fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1021fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* oppTest = oppFirst;
1022fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            do {
1023fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (oppTest == oppSpan) {
1024fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
1025fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1026fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // check to see if the candidate meets specific criteria:
1027fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // it contains spans of segments in test's loop but not including 'this'
1028fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* oppStartPtT = oppTest->ptT();
1029fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* oppPtT = oppStartPtT;
1030fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                while ((oppPtT = oppPtT->next()) != oppStartPtT) {
1031fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    const SkOpSegment* oppPtTSegment = oppPtT->segment();
1032fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (oppPtTSegment == this) {
1033fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        goto tryNextSpan;
1034fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
1035fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    const SkOpPtT* matchPtT = startPtT;
1036fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    do {
1037fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        if (matchPtT->segment() == oppPtTSegment) {
1038fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            goto foundMatch;
1039fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        }
1040fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    } while ((matchPtT = matchPtT->next()) != startPtT);
1041fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    goto tryNextSpan;
1042fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            foundMatch:  // merge oppTest and oppSpan
1043fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oppSegment->debugValidate();
1044fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oppTest->debugMergeMatches(glitches, oppSpan);
1045fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oppTest->debugAddOpp(glitches, oppSpan);
1046fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oppSegment->debugValidate();
1047fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    goto checkNextSpan;
1048fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1049fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        tryNextSpan:
1050fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ;
1051fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
1052fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while ((testPtT = testPtT->next()) != startPtT);
1053fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotcheckNextSpan:
1054fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ;
1055fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((test = test->final() ? nullptr : test->upCast()->next()));
1056fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot   debugValidate();
1057fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot   return;
1058fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1059fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1060fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commented-out lines keep this in sync with moveNearby()
1061fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
1062fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugMoveNearby(SkPathOpsDebug::GlitchLog* glitches) const {
1063fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
1064fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // release undeleted spans pointing to this seg that are linked to the primary span
1065fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* spanBase = &fHead;
1066fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1067fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* ptT = spanBase->ptT();
1068fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* headPtT = ptT;
1069fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((ptT = ptT->next()) != headPtT) {
1070fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              const SkOpSpanBase* test = ptT->span();
1071fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT->segment() == this && !ptT->deleted() && test != spanBase
1072fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    && test->ptT() == ptT) {
1073fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (test->final()) {
1074fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (spanBase == &fHead) {
1075fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        glitches->record(SkPathOpsDebug::kMoveNearbyClearAll_Glitch, this);
1076fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                        return;
1077fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
1078fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitches->record(SkPathOpsDebug::kMoveNearbyReleaseFinal_Glitch, spanBase, ptT);
1079fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else if (test->prev()) {
1080fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitches->record(SkPathOpsDebug::kMoveNearbyRelease_Glitch, test, headPtT);
1081fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1082fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                break;
1083fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1084fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1085fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        spanBase = spanBase->upCast()->next();
1086fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (!spanBase->final());
1087fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1088fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // This loop looks for adjacent spans which are near by
1089fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    spanBase = &fHead;
1090fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {  // iterate through all spans associated with start
1091fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* test = spanBase->upCast()->next();
1092fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool found;
1093fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!this->spansNearby(spanBase, test, &found)) {
1094fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch, test);
1095fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1096fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (found) {
1097fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (test->final()) {
1098fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (spanBase->prev()) {
1099fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch, test);
1100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
1101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    glitches->record(SkPathOpsDebug::kMoveNearbyClearAll2_Glitch, this);
1102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // return
1103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
1105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                glitches->record(SkPathOpsDebug::kMoveNearbyMerge_Glitch, spanBase);
1106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        spanBase = test;
1109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (!spanBase->final());
1110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
1111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugReset() {
1115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->init(this->fPts, this->fWeight, this->contour(), this->verb());
1116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_ORDER
1119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugSetCoinT(int index, SkScalar t) const {
1120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDebugBaseMax < 0 || fDebugBaseIndex == index) {
1121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugBaseIndex = index;
1122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugBaseMin = SkTMin(t, fDebugBaseMin);
1123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugBaseMax = SkTMax(t, fDebugBaseMax);
1124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fDebugBaseMin >= t || t >= fDebugBaseMax);
1127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDebugLastMax < 0 || fDebugLastIndex == index) {
1128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugLastIndex = index;
1129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugLastMin = SkTMin(t, fDebugLastMin);
1130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDebugLastMax = SkTMax(t, fDebugLastMax);
1131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fDebugLastMin >= t || t >= fDebugLastMax);
1134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT((t - fDebugBaseMin > 0) == (fDebugLastMin - fDebugBaseMin > 0));
1135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_ACTIVE_SPANS
1139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugShowActiveSpans(SkString* str) const {
1140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
1141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (done()) {
1142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int lastId = -1;
1145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double lastT = -1;
1146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* span = &fHead;
1147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (span->done()) {
1149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
1150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (lastId == this->debugID() && lastT == span->t()) {
1152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
1153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        lastId = this->debugID();
1155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        lastT = span->t();
1156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str->appendf("%s id=%d", __FUNCTION__, this->debugID());
1157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // since endpoints may have be adjusted, show actual computed curves
1158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDCurve curvePart;
1159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->subDivide(span, span->next(), &curvePart);
1160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkDPoint* pts = curvePart.fCubic.fPts;
1161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str->appendf(" (%1.9g,%1.9g", pts[0].fX, pts[0].fY);
1162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
1163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str->appendf(" %1.9g,%1.9g", pts[vIndex].fX, pts[vIndex].fY);
1164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (SkPath::kConic_Verb == fVerb) {
1166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str->appendf(" %1.9gf", curvePart.fConic.fWeight);
1167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str->appendf(") t=%1.9g tEnd=%1.9g", span->t(), span->next()->t());
1169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (span->windSum() == SK_MinS32) {
1170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str->appendf(" windSum=?");
1171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
1172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str->appendf(" windSum=%d", span->windSum());
1173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (span->oppValue() && span->oppSum() == SK_MinS32) {
1175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str->appendf(" oppSum=?");
1176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else if (span->oppValue() || span->oppSum() != SK_MinS32) {
1177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str->appendf(" oppSum=%d", span->oppSum());
1178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str->appendf(" windValue=%d", span->windValue());
1180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (span->oppValue() || span->oppSum() != SK_MinS32) {
1181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            str->appendf(" oppValue=%d", span->oppValue());
1182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str->appendf("\n");
1184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot   } while ((span = span->next()->upCastable()));
1185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_MARK_DONE
1189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding) {
1190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPoint& pt = span->ptT()->fPt;
1191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("%s id=%d", fun, this->debugID());
1192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
1193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
1194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
1195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
1197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t());
1198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (winding == SK_MinS32) {
1199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("?");
1200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
1201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", winding);
1202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" windSum=");
1204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (span->windSum() == SK_MinS32) {
1205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("?");
1206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
1207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", span->windSum());
1208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" windValue=%d\n", span->windValue());
1210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding,
1213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                      int oppWinding) {
1214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPoint& pt = span->ptT()->fPt;
1215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("%s id=%d", fun, this->debugID());
1216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
1217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
1218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
1219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
1221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t(), winding, oppWinding);
1222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (winding == SK_MinS32) {
1223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("?");
1224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
1225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", winding);
1226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" newOppSum=");
1228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (oppWinding == SK_MinS32) {
1229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("?");
1230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
1231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", oppWinding);
1232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" oppSum=");
1234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (span->oppSum() == SK_MinS32) {
1235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("?");
1236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
1237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", span->oppSum());
1238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" windSum=");
1240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (span->windSum() == SK_MinS32) {
1241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("?");
1242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
1243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", span->windSum());
1244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue());
1246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// loop looking for a pair of angle parts that are too close to be sorted
1251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* This is called after other more simple intersection and angle sorting tests have been exhausted.
1252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot   This should be rarely called -- the test below is thorough and time consuming.
1253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot   This checks the distance between start points; the distance between
1254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot*/
1255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_ANGLE
1256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpAngle::debugCheckNearCoincidence() const {
1257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* test = this;
1258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* testSegment = test->segment();
1260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double testStartT = test->start()->t();
1261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDPoint testStartPt = testSegment->dPtAtT(testStartT);
1262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double testEndT = test->end()->t();
1263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDPoint testEndPt = testSegment->dPtAtT(testEndT);
1264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double testLenSq = testStartPt.distanceSquared(testEndPt);
1265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%s testLenSq=%1.9g id=%d\n", __FUNCTION__, testLenSq, testSegment->debugID());
1266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double testMidT = (testStartT + testEndT) / 2;
1267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpAngle* next = test;
1268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((next = next->fNext) != this) {
1269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSegment* nextSegment = next->segment();
1270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double testMidDistSq = testSegment->distSq(testMidT, next);
1271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double testEndDistSq = testSegment->distSq(testEndT, next);
1272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double nextStartT = next->start()->t();
1273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDPoint nextStartPt = nextSegment->dPtAtT(nextStartT);
1274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double distSq = testStartPt.distanceSquared(nextStartPt);
1275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double nextEndT = next->end()->t();
1276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double nextMidT = (nextStartT + nextEndT) / 2;
1277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double nextMidDistSq = nextSegment->distSq(nextMidT, test);
1278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double nextEndDistSq = nextSegment->distSq(nextEndT, test);
1279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%s distSq=%1.9g testId=%d nextId=%d\n", __FUNCTION__, distSq,
1280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    testSegment->debugID(), nextSegment->debugID());
1281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq);
1282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq);
1283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq);
1284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq);
1285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT);
1286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double nextLenSq = nextStartPt.distanceSquared(nextEndPt);
1287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq);
1288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("\n");
1289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        test = test->fNext;
1291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (test->fNext != this);
1292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_ANGLE
1296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkString SkOpAngle::debugPart() const {
1297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkString result;
1298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (this->segment()->verb()) {
1299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkPath::kLine_Verb:
1300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fPart.fCurve),
1301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->segment()->debugID());
1302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkPath::kQuad_Verb:
1304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result.printf(QUAD_DEBUG_STR " id=%d", QUAD_DEBUG_DATA(fPart.fCurve),
1305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->segment()->debugID());
1306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkPath::kConic_Verb:
1308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result.printf(CONIC_DEBUG_STR " id=%d",
1309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    CONIC_DEBUG_DATA(fPart.fCurve, fPart.fCurve.fConic.fWeight),
1310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->segment()->debugID());
1311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case SkPath::kCubic_Verb:
1313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result.printf(CUBIC_DEBUG_STR " id=%d", CUBIC_DEBUG_DATA(fPart.fCurve),
1314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->segment()->debugID());
1315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
1317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(0);
1318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
1320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_SORT
1324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpAngle::debugLoop() const {
1325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* first = this;
1326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* next = this;
1327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        next->dumpOne(true);
1329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("\n");
1330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        next = next->fNext;
1331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (next && next != first);
1332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    next = first;
1333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        next->debugValidate();
1335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        next = next->fNext;
1336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (next && next != first);
1337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpAngle::debugValidate() const {
1341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
1342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->globalState()->debugCheckHealth()) {
1343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_VALIDATE
1347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* first = this;
1348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* next = this;
1349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int wind = 0;
1350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int opp = 0;
1351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int lastXor = -1;
1352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int lastOppXor = -1;
1353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (next->unorderable()) {
1355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
1356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpan* minSpan = next->start()->starter(next->end());
1358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (minSpan->windValue() == SK_MinS32) {
1359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
1360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool op = next->segment()->operand();
1362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool isXor = next->segment()->isXor();
1363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool oppXor = next->segment()->oppXor();
1364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!DEBUG_LIMIT_WIND_SUM || between(0, minSpan->windValue(), DEBUG_LIMIT_WIND_SUM));
1365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!DEBUG_LIMIT_WIND_SUM
1366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                || between(-DEBUG_LIMIT_WIND_SUM, minSpan->oppValue(), DEBUG_LIMIT_WIND_SUM));
1367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool useXor = op ? oppXor : isXor;
1368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(lastXor == -1 || lastXor == (int) useXor);
1369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        lastXor = (int) useXor;
1370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        wind += next->debugSign() * (op ? minSpan->oppValue() : minSpan->windValue());
1371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (useXor) {
1372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            wind &= 1;
1373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        useXor = op ? isXor : oppXor;
1375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor);
1376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        lastOppXor = (int) useXor;
1377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        opp += next->debugSign() * (op ? minSpan->windValue() : minSpan->oppValue());
1378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (useXor) {
1379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            opp &= 1;
1380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        next = next->fNext;
1382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (next && next != first);
1383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(wind == 0 || !SkPathOpsDebug::gRunFail);
1384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(opp == 0 || !SkPathOpsDebug::gRunFail);
1385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpAngle::debugValidateNext() const {
1389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if !FORCE_RELEASE
1390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* first = this;
1391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpAngle* next = first;
1392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTDArray<const SkOpAngle*>(angles);
1393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//        SkASSERT_RELEASE(next->fSegment->debugContains(next));
1395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        angles.push(next);
1396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        next = next->next();
1397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (next == first) {
1398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT_RELEASE(!angles.contains(next));
1401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!next) {
1402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
1403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (true);
1405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
1409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over,
1410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpGlobalState* debugState) const {
1411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(coinPtTEnd()->span() == over || !SkOpGlobalState::DebugRunFail());
1412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(oppPtTEnd()->span() == outer || !SkOpGlobalState::DebugRunFail());
1413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
1417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// sets the span's end to the ptT referenced by the previous-next
1418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkCoincidentSpans::debugCorrectOneEnd(SkPathOpsDebug::GlitchLog* log,
1419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
1420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) const ) const {
1421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* origPtT = (this->*getEnd)();
1422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* origSpan = origPtT->span();
1423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* prev = origSpan->prev();
1424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* testPtT = prev ? prev->next()->ptT()
1425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            : origSpan->upCast()->next()->prev()->ptT();
1426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (origPtT != testPtT) {
1427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        log->record(SkPathOpsDebug::kCorrectEnd_Glitch, this, origPtT, testPtT);
1428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* Commented-out lines keep this in sync with correctEnds */
1433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// FIXME: member pointers have fallen out of favor and can be replaced with
1434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// an alternative approach.
1435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// makes all span ends agree with the segment's spans that define them
1436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkCoincidentSpans::debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const {
1437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugCorrectOneEnd(log, &SkCoincidentSpans::coinPtTStart, nullptr);
1438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugCorrectOneEnd(log, &SkCoincidentSpans::coinPtTEnd, nullptr);
1439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugCorrectOneEnd(log, &SkCoincidentSpans::oppPtTStart, nullptr);
1440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugCorrectOneEnd(log, &SkCoincidentSpans::oppPtTEnd, nullptr);
1441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* Commented-out lines keep this in sync with expand */
1444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// expand the range by checking adjacent spans for coincidence
1445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkCoincidentSpans::debugExpand(SkPathOpsDebug::GlitchLog* log) const {
1446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool expanded = false;
1447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment = coinPtTStart()->segment();
1448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* oppSegment = oppPtTStart()->segment();
1449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpan* start = coinPtTStart()->span()->upCast();
1451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpan* prev = start->prev();
1452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* oppPtT;
1453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!prev || !(oppPtT = prev->contains(oppSegment))) {
1454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double midT = (prev->t() + start->t()) / 2;
1457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!segment->isClose(midT, oppSegment)) {
1458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, this, prev->ptT(), oppPtT);
1461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        expanded = true;
1462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (false);  // actual continues while expansion is possible
1463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* end = coinPtTEnd()->span();
1465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
1466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (next && next->deleted()) {
1467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* oppPtT;
1470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!next || !(oppPtT = next->contains(oppSegment))) {
1471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double midT = (end->t() + next->t()) / 2;
1474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!segment->isClose(midT, oppSegment)) {
1475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
1476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, this, next->ptT(), oppPtT);
1478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        expanded = true;
1479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (false);  // actual continues while expansion is possible
1480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return expanded;
1481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// description below
1484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log, const SkOpSpan* base, const SkOpSpanBase* testSpan) const {
1485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* testPtT = testSpan->ptT();
1486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stopPtT = testPtT;
1487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* baseSeg = base->segment();
1488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((testPtT = testPtT->next()) != stopPtT) {
1489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* testSeg = testPtT->segment();
1490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (testPtT->deleted()) {
1491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
1492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (testSeg == baseSeg) {
1494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
1495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (testPtT->span()->ptT() != testPtT) {
1497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
1498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (this->contains(baseSeg, testSeg, testPtT->fT)) {
1500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
1501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // intersect perp with base->ptT() with testPtT->segment()
1503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
1504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint& pt = base->pt();
1505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
1506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkIntersections i;
1507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
1508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int index = 0; index < i.used(); ++index) {
1509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double t = i[0][index];
1510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!between(0, t, 1)) {
1511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
1512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDPoint oppPt = i.pt(index);
1514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!oppPt.approximatelyEqual(pt)) {
1515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
1516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
1518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpPtT* oppStart = writableSeg->addT(t);
1519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppStart == testPtT) {
1520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
1521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
1523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            oppStart->span()->addOpp(writableBase);
1524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppStart->deleted()) {
1525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
1526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSegment* coinSeg = base->segment();
1528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkOpSegment* oppSeg = oppStart->segment();
1529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double coinTs, coinTe, oppTs, oppTe;
1530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (Ordered(coinSeg, oppSeg)) {
1531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                coinTs = base->t();
1532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                coinTe = testSpan->t();
1533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oppTs = oppStart->fT;
1534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oppTe = testPtT->fT;
1535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
1536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(coinSeg, oppSeg);
1537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                coinTs = oppStart->fT;
1538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                coinTe = testPtT->fT;
1539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oppTs = base->t();
1540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oppTe = testSpan->t();
1541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (coinTs > coinTe) {
1543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(coinTs, coinTe);
1544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(oppTs, oppTe);
1545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool added;
1547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (this->debugAddOrOverlap(log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added), false) {
1548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return;
1549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
1553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// description below
1556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* ptT) const {
1557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FAIL_IF(!ptT->span()->upCastable(), ptT->span());
1558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* base = ptT->span()->upCast();
1559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* prev = base->prev();
1560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FAIL_IF(!prev, ptT->span());
1561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!prev->isCanceled()) {
1562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (this->debugAddEndMovedSpans(log, base, base->prev()), false) {
1563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
1564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!base->isCanceled()) {
1567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (this->debugAddEndMovedSpans(log, base, base->next()), false) {
1568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
1569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
1572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*  If A is coincident with B and B includes an endpoint, and A's matching point
1575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    is not the endpoint (i.e., there's an implied line connecting B-end and A)
1576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    then assume that the same implied line may intersect another curve close to B.
1577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Since we only care about coincidence that was undetected, look at the
1578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
1579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    next door) and see if the A matching point is close enough to form another
1580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coincident pair. If so, check for a new coincident span between B-end/A ptT loop
1581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    and the adjacent ptT loop.
1582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot*/
1583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) const {
1584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* span = fHead;
1585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!span) {
1586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    fTop = span;
1589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    fHead = nullptr;
1590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
1592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FAIL_IF(1 == span->coinPtTStart()->fT, span);
1593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool onEnd = span->coinPtTStart()->fT == 0;
1594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
1595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (onEnd) {
1596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!oOnEnd) {  // if both are on end, any nearby intersect was already found
1597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (this->debugAddEndMovedSpans(log, span->oppPtTStart()), false) {
1598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        return;
1599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
1600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (oOnEnd) {
1602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (this->debugAddEndMovedSpans(log, span->coinPtTStart()), false) {
1603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return;
1604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
1608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool onEnd = span->coinPtTEnd()->fT == 1;
1609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
1610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (onEnd) {
1611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!oOnEnd) {
1612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (this->debugAddEndMovedSpans(log, span->oppPtTEnd()), false) {
1613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        return;
1614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
1615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (oOnEnd) {
1617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (this->debugAddEndMovedSpans(log, span->coinPtTEnd()), false) {
1618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return;
1619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((span = span->next()));
1623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    this->restoreHead();
1624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
1625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* Commented-out lines keep this in sync with addExpanded */
1628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// for each coincident pair, match the spans
1629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// if the spans don't match, add the mssing pt to the segment and loop it in the opposite span
1630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const {
1631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    DEBUG_SET_PHASE();
1632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* coin = this->fHead;
1633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!coin) {
1634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* startPtT = coin->coinPtTStart();
1638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* oStartPtT = coin->oppPtTStart();
1639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double priorT = startPtT->fT;
1640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double oPriorT = oStartPtT->fT;
1641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_IF(!startPtT->contains(oStartPtT), coin);
1642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
1643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* start = startPtT->span();
1644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* oStart = oStartPtT->span();
1645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* end = coin->coinPtTEnd()->span();
1646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
1647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_IF(oEnd->deleted(), coin);
1648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_IF(!start->upCastable(), coin);
1649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* test = start->upCast()->next();
1650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_IF(!coin->flipped() && !oStart->upCastable(), coin);
1651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
1652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_IF(!oTest, coin);
1653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* seg = start->segment();
1654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* oSeg = oStart->segment();
1655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (test != end || oTest != oEnd) {
1656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
1657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
1658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!containedOpp || !containedThis) {
1659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // choose the ends, or the first common pt-t list shared by both
1660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                double nextT, oNextT;
1661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (containedOpp) {
1662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    nextT = test->t();
1663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oNextT = containedOpp->fT;
1664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else if (containedThis) {
1665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    nextT = containedThis->fT;
1666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oNextT = oTest->t();
1667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
1668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    // iterate through until a pt-t list found that contains the other
1669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    const SkOpSpanBase* walk = test;
1670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    const SkOpPtT* walkOpp;
1671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    do {
1672fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        FAIL_IF(!walk->upCastable(), coin);
1673fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        walk = walk->upCast()->next();
1674fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    } while (!(walkOpp = walk->ptT()->contains(oSeg))
1675fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            && walk != coin->coinPtTEnd()->span());
1676fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    FAIL_IF(!walkOpp, coin);
1677fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    nextT = walk->t();
1678fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oNextT = walkOpp->fT;
1679fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1680fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // use t ranges to guess which one is missing
1681fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                double startRange = nextT - priorT;
1682fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!startRange, coin);
1683fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                double startPart = (test->t() - priorT) / startRange;
1684fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                double oStartRange = oNextT - oPriorT;
1685fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!oStartRange, coin);
1686fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange;
1687fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(startPart == oStartPart, coin);
1688fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
1689fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        : !!containedThis;
1690fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                bool startOver = false;
1691fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                addToOpp ? log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch,
1692fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        oPriorT + oStartRange * startPart, test)
1693fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        : log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch,
1694fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        priorT + startRange * oStartPart, oTest);
1695fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         //       FAIL_IF(!success, coin);
1696fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (startOver) {
1697fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    test = start;
1698fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    oTest = oStart;
1699fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1700fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                end = coin->coinPtTEnd()->span();
1701fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oEnd = coin->oppPtTEnd()->span();
1702fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1703fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (test != end) {
1704fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!test->upCastable(), coin);
1705fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                priorT = test->t();
1706fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                test = test->upCast()->next();
1707fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1708fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oTest != oEnd) {
1709fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oPriorT = oTest->t();
1710fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next();
1711fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!oTest, coin);
1712fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1713fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1714fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((coin = coin->next()));
1715fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
1716fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1717fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1718fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* Commented-out lines keep this in sync addIfMissing() */
1719fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// note that over1s, over1e, over2s, over2e are ordered
1720fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugAddIfMissing(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* over1s, const SkOpPtT* over2s,
1721fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double tStart, double tEnd, const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, bool* added,
1722fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* over1e, const SkOpPtT* over2e) const {
1723fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(tStart < tEnd);
1724fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(over1s->fT < over1e->fT);
1725fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(over1s->fT, tStart, over1e->fT));
1726fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(over1s->fT, tEnd, over1e->fT));
1727fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(over2s->fT < over2e->fT);
1728fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(over2s->fT, tStart, over2e->fT));
1729fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(over2s->fT, tEnd, over2e->fT));
1730fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(over1s->segment() == over1e->segment());
1731fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(over2s->segment() == over2e->segment());
1732fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(over1s->segment() == over2s->segment());
1733fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(over1s->segment() != coinSeg);
1734fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(over1s->segment() != oppSeg);
1735fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(coinSeg != oppSeg);
1736fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double coinTs, coinTe, oppTs, oppTe;
1737fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coinTs = TRange(over1s, tStart, coinSeg  SkDEBUGPARAMS(over1e));
1738fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    coinTe = TRange(over1s, tEnd, coinSeg  SkDEBUGPARAMS(over1e));
1739fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (coinSeg->collapsed(coinTs, coinTe)) {
1740fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, coinSeg);
1741fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1742fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    oppTs = TRange(over2s, tStart, oppSeg  SkDEBUGPARAMS(over2e));
1743fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    oppTe = TRange(over2s, tEnd, oppSeg  SkDEBUGPARAMS(over2e));
1744fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (oppSeg->collapsed(oppTs, oppTe)) {
1745fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, oppSeg);
1746fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1747fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (coinTs > coinTe) {
1748fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTSwap(coinTs, coinTe);
1749fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTSwap(oppTs, oppTe);
1750fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1751fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return this->debugAddOrOverlap(log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added
1752fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            );
1753fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1754fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1755fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* Commented-out lines keep this in sync addOrOverlap() */
1756fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
1757fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
1758fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugAddOrOverlap(SkPathOpsDebug::GlitchLog* log,
1759fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
1760fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double coinTs, double coinTe, double oppTs, double oppTe, bool* added) const {
1761fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkTDArray<SkCoincidentSpans*> overlaps;
1762fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOPASSERT(!fTop);   // this is (correctly) reversed in addifMissing()
1763fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fTop && !this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe,
1764fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            &overlaps)) {
1765fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1766fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1767fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
1768fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coinTe, oppTs, oppTe, &overlaps)) {
1769fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1770fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1771fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
1772fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
1773fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkCoincidentSpans* test = overlaps[index];
1774fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
1775fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->coinPtTStart());
1776fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1777fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
1778fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->coinPtTEnd());
1779fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1780fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (overlap->flipped()
1781fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
1782fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
1783fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->oppPtTStart());
1784fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1785fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (overlap->flipped()
1786fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
1787fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
1788fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->oppPtTEnd());
1789fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1790fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fHead) { this->debugRelease(log, fHead, test);
1791fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->debugRelease(log, fTop, test);
1792fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1793fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1794fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
1795fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
1796fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(overlap && cs && ce && overlap->contains(cs, ce), coinSeg);
1797fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(cs != ce || !cs, coinSeg);
1798fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
1799fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
1800fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(overlap && os && oe && overlap->contains(os, oe), oppSeg);
1801fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(true || !cs || !cs->deleted());
1802fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(true || !os || !os->deleted());
1803fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(true || !ce || !ce->deleted());
1804fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(true || !oe || !oe->deleted());
1805fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
1806fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
1807fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(csExisting && csExisting == ceExisting, coinSeg);
1808fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(csExisting && (csExisting == ce ||
1809fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            csExisting->contains(ceExisting ? ceExisting : ce)), coinSeg);
1810fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(ceExisting && (ceExisting == cs ||
1811fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ceExisting->contains(csExisting ? csExisting : cs)), coinSeg);
1812fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
1813fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
1814fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(osExisting && osExisting == oeExisting, oppSeg);
1815fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(osExisting && (osExisting == oe ||
1816fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            osExisting->contains(oeExisting ? oeExisting : oe)), oppSeg);
1817fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(oeExisting && (oeExisting == os ||
1818fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            oeExisting->contains(osExisting ? osExisting : os)), oppSeg);
1819fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool csDeleted = false, osDeleted = false, ceDeleted = false,  oeDeleted = false;
1820fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugValidate();
1821fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!cs || !os) {
1822fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!cs)
1823fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            cs = coinSeg->debugAddT(coinTs, log);
1824fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!os)
1825fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            os = oppSeg->debugAddT(oppTs, log);
1826fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//      RETURN_FALSE_IF(callerAborts, !csWritable || !osWritable);
1827fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (cs && os) cs->span()->debugAddOpp(log, os->span());
1828fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         cs = csWritable;
1829fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         os = osWritable->active();
1830fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        RETURN_FALSE_IF((ce && ce->deleted()) || (oe && oe->deleted()), coinSeg);
1831fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1832fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!ce || !oe) {
1833fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!ce)
1834fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ce = coinSeg->debugAddT(coinTe, log);
1835fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!oe)
1836fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            oe = oppSeg->debugAddT(oppTe, log);
1837fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ce && oe) ce->span()->debugAddOpp(log, oe->span());
1838fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         ce = ceWritable;
1839fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         oe = oeWritable;
1840fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1841fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugValidate();
1842fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(csDeleted, coinSeg);
1843fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(osDeleted, oppSeg);
1844fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(ceDeleted, coinSeg);
1845fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(oeDeleted, oppSeg);
1846fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    RETURN_FALSE_IF(!cs || !ce || cs == ce || cs->contains(ce) || !os || !oe || os == oe || os->contains(oe), coinSeg);
1847fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool result = true;
1848fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (overlap) {
1849fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (overlap->coinPtTStart()->segment() == coinSeg) {
1850fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe);
1851fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
1852fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppTs > oppTe) {
1853fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(coinTs, coinTe);
1854fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(oppTs, oppTe);
1855fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1856fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, oppSeg, oppTs, oppTe, coinSeg, coinTs, coinTe);
1857fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1858fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if 0 && DEBUG_COINCIDENCE_VERBOSE
1859fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (result) {
1860fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             overlap->debugShow();
1861fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1862fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1863fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
1864fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        log->record(SkPathOpsDebug::kAddMissingCoin_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe);
1865fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if 0 && DEBUG_COINCIDENCE_VERBOSE
1866fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fHead->debugShow();
1867fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
1868fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1869fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugValidate();
1870fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return (void) result;
1871fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1872fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1873fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Extra commented-out lines keep this in sync with addMissing()
1874fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* detects overlaps of different coincident runs on same segment */
1875fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* does not detect overlaps for pairs without any segments in common */
1876fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// returns true if caller should loop again
1877fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugAddMissing(SkPathOpsDebug::GlitchLog* log, bool* added) const {
1878fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* outer = fHead;
1879fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *added = false;
1880fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!outer) {
1881fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1882fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
1883fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // fTop = outer;
1884fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // fHead = nullptr;
1885fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1886fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // addifmissing can modify the list that this is walking
1887fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // save head so that walker can iterate over old data unperturbed
1888fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // addifmissing adds to head freely then add saved head in the end
1889fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* ocs = outer->coinPtTStart();
1890fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!ocs->deleted());
1891fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* outerCoin = ocs->segment();
1892fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!outerCoin->done());  // if it's done, should have already been removed from list
1893fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* oos = outer->oppPtTStart();
1894fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (oos->deleted()) {
1895fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
1896fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1897fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* outerOpp = oos->segment();
1898fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!outerOpp->done());
1899fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//        SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
1900fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//        SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
1901fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkCoincidentSpans* inner = outer;
1902fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((inner = inner->next())) {
1903fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->debugValidate();
1904fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            double overS, overE;
1905fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* ics = inner->coinPtTStart();
1906fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(!ics->deleted());
1907fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSegment* innerCoin = ics->segment();
1908fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(!innerCoin->done());
1909fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* ios = inner->oppPtTStart();
1910fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(!ios->deleted());
1911fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSegment* innerOpp = ios->segment();
1912fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(!innerOpp->done());
1913fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//            SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
1914fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//            SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
1915fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (outerCoin == innerCoin) {
1916fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* oce = outer->coinPtTEnd();
1917fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (oce->deleted()) {
1918fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return;
1919fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1920fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* ice = inner->coinPtTEnd();
1921fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!ice->deleted());
1922fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
1923fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->debugAddIfMissing(log, ocs->starter(oce), ics->starter(ice),
1924fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            overS, overE, outerOpp, innerOpp, added,
1925fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            ocs->debugEnder(oce),
1926fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            ics->debugEnder(ice));
1927fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1928fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (outerCoin == innerOpp) {
1929fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* oce = outer->coinPtTEnd();
1930fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!oce->deleted());
1931fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* ioe = inner->oppPtTEnd();
1932fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!ioe->deleted());
1933fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
1934fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->debugAddIfMissing(log, ocs->starter(oce), ios->starter(ioe),
1935fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            overS, overE, outerOpp, innerCoin, added,
1936fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            ocs->debugEnder(oce),
1937fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            ios->debugEnder(ioe));
1938fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1939fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (outerOpp == innerCoin) {
1940fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* ooe = outer->oppPtTEnd();
1941fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!ooe->deleted());
1942fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* ice = inner->coinPtTEnd();
1943fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!ice->deleted());
1944fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(outerCoin != innerOpp);
1945fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
1946fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->debugAddIfMissing(log, oos->starter(ooe), ics->starter(ice),
1947fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            overS, overE, outerCoin, innerOpp, added,
1948fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            oos->debugEnder(ooe),
1949fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            ics->debugEnder(ice));
1950fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1951fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (outerOpp == innerOpp) {
1952fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* ooe = outer->oppPtTEnd();
1953fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(!ooe->deleted());
1954fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* ioe = inner->oppPtTEnd();
1955fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (ioe->deleted()) {
1956fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return;
1957fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1958fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(outerCoin != innerCoin);
1959fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
1960fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    this->debugAddIfMissing(log, oos->starter(ooe), ios->starter(ioe),
1961fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            overS, overE, outerCoin, innerCoin, added,
1962fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            oos->debugEnder(ooe),
1963fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            ios->debugEnder(ioe));
1964fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
1965fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1966fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->debugValidate();
1967fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1968fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((outer = outer->next()));
1969fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // this->restoreHead();
1970fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
1971fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1972fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1973fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with release()
1974fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugRelease(SkPathOpsDebug::GlitchLog* log, const SkCoincidentSpans* coin, const SkCoincidentSpans* remove) const {
1975fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* head = coin;
1976fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* prev = nullptr;
1977fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* next;
1978fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
1979fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        next = coin->next();
1980fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (coin == remove) {
1981fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (prev) {
1982fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                prev->setNext(next);
1983fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else if (head == fHead) {
1984fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                fHead = next;
1985fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
1986fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                fTop = next;
1987fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
1988fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin);
1989fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
1990fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        prev = coin;
1991fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((coin = next));
1992fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
1993fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
1994fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
1995fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugRelease(SkPathOpsDebug::GlitchLog* log, const SkOpSegment* deleted) const {
1996fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* coin = fHead;
1997fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!coin) {
1998fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
1999fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2000fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2001fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (coin->coinPtTStart()->segment() == deleted
2002fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                || coin->coinPtTEnd()->segment() == deleted
2003fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                || coin->oppPtTStart()->segment() == deleted
2004fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                || coin->oppPtTEnd()->segment() == deleted) {
2005fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin);
2006fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2007fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((coin = coin->next()));
2008fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2009fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2010fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with expand()
2011fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// expand the range by checking adjacent spans for coincidence
2012fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpCoincidence::debugExpand(SkPathOpsDebug::GlitchLog* log) const {
2013fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* coin = fHead;
2014fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!coin) {
2015fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
2016fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2017fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool expanded = false;
2018fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2019fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (coin->debugExpand(log)) {
2020fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // check to see if multiple spans expanded so they are now identical
2021fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkCoincidentSpans* test = fHead;
2022fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            do {
2023fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (coin == test) {
2024fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    continue;
2025fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2026fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (coin->coinPtTStart() == test->coinPtTStart()
2027fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        && coin->oppPtTStart() == test->oppPtTStart()) {
2028fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, fHead, test->coinPtTStart());
2029fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
2030fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2031fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } while ((test = test->next()));
2032fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            expanded = true;
2033fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2034fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((coin = coin->next()));
2035fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return expanded;
2036fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2037fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2038fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with mark()
2039fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
2040fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugMark(SkPathOpsDebug::GlitchLog* log) const {
2041fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* coin = fHead;
2042fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!coin) {
2043fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2044fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2045fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2046fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_IF(!coin->coinPtTStartWritable()->span()->upCastable(), coin);
2047fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast();
2048fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         SkASSERT(start->deleted());
2049fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
2050fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         SkASSERT(end->deleted());
2051fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
2052fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         SkASSERT(oStart->deleted());
2053fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
2054fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         SkASSERT(oEnd->deleted());
2055fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool flipped = coin->flipped();
2056fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (flipped) {
2057fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkTSwap(oStart, oEnd);
2058fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2059fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /* coin and opp spans may not match up. Mark the ends, and then let the interior
2060fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot           get marked as many times as the spans allow */
2061fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        start->debugInsertCoincidence(log, oStart->upCast());
2062fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        end->debugInsertCoinEnd(log, oEnd);
2063fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* segment = start->segment();
2064fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* oSegment = oStart->segment();
2065fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* next = start;
2066fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* oNext = oStart;
2067fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool ordered;
2068fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        FAIL_IF(!coin->ordered(&ordered), coin);
2069fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((next = next->upCast()->next()) != end) {
2070fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FAIL_IF(!next->upCastable(), coin);
2071fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (next->upCast()->debugInsertCoincidence(log, oSegment, flipped, ordered), false) {
2072fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return;
2073fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2074fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2075fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while ((oNext = oNext->upCast()->next()) != oEnd) {
2076fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            FAIL_IF(!oNext->upCastable(), coin);
2077fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oNext->upCast()->debugInsertCoincidence(log, segment, flipped, ordered), false) {
2078fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return;
2079fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2080fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2081fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((coin = coin->next()));
2082fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
2083fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2084fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2085fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2086fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2087fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with markCollapsed()
2088fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugMarkCollapsed(SkPathOpsDebug::GlitchLog* log, const SkCoincidentSpans* coin, const SkOpPtT* test) const {
2089fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* head = coin;
2090fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (coin) {
2091fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (coin->collapsed(test)) {
2092fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
2093fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin);
2094fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2095fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
2096fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin);
2097fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2098fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->debugRelease(log, head, coin);
2099fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coin = coin->next();
2101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with markCollapsed()
2105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugMarkCollapsed(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* test) const {
2106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugMarkCollapsed(log, fHead, test);
2107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugMarkCollapsed(log, fTop, test);
2108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkCoincidentSpans::debugShow() const {
2112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("coinSpan - id=%d t=%1.9g tEnd=%1.9g\n", coinPtTStart()->segment()->debugID(),
2113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            coinPtTStart()->fT, coinPtTEnd()->fT);
2114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("coinSpan + id=%d t=%1.9g tEnd=%1.9g\n", oppPtTStart()->segment()->debugID(),
2115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            oppPtTStart()->fT, oppPtTEnd()->fT);
2116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugShowCoincidence() const {
2119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
2120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* span = fHead;
2121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (span) {
2122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        span->debugShow();
2123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        span = span->next();
2124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void DebugCheckBetween(const SkOpSpanBase* next, const SkOpSpanBase* end,
2130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double oStart, double oEnd, const SkOpSegment* oSegment,
2131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPathOpsDebug::GlitchLog* log) {
2132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(next != end);
2133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!next->contains(end) || log);
2134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (next->t() > end->t()) {
2135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTSwap(next, end);
2136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* ptT = next->ptT();
2139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int index = 0;
2140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool somethingBetween = false;
2141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
2142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++index;
2143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ptT = ptT->next();
2144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* checkPtT = next->ptT();
2145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT == checkPtT) {
2146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool looped = false;
2149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int check = 0; check < index; ++check) {
2150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if ((looped = checkPtT == ptT)) {
2151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    break;
2152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                checkPtT = checkPtT->next();
2154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (looped) {
2156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(0);
2157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT->deleted()) {
2160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
2161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT->segment() != oSegment) {
2163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
2164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            somethingBetween |= between(oStart, ptT->fT, oEnd);
2166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while (true);
2167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(somethingBetween);
2168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (next != end && (next = next->upCast()->next()));
2169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void DebugCheckOverlap(const SkCoincidentSpans* test, const SkCoincidentSpans* list,
2172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPathOpsDebug::GlitchLog* log) {
2173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!list) {
2174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* coinSeg = test->coinPtTStart()->segment();
2177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(coinSeg == test->coinPtTEnd()->segment());
2178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* oppSeg = test->oppPtTStart()->segment();
2179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(oppSeg == test->oppPtTEnd()->segment());
2180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(coinSeg != test->oppPtTStart()->segment());
2181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(double tcs = test->coinPtTStart()->fT);
2182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(0, tcs, 1));
2183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(double tce = test->coinPtTEnd()->fT);
2184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(0, tce, 1));
2185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(tcs < tce);
2186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double tos = test->oppPtTStart()->fT;
2187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(0, tos, 1));
2188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double toe = test->oppPtTEnd()->fT;
2189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(between(0, toe, 1));
2190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(tos != toe);
2191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (tos > toe) {
2192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTSwap(tos, toe);
2193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double lcs, lce, los, loe;
2196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (coinSeg == list->coinPtTStart()->segment()) {
2197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppSeg != list->oppPtTStart()->segment()) {
2198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
2199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            lcs = list->coinPtTStart()->fT;
2201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            lce = list->coinPtTEnd()->fT;
2202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            los = list->oppPtTStart()->fT;
2203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            loe = list->oppPtTEnd()->fT;
2204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (los > loe) {
2205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(los, loe);
2206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else if (coinSeg == list->oppPtTStart()->segment()) {
2208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (oppSeg != list->coinPtTStart()->segment()) {
2209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
2210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            lcs = list->oppPtTStart()->fT;
2212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            lce = list->oppPtTEnd()->fT;
2213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (lcs > lce) {
2214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkTSwap(lcs, lce);
2215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            los = list->coinPtTStart()->fT;
2217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            loe = list->coinPtTEnd()->fT;
2218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
2219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
2220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(tce < lcs || lce < tcs);
2222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(toe < los || loe < tos);
2223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((list = list->next()));
2224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void DebugCheckOverlapTop(const SkCoincidentSpans* head, const SkCoincidentSpans* opt,
2228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPathOpsDebug::GlitchLog* log) {
2229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // check for overlapping coincident spans
2230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* test = head;
2231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (test) {
2232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkCoincidentSpans* next = test->next();
2233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        DebugCheckOverlap(test, next, log);
2234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        DebugCheckOverlap(test, opt, log);
2235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        test = next;
2236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void DebugValidate(const SkCoincidentSpans* head, const SkCoincidentSpans* opt,
2240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPathOpsDebug::GlitchLog* log) {
2241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // look for pts inside coincident spans that are not inside the opposite spans
2242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* coin = head;
2243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (coin) {
2244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(SkOpCoincidence::Ordered(coin->coinPtTStart()->segment(),
2245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                coin->oppPtTStart()->segment()));
2246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(coin->coinPtTStart()->span()->ptT() == coin->coinPtTStart());
2247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(coin->coinPtTEnd()->span()->ptT() == coin->coinPtTEnd());
2248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(coin->oppPtTStart()->span()->ptT() == coin->oppPtTStart());
2249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(coin->oppPtTEnd()->span()->ptT() == coin->oppPtTEnd());
2250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coin = coin->next();
2251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugCheckOverlapTop(head, opt, log);
2253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugValidate() const {
2257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
2258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugValidate(fHead, fTop, nullptr);
2259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugValidate(fTop, nullptr, nullptr);
2260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void DebugCheckBetween(const SkCoincidentSpans* head, const SkCoincidentSpans* opt,
2265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPathOpsDebug::GlitchLog* log) {
2266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // look for pts inside coincident spans that are not inside the opposite spans
2267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* coin = head;
2268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (coin) {
2269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        DebugCheckBetween(coin->coinPtTStart()->span(), coin->coinPtTEnd()->span(),
2270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                coin->oppPtTStart()->fT, coin->oppPtTEnd()->fT, coin->oppPtTStart()->segment(),
2271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                log);
2272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        DebugCheckBetween(coin->oppPtTStart()->span(), coin->oppPtTEnd()->span(),
2273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                coin->coinPtTStart()->fT, coin->coinPtTEnd()->fT, coin->coinPtTStart()->segment(),
2274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                log);
2275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coin = coin->next();
2276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugCheckOverlapTop(head, opt, log);
2278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugCheckBetween() const {
2282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
2283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fGlobalState->debugCheckHealth()) {
2284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugCheckBetween(fHead, fTop, nullptr);
2287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugCheckBetween(fTop, nullptr, nullptr);
2288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpContour::debugCheckHealth(SkPathOpsDebug::GlitchLog* log) const {
2293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment = &fHead;
2294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        segment->debugCheckHealth(log);
2296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((segment = segment->next()));
2297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugCheckValid(SkPathOpsDebug::GlitchLog* log) const {
2300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_VALIDATE
2301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugValidate(fHead, fTop, log);
2302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DebugValidate(fTop, nullptr, log);
2303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpCoincidence::debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const {
2307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkCoincidentSpans* coin = fHead;
2308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!coin) {
2309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coin->debugCorrectEnds(log);
2313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((coin = coin->next()));
2314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// commmented-out lines keep this aligned with missingCoincidence()
2317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpContour::debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const {
2318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    SkASSERT(fCount > 0);
2319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment = &fHead;
2320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    bool result = false;
2321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (segment->debugMissingCoincidence(log), false) {
2323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//          result = true;
2324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        segment = segment->next();
2326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (segment);
2327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
2328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpContour::debugMoveMultiples(SkPathOpsDebug::GlitchLog* log) const {
2331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fCount > 0);
2332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment = &fHead;
2333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (segment->debugMoveMultiples(log), false) {
2335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
2336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((segment = segment->next()));
2338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
2339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpContour::debugMoveNearby(SkPathOpsDebug::GlitchLog* log) const {
2342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fCount > 0);
2343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSegment* segment = &fHead;
2344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        segment->debugMoveNearby(log);
2346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((segment = segment->next()));
2347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_ORDER
2351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugResetCoinT() const {
2352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDebugBaseIndex = -1;
2353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDebugBaseMin = 1;
2354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDebugBaseMax = -1;
2355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDebugLastIndex = -1;
2356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDebugLastMin = 1;
2357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDebugLastMax = -1;
2358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSegment::debugValidate() const {
2362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_ORDER
2363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
2364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* span = &fHead;
2365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
2366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            span->debugResetCoinT();
2367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while (!span->final() && (span = span->upCast()->next()));
2368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        span = &fHead;
2369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int index = 0;
2370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
2371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            span->debugSetCoinT(index++);
2372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while (!span->final() && (span = span->upCast()->next()));
2373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
2376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->globalState()->debugCheckHealth()) {
2377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_VALIDATE
2381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* span = &fHead;
2382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    double lastT = -1;
2383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* prev = nullptr;
2384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count = 0;
2385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int done = 0;
2386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!span->final()) {
2388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++count;
2389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            done += span->upCast()->done() ? 1 : 0;
2390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(span->segment() == this);
2392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!prev || prev->upCast()->next() == span);
2393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!prev || prev == span->prev());
2394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        prev = span;
2395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        double t = span->ptT()->fT;
2396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(lastT < t);
2397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        lastT = t;
2398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        span->debugValidate();
2399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (!span->final() && (span = span->upCast()->next()));
2400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(count == fCount);
2401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(done == fDoneCount);
2402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(count >= fDoneCount);
2403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(span->final());
2404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    span->debugValidate();
2405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with addOpp()
2411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::debugAddOpp(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* opp) const {
2412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
2413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!oppPrev) {
2414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugMergeMatches(log, opp);
2417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->ptT()->debugAddOpp(opp->ptT(), oppPrev);
2418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugCheckForCollapsedCoincidence(log);
2419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with checkForCollapsedCoincidence()
2422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog* log) const {
2423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpCoincidence* coins = this->globalState()->coincidence();
2424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (coins->isEmpty()) {
2425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// the insert above may have put both ends of a coincident run in the same span
2428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// for each coincident ptT in loop; see if its opposite in is also in the loop
2429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// this implementation is the motivation for marking that a ptT is referenced by a coincident span
2430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* head = this->ptT();
2431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* test = head;
2432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!test->coincident()) {
2434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
2435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coins->debugMarkCollapsed(log, test);
2437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((test = test->next()) != head);
2438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpSpanBase::debugCoinEndLoopCheck() const {
2442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int loop = 0;
2443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* next = this;
2444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpanBase* nextCoin;
2445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        nextCoin = next->fCoinEnd;
2447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin);
2448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int check = 1; check < loop - 1; ++check) {
2449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* checkCoin = this->fCoinEnd;
2450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* innerCoin = checkCoin;
2451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int inner = check + 1; inner < loop; ++inner) {
2452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                innerCoin = innerCoin->fCoinEnd;
2453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (checkCoin == innerCoin) {
2454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkDebugf("*** bad coincident end loop ***\n");
2455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return false;
2456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++loop;
2460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((next = nextCoin) && next != this);
2461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
2462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with insertCoinEnd()
2466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::debugInsertCoinEnd(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* coin) const {
2467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (containsCoinEnd(coin)) {
2468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         SkASSERT(coin->containsCoinEnd(this));
2469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
2472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//     SkASSERT(this != coin);
2473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    log->record(SkPathOpsDebug::kMarkCoinEnd_Glitch, this, coin);
2474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//     coin->fCoinEnd = this->fCoinEnd;
2475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//     this->fCoinEnd = coinNext;
2476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
2477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with mergeMatches()
2480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Look to see if pt-t linked list contains same segment more than once
2481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// if so, and if each pt-t is directly pointed to by spans in that segment,
2482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// merge them
2483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// keep the points, but remove spans so that the segment doesn't have 2 or more
2484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// spans pointing to the same pt-t loop at different loop elements
2485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::debugMergeMatches(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* opp) const {
2486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* test = &fPtT;
2487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* testNext;
2488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* stop = test;
2489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        testNext = test->next();
2491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (test->deleted()) {
2492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
2493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSpanBase* testBase = test->span();
2495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(testBase->ptT() == test);
2496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpSegment* segment = test->segment();
2497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (segment->done()) {
2498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            continue;
2499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* inner = opp->ptT();
2501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* innerStop = inner;
2502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        do {
2503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (inner->segment() != segment) {
2504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
2505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (inner->deleted()) {
2507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
2508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* innerBase = inner->span();
2510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(innerBase->ptT() == inner);
2511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // when the intersection is first detected, the span base is marked if there are
2512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // more than one point in the intersection.
2513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//            if (!innerBase->hasMultipleHint() && !testBase->hasMultipleHint()) {
2514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (!zero_or_one(inner->fT)) {
2515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    log->record(SkPathOpsDebug::kMergeMatches_Glitch, innerBase, test);
2516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
2517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkASSERT(inner->fT != test->fT);
2518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (!zero_or_one(test->fT)) {
2519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        log->record(SkPathOpsDebug::kMergeMatches_Glitch, testBase, inner);
2520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    } else {
2521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        log->record(SkPathOpsDebug::kMergeMatches_Glitch, segment);
2522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                        SkDEBUGCODE(testBase->debugSetDeleted());
2523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                        test->setDeleted();
2524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                        SkDEBUGCODE(innerBase->debugSetDeleted());
2525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//                        inner->setDeleted();
2526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
2527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG   // assert if another undeleted entry points to segment
2529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* debugInner = inner;
2530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                while ((debugInner = debugInner->next()) != innerStop) {
2531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (debugInner->segment() != segment) {
2532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        continue;
2533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
2534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (debugInner->deleted()) {
2535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        continue;
2536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
2537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkOPASSERT(0);
2538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//            }
2542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
2543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } while ((inner = inner->next()) != innerStop);
2544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((test = testNext) != stop);
2545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->debugCheckForCollapsedCoincidence(log);
2546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::debugResetCoinT() const {
2551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_ORDER
2552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = &fPtT;
2553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT->debugResetCoinT();
2555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT = ptT->next();
2556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (ptT != &fPtT);
2557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::debugSetCoinT(int index) const {
2561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_ORDER
2562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = &fPtT;
2563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!ptT->deleted()) {
2565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ptT->debugSetCoinT(index);
2566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT = ptT->next();
2568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (ptT != &fPtT);
2569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpSpan* SkOpSpanBase::debugStarter(SkOpSpanBase const** endPtr) const {
2573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* end = *endPtr;
2574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->segment() == end->segment());
2575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpanBase* result;
2576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (t() < end->t()) {
2577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result = this;
2578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
2579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result = end;
2580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *endPtr = this;
2581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result->upCast();
2583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpanBase::debugValidate() const {
2586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
2587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->globalState()->debugCheckHealth()) {
2588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_VALIDATE
2592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = &fPtT;
2593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(ptT->span() == this);
2594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//        SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt));
2596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT->debugValidate();
2597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT = ptT->next();
2598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (ptT != &fPtT);
2599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->debugCoinEndLoopCheck());
2600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!this->final()) {
2601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(this->upCast()->debugCoinLoopCheck());
2602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fFromAngle) {
2604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fFromAngle->debugValidate();
2605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!this->final() && this->upCast()->toAngle()) {
2607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->upCast()->toAngle()->debugValidate();
2608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpSpan::debugCoinLoopCheck() const {
2613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int loop = 0;
2614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpSpan* next = this;
2615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpSpan* nextCoin;
2616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        nextCoin = next->fCoincident;
2618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(nextCoin == this || nextCoin->fCoincident != nextCoin);
2619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int check = 1; check < loop - 1; ++check) {
2620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpan* checkCoin = this->fCoincident;
2621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpan* innerCoin = checkCoin;
2622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int inner = check + 1; inner < loop; ++inner) {
2623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                innerCoin = innerCoin->fCoincident;
2624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (checkCoin == innerCoin) {
2625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkDebugf("*** bad coincident loop ***\n");
2626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return false;
2627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++loop;
2631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((next = nextCoin) && next != this);
2632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
2633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with insertCoincidence() in header
2637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog* log, const SkOpSpan* coin) const {
2638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (containsCoincidence(coin)) {
2639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//         SkASSERT(coin->containsCoincidence(this));
2640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
2643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//     SkASSERT(this != coin);
2644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    log->record(SkPathOpsDebug::kMarkCoinStart_Glitch, this, coin);
2645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//     coin->fCoincident = this->fCoincident;
2646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//     this->fCoincident = coinNext;
2647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debugValidate();
2648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with insertCoincidence()
2651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog* log, const SkOpSegment* segment, bool flipped, bool ordered) const {
2652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->containsCoincidence(segment)) {
2653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* next = &fPtT;
2656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((next = next->next()) != &fPtT) {
2657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (next->segment() == segment) {
2658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpan* span;
2659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpSpanBase* base = next->span();
2660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!ordered) {
2661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpSpanBase* spanEnd = fNext->contains(segment)->span();
2662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT());
2663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!start->span()->upCastable(), this);
2664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                span = const_cast<SkOpSpan*>(start->span()->upCast());
2665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            else if (flipped) {
2667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                span = base->prev();
2668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!span, this);
2669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            else {
2671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                FAIL_IF(!base->upCastable(), this);
2672fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                span = base->upCast();
2673fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2674fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            log->record(SkPathOpsDebug::kMarkCoinInsert_Glitch, span);
2675fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
2676fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2677fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2678fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COIN
2679fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    log->record(SkPathOpsDebug::kMarkCoinMissing_Glitch, segment, this);
2680fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2681fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return;
2682fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2683fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2684fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2685fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// called only by test code
2686fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkIntersections::debugCoincidentUsed() const {
2687fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fIsCoincident[0]) {
2688fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(!fIsCoincident[1]);
2689fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return 0;
2690fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2691fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int count = 0;
2692fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(int count2 = 0;)
2693fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < fUsed; ++index) {
2694fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fIsCoincident[0] & (1 << index)) {
2695fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++count;
2696fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2697fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_DEBUG
2698fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fIsCoincident[1] & (1 << index)) {
2699fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            ++count2;
2700fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2701fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2702fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2703fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(count == count2);
2704fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return count;
2705fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2706fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2707fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOpContour.h"
2708fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2709fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Commented-out lines keep this in sync with addOpp()
2710fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpPtT::debugAddOpp(const SkOpPtT* opp, const SkOpPtT* oppPrev) const {
2711fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDEBUGCODE(const SkOpPtT* oldNext = this->fNext);
2712fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this != opp);
2713fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    this->fNext = opp;
2714fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(oppPrev != oldNext);
2715fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//    oppPrev->fNext = oldNext;
2716fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2717fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2718fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOpPtT::debugContains(const SkOpPtT* check) const {
2719fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this != check);
2720fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
2721fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int links = 0;
2722fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2723fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT = ptT->next();
2724fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT == check) {
2725fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return true;
2726fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2727fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++links;
2728fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* test = this;
2729fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int index = 0; index < links; ++index) {
2730fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT == test) {
2731fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
2732fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2733fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            test = test->next();
2734fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2735fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (true);
2736fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2737fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2738fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpPtT* SkOpPtT::debugContains(const SkOpSegment* check) const {
2739fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(this->segment() != check);
2740fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* ptT = this;
2741fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int links = 0;
2742fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2743fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ptT = ptT->next();
2744fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (ptT->segment() == check) {
2745fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return ptT;
2746fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2747fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ++links;
2748fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkOpPtT* test = this;
2749fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int index = 0; index < links; ++index) {
2750fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (ptT == test) {
2751fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return nullptr;
2752fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2753fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            test = test->next();
2754fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2755fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while (true);
2756fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2757fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2758fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpPtT* SkOpPtT::debugEnder(const SkOpPtT* end) const {
2759fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fT < end->fT ? end : this;
2760fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2761fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2762fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint SkOpPtT::debugLoopLimit(bool report) const {
2763fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int loop = 0;
2764fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkOpPtT* next = this;
2765fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    do {
2766fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int check = 1; check < loop - 1; ++check) {
2767fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* checkPtT = this->fNext;
2768fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkOpPtT* innerPtT = checkPtT;
2769fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int inner = check + 1; inner < loop; ++inner) {
2770fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                innerPtT = innerPtT->fNext;
2771fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (checkPtT == innerPtT) {
2772fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (report) {
2773fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        SkDebugf("*** bad ptT loop ***\n");
2774fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
2775fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return loop;
2776fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
2777fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
2778fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2779fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // there's nothing wrong with extremely large loop counts -- but this may appear to hang
2780fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // by taking a very long time to figure out that no loop entry is a duplicate
2781fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // -- and it's likely that a large loop count is indicative of a bug somewhere
2782fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (++loop > 1000) {
2783fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("*** loop count exceeds 1000 ***\n");
2784fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return 1000;
2785fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2786fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } while ((next = next->fNext) && next != this);
2787fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return 0;
2788fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2789fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2790fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst SkOpPtT* SkOpPtT::debugOppPrev(const SkOpPtT* opp) const {
2791fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return this->oppPrev(const_cast<SkOpPtT*>(opp));
2792fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2793fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2794fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpPtT::debugResetCoinT() const {
2795fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_ORDER
2796fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->segment()->debugResetCoinT();
2797fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2798fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2799fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2800fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpPtT::debugSetCoinT(int index) const {
2801fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE_ORDER
2802fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->segment()->debugSetCoinT(index, fT);
2803fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2804fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2805fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2806fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOpPtT::debugValidate() const {
2807fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_COINCIDENCE
2808fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (this->globalState()->debugCheckHealth()) {
2809fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2810fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2811fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2812fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_VALIDATE
2813fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkOpPhase phase = contour()->globalState()->phase();
2814fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (phase == SkOpPhase::kIntersecting || phase == SkOpPhase::kFixWinding) {
2815fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2816fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2817fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fNext);
2818fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fNext != this);
2819fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fNext->fNext);
2820fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(debugLoopLimit(false) == 0);
2821fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2822fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2823fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2824fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void output_scalar(SkScalar num) {
2825fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (num == (int) num) {
2826fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d", (int) num);
2827fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
2828fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkString str;
2829fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str.printf("%1.9g", num);
2830fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int width = (int) str.size();
2831fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* cStr = str.c_str();
2832fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (cStr[width - 1] == '0') {
2833fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            --width;
2834fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2835fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        str.resize(width);
2836fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%sf", str.c_str());
2837fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2838fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2839fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2840fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void output_points(const SkPoint* pts, int count) {
2841fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int index = 0; index < count; ++index) {
2842fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        output_scalar(pts[index].fX);
2843fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf(", ");
2844fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        output_scalar(pts[index].fY);
2845fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (index + 1 < count) {
2846fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf(", ");
2847fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2848fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2849fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2850fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2851fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void showPathContours(SkPath::RawIter& iter, const char* pathName) {
2852fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t verb;
2853fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint pts[4];
2854fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
2855fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        switch (verb) {
2856fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkPath::kMove_Verb:
2857fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf("    %s.moveTo(", pathName);
2858fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                output_points(&pts[0], 1);
2859fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf(");\n");
2860fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                continue;
2861fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkPath::kLine_Verb:
2862fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf("    %s.lineTo(", pathName);
2863fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                output_points(&pts[1], 1);
2864fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf(");\n");
2865fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2866fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkPath::kQuad_Verb:
2867fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf("    %s.quadTo(", pathName);
2868fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                output_points(&pts[1], 2);
2869fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf(");\n");
2870fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2871fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkPath::kConic_Verb:
2872fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf("    %s.conicTo(", pathName);
2873fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                output_points(&pts[1], 2);
2874fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf(", %1.9gf);\n", iter.conicWeight());
2875fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2876fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkPath::kCubic_Verb:
2877fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf("    %s.cubicTo(", pathName);
2878fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                output_points(&pts[1], 3);
2879fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf(");\n");
2880fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2881fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            case SkPath::kClose_Verb:
2882fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDebugf("    %s.close();\n", pathName);
2883fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                break;
2884fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            default:
2885fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkDEBUGFAIL("bad verb");
2886fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return;
2887fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2888fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2889fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2890fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2891fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const char* gFillTypeStr[] = {
2892fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kWinding_FillType",
2893fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kEvenOdd_FillType",
2894fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kInverseWinding_FillType",
2895fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    "kInverseEvenOdd_FillType"
2896fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
2897fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2898fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration) {
2899fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath::RawIter iter(path);
2900fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define SUPPORT_RECT_CONTOUR_DETECTION 0
2901fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SUPPORT_RECT_CONTOUR_DETECTION
2902fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int rectCount = path.isRectContours() ? path.rectContours(nullptr, nullptr) : 0;
2903fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (rectCount > 0) {
2904fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTDArray<SkRect> rects;
2905fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkTDArray<SkPath::Direction> directions;
2906fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rects.setCount(rectCount);
2907fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        directions.setCount(rectCount);
2908fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        path.rectContours(rects.begin(), directions.begin());
2909fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int contour = 0; contour < rectCount; ++contour) {
2910fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkRect& rect = rects[contour];
2911fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
2912fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
2913fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
2914fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
2915fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
2916fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2917fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
2918fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath::FillType fillType = path.getFillType();
2919fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
2920fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (includeDeclaration) {
2921fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("    SkPath %s;\n", name);
2922fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2923fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("    %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]);
2924fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    iter.setPath(path);
2925fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    showPathContours(iter, name);
2926fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2927fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2928fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if DEBUG_DUMP_VERIFY
2929fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkData.h"
2930fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkStream.h"
2931fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2932fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) {
2933fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDynamicMemoryWStream wStream;
2934fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path.dump(&wStream, force, dumpAsHex);
2935fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkData> data(wStream.detachAsData());
2936fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data());
2937fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2938fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2939fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int dumpID = 0;
2940fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2941fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
2942fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* testName) {
2943fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FILE* file = sk_fopen("op_dump.txt", kWrite_SkFILE_Flag);
2944fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DumpOp(file, one, two, op, testName);
2945fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2946fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2947fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
2948fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const char* testName) {
2949fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* name = testName ? testName : "op";
2950fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file,
2951fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
2952fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            name, ++dumpID);
2953fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    SkPath path;\n");
2954fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    path.setFillType((SkPath::FillType) %d);\n", one.getFillType());
2955fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    dump_path(file, one, false, true);
2956fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    SkPath path1(path);\n");
2957fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    path.reset();\n");
2958fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    path.setFillType((SkPath::FillType) %d);\n", two.getFillType());
2959fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    dump_path(file, two, false, true);
2960fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    SkPath path2(path);\n");
2961fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op);
2962fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "}\n\n");
2963fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fclose(file);
2964fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2965fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2966fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::DumpSimplify(const SkPath& path, const char* testName) {
2967fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FILE* file = sk_fopen("simplify_dump.txt", kWrite_SkFILE_Flag);
2968fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DumpSimplify(file, path, testName);
2969fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2970fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2971fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::DumpSimplify(FILE* file, const SkPath& path, const char* testName) {
2972fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* name = testName ? testName : "simplify";
2973fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file,
2974fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
2975fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            name, ++dumpID);
2976fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    SkPath path;\n");
2977fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    path.setFillType((SkPath::FillType) %d);\n", path.getFillType());
2978fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    dump_path(file, path, false, true);
2979fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "    testSimplify(reporter, path, filename);\n");
2980fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fprintf(file, "}\n\n");
2981fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fclose(file);
2982fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
2983fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2984fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBitmap.h"
2985fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkCanvas.h"
2986fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPaint.h"
2987fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2988fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst int bitWidth = 64;
2989fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotconst int bitHeight = 64;
2990fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
2991fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void debug_scale_matrix(const SkPath& one, const SkPath* two, SkMatrix& scale) {
2992fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect larger = one.getBounds();
2993fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (two) {
2994fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        larger.join(two->getBounds());
2995fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
2996fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar largerWidth = larger.width();
2997fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (largerWidth < 4) {
2998fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        largerWidth = 4;
2999fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
3000fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar largerHeight = larger.height();
3001fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (largerHeight < 4) {
3002fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        largerHeight = 4;
3003fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
3004fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar hScale = (bitWidth - 2) / largerWidth;
3005fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar vScale = (bitHeight - 2) / largerHeight;
3006fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scale.reset();
3007fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scale.preScale(hScale, vScale);
3008fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    larger.fLeft *= hScale;
3009fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    larger.fRight *= hScale;
3010fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    larger.fTop *= vScale;
3011fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    larger.fBottom *= vScale;
3012fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
3013fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            : 16000 < larger.fRight ? 16000 - larger.fRight : 0;
3014fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
3015fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
3016fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scale.preTranslate(dx, dy);
3017fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
3018fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
3019fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) {
3020fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (bits.width() == 0) {
3021fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bits.allocN32Pixels(bitWidth * 2, bitHeight);
3022fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
3023fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkCanvas canvas(bits);
3024fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.drawColor(SK_ColorWHITE);
3025fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint paint;
3026fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.save();
3027fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkRect& bounds1 = one.getBounds();
3028fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
3029fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.drawPath(one, paint);
3030fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.restore();
3031fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.save();
3032fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
3033fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.drawPath(two, paint);
3034fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas.restore();
3035fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int errors = 0;
3036fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int y = 0; y < bitHeight - 1; ++y) {
3037fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* addr1 = bits.getAddr32(0, y);
3038fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* addr2 = bits.getAddr32(0, y + 1);
3039fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* addr3 = bits.getAddr32(bitWidth, y);
3040fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
3041fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int x = 0; x < bitWidth - 1; ++x) {
3042fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            // count 2x2 blocks
3043fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            bool err = addr1[x] != addr3[x];
3044fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (err) {
3045fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                errors += addr1[x + 1] != addr3[x + 1]
3046fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
3047fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
3048fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
3049fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
3050fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return errors;
3051fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
3052fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
3053fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op) {
3054fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("// Op did not expect failure\n");
3055fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DumpOp(stderr, one, two, op, "opTest");
3056fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fflush(stderr);
3057fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
3058fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
3059fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op,
3060fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPath& result) {
3061fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath pathOut, scaledPathOut;
3062fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRegion rgnA, rgnB, openClip, rgnOut;
3063fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    openClip.setRect(-16000, -16000, 16000, 16000);
3064fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rgnA.setPath(one, openClip);
3065fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rgnB.setPath(two, openClip);
3066fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rgnOut.op(rgnA, rgnB, (SkRegion::Op) op);
3067fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rgnOut.getBoundaryPath(&pathOut);
3068fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMatrix scale;
3069fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debug_scale_matrix(one, &two, scale);
3070fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
3071fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath scaledA, scaledB;
3072fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledA.addPath(one, scale);
3073fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledA.setFillType(one.getFillType());
3074fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledB.addPath(two, scale);
3075fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledB.setFillType(two.getFillType());
3076fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledRgnA.setPath(scaledA, openClip);
3077fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledRgnB.setPath(scaledB, openClip);
3078fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op);
3079fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledRgnOut.getBoundaryPath(&scaledPathOut);
3080fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBitmap bitmap;
3081fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath scaledOut;
3082fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledOut.addPath(result, scale);
3083fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledOut.setFillType(result.getFillType());
3084fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
3085fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int MAX_ERRORS = 9;
3086fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (errors > MAX_ERRORS) {
3087fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fprintf(stderr, "// Op did not expect errors=%d\n", errors);
3088fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        DumpOp(stderr, one, two, op, "opTest");
3089fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fflush(stderr);
3090fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
3091fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
3092fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
3093fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::ReportSimplifyFail(const SkPath& path) {
3094fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("// Simplify did not expect failure\n");
3095fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    DumpSimplify(stderr, path, "simplifyTest");
3096fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fflush(stderr);
3097fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
3098fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
3099fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) {
3100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath pathOut, scaledPathOut;
3101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRegion rgnA, openClip, rgnOut;
3102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    openClip.setRect(-16000, -16000, 16000, 16000);
3103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rgnA.setPath(path, openClip);
3104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rgnOut.getBoundaryPath(&pathOut);
3105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMatrix scale;
3106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    debug_scale_matrix(path, nullptr, scale);
3107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRegion scaledRgnA;
3108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath scaledA;
3109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledA.addPath(path, scale);
3110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledA.setFillType(path.getFillType());
3111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledRgnA.setPath(scaledA, openClip);
3112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledRgnA.getBoundaryPath(&scaledPathOut);
3113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBitmap bitmap;
3114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath scaledOut;
3115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledOut.addPath(result, scale);
3116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    scaledOut.setFillType(result.getFillType());
3117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
3118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int MAX_ERRORS = 9;
3119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (errors > MAX_ERRORS) {
3120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fprintf(stderr, "// Simplify did not expect errors=%d\n", errors);
3121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        DumpSimplify(stderr, path, "simplifyTest");
3122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fflush(stderr);
3123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
3124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
3125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
3126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
3127