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