107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com/*
207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Copyright 2013 Google Inc.
307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com *
407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * found in the LICENSE file.
607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com */
707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
81b24933e52f50773de29332387a12721811f3012mtklein#include "SkMutex.h"
926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#include "SkOpCoincidence.h"
1026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#include "SkOpContour.h"
111326068147ee60de138061a3fc1157fcfd5d017bcaryclark#include "SkOSFile.h"
1202802f64ea0b1fc9223386328a95280b74092c94jvanverth#include "SkPath.h"
131b24933e52f50773de29332387a12721811f3012mtklein#include "SkPathOpsDebug.h"
1454359294a7c9dc54802d512a5d891a35c1663392caryclark#include "SkString.h"
1554359294a7c9dc54802d512a5d891a35c1663392caryclark
16918fb1fe6ff5349a2d1e5fb6872139f5fb931480Cary Clark#if DEBUG_DUMP_VERIFY
171326068147ee60de138061a3fc1157fcfd5d017bcaryclarkbool SkPathOpsDebug::gDumpOp;  // set to true to write op to file before a crash
181326068147ee60de138061a3fc1157fcfd5d017bcaryclarkbool SkPathOpsDebug::gVerifyOp;  // set to true to compare result against regions
191326068147ee60de138061a3fc1157fcfd5d017bcaryclark#endif
201326068147ee60de138061a3fc1157fcfd5d017bcaryclark
2159d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clarkbool SkPathOpsDebug::gRunFail;  // set to true to check for success on tests known to fail
221326068147ee60de138061a3fc1157fcfd5d017bcaryclarkbool SkPathOpsDebug::gVeryVerbose;  // set to true to run extensive checking tests
231326068147ee60de138061a3fc1157fcfd5d017bcaryclark
2430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#undef FAIL_IF
2530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#define FAIL_IF(cond, coin) \
26ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark         do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, coin); } while (false)
2730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark
2830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#undef FAIL_WITH_NULL_IF
2930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#define FAIL_WITH_NULL_IF(cond, span) \
30ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark         do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, span); } while (false)
3130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark
3230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#undef RETURN_FALSE_IF
3330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#define RETURN_FALSE_IF(cond, span) \
34ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark         do { if (cond) log->record(SkPathOpsDebug::kReturnFalse_Glitch, span); \
35ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark         } while (false)
3630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark
3755888e44171ffd48b591d19256884a969fe4da17caryclarkclass SkCoincidentSpans;
3826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
39624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#if DEBUG_SORT
40624637cc8ec22c000409704d0b403ac1b81ad4b0caryclarkint SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
41624637cc8ec22c000409704d0b403ac1b81ad4b0caryclarkint SkPathOpsDebug::gSortCount;
42624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#endif
43624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark
44624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#if DEBUG_ACTIVE_OP
45624637cc8ec22c000409704d0b403ac1b81ad4b0caryclarkconst char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"};
46624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#endif
47624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark
4807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#if defined SK_DEBUG || !FORCE_RELEASE
4907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
50570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comconst char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"};
518cb1daaa1e4343eb60a7c4f21c12e33de30dad64commit-bot@chromium.org
52fe41b8ffff3463a1b062c4fd7315b44e278ba390commit-bot@chromium.orgint SkPathOpsDebug::gContourID = 0;
53fe41b8ffff3463a1b062c4fd7315b44e278ba390commit-bot@chromium.orgint SkPathOpsDebug::gSegmentID = 0;
54570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
5554359294a7c9dc54802d512a5d891a35c1663392caryclarkbool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray,
5654359294a7c9dc54802d512a5d891a35c1663392caryclark        const SkOpSpanBase* span) {
574431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int index = 0; index < chaseArray.count(); ++index) {
5854359294a7c9dc54802d512a5d891a35c1663392caryclark        const SkOpSpanBase* entry = chaseArray[index];
594431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        if (entry == span) {
604431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            return true;
614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
634431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    return false;
644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
6526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
66ff11428526843d3e03feb6843bd21f2d80536415Cary Clark
67ff11428526843d3e03feb6843bd21f2d80536415Cary Clark#if DEBUG_ACTIVE_SPANS
68ff11428526843d3e03feb6843bd21f2d80536415Cary ClarkSkString SkPathOpsDebug::gActiveSpans;
69ff11428526843d3e03feb6843bd21f2d80536415Cary Clark#endif
7026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
71ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
7226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
73ab87d7abf1df007c90bef2e916294ca325d81c81Cary ClarkSkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumChangedDict;
74ab87d7abf1df007c90bef2e916294ca325d81c81Cary ClarkSkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumVisitedDict;
75ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
76ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkstatic const int kGlitchType_Count = SkPathOpsDebug::kUnalignedTail_Glitch + 1;
7726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
7826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkstruct SpanGlitch {
7926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpanBase* fBase;
8026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpanBase* fSuspect;
8126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSegment* fSegment;
8255888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSegment* fOppSegment;
8326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpPtT* fCoinSpan;
8426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpPtT* fEndSpan;
8526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpPtT* fOppSpan;
8626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpPtT* fOppEndSpan;
8755888e44171ffd48b591d19256884a969fe4da17caryclark    double fStartT;
8855888e44171ffd48b591d19256884a969fe4da17caryclark    double fEndT;
8955888e44171ffd48b591d19256884a969fe4da17caryclark    double fOppStartT;
9055888e44171ffd48b591d19256884a969fe4da17caryclark    double fOppEndT;
9126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkPoint fPt;
92ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkPathOpsDebug::GlitchType fType;
93ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
94ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void dumpType() const;
9526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark};
9626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
9726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkstruct SkPathOpsDebug::GlitchLog {
98ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void init(const SkOpGlobalState* state) {
99ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fGlobalState = state;
100ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
101ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
102ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SpanGlitch* recordCommon(GlitchType type) {
10326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SpanGlitch* glitch = fGlitches.push();
10426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fBase = nullptr;
10526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fSuspect = nullptr;
10626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fSegment = nullptr;
10755888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppSegment = nullptr;
10826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fCoinSpan = nullptr;
10926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fEndSpan = nullptr;
11026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fOppSpan = nullptr;
11126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fOppEndSpan = nullptr;
11255888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fStartT = SK_ScalarNaN;
11355888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fEndT = SK_ScalarNaN;
11455888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppStartT = SK_ScalarNaN;
11555888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppEndT = SK_ScalarNaN;
11626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fPt = { SK_ScalarNaN, SK_ScalarNaN };
11726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fType = type;
11826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        return glitch;
11926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
12026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
121ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpSpanBase* base,
12226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpanBase* suspect = NULL) {
123ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
12426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fBase = base;
12526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fSuspect = suspect;
12626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
12726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
128ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpSpanBase* base,
12955888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpPtT* ptT) {
130ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
13155888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fBase = base;
13255888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fCoinSpan = ptT;
13355888e44171ffd48b591d19256884a969fe4da17caryclark    }
13455888e44171ffd48b591d19256884a969fe4da17caryclark
135ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkCoincidentSpans* coin,
13655888e44171ffd48b591d19256884a969fe4da17caryclark            const SkCoincidentSpans* opp = NULL) {
137ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
13855888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fCoinSpan = coin->coinPtTStart();
13955888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fEndSpan = coin->coinPtTEnd();
14055888e44171ffd48b591d19256884a969fe4da17caryclark        if (opp) {
14155888e44171ffd48b591d19256884a969fe4da17caryclark            glitch->fOppSpan = opp->coinPtTStart();
14255888e44171ffd48b591d19256884a969fe4da17caryclark            glitch->fOppEndSpan = opp->coinPtTEnd();
14355888e44171ffd48b591d19256884a969fe4da17caryclark        }
14426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
14526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
146ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpSpanBase* base,
14726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSegment* seg, double t, SkPoint pt) {
148ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
14926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fBase = base;
15026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fSegment = seg;
15155888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fStartT = t;
15226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fPt = pt;
15326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
15426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
155ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpSpanBase* base, double t,
15626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkPoint pt) {
157ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
15826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fBase = base;
15955888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fStartT = t;
16026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fPt = pt;
16126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
16226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
163ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkCoincidentSpans* coin,
16426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpPtT* coinSpan, const SkOpPtT* endSpan) {
165ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
16655888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fCoinSpan = coin->coinPtTStart();
16755888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fEndSpan = coin->coinPtTEnd();
16826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fEndSpan = endSpan;
16955888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppSpan = coinSpan;
17055888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppEndSpan = endSpan;
17126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
17226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
173ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkCoincidentSpans* coin,
17455888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpSpanBase* base) {
175ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
17655888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fBase = base;
17755888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fCoinSpan = coin->coinPtTStart();
17855888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fEndSpan = coin->coinPtTEnd();
17926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
18026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
181ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpPtT* ptTS, const SkOpPtT* ptTE,
18226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpPtT* oPtTS, const SkOpPtT* oPtTE) {
183ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
18426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fCoinSpan = ptTS;
18526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fEndSpan = ptTE;
18626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fOppSpan = oPtTS;
18726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        glitch->fOppEndSpan = oPtTE;
18826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
18926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
190ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpSegment* seg, double startT,
19155888e44171ffd48b591d19256884a969fe4da17caryclark            double endT, const SkOpSegment* oppSeg, double oppStartT, double oppEndT) {
192ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
19355888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fSegment = seg;
19455888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fStartT = startT;
19555888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fEndT = endT;
19655888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppSegment = oppSeg;
19755888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppStartT = oppStartT;
19855888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fOppEndT = oppEndT;
19955888e44171ffd48b591d19256884a969fe4da17caryclark    }
20055888e44171ffd48b591d19256884a969fe4da17caryclark
201ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpSegment* seg,
20255888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpSpan* span) {
203ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
20455888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fSegment = seg;
20555888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fBase = span;
20655888e44171ffd48b591d19256884a969fe4da17caryclark    }
20755888e44171ffd48b591d19256884a969fe4da17caryclark
208ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, double t, const SkOpSpanBase* span) {
209ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
21055888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fStartT = t;
21155888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fBase = span;
21255888e44171ffd48b591d19256884a969fe4da17caryclark    }
21355888e44171ffd48b591d19256884a969fe4da17caryclark
214ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkOpSegment* seg) {
215ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
21655888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fSegment = seg;
21755888e44171ffd48b591d19256884a969fe4da17caryclark    }
21855888e44171ffd48b591d19256884a969fe4da17caryclark
219ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    void record(GlitchType type, const SkCoincidentSpans* coin,
22055888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpPtT* ptT) {
221ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SpanGlitch* glitch = recordCommon(type);
22255888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fCoinSpan = coin->coinPtTStart();
22355888e44171ffd48b591d19256884a969fe4da17caryclark        glitch->fEndSpan = ptT;
22455888e44171ffd48b591d19256884a969fe4da17caryclark    }
22555888e44171ffd48b591d19256884a969fe4da17caryclark
22626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkTDArray<SpanGlitch> fGlitches;
227ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpGlobalState* fGlobalState;
22826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark};
229ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
230ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
231ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkPathOpsDebug::CoinDict::add(const SkPathOpsDebug::CoinDict& dict) {
232ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    int count = dict.fDict.count();
233ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    for (int index = 0; index < count; ++index) {
234ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        this->add(dict.fDict[index]);
235ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
236ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
237ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
238ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkPathOpsDebug::CoinDict::add(const CoinDictEntry& key) {
239ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    int count = fDict.count();
240ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    for (int index = 0; index < count; ++index) {
241ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        CoinDictEntry* entry = &fDict[index];
242ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (entry->fIteration == key.fIteration && entry->fLineNumber == key.fLineNumber) {
243ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            SkASSERT(!strcmp(entry->fFunctionName, key.fFunctionName));
244ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (entry->fGlitchType == kUninitialized_Glitch) {
245ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                entry->fGlitchType = key.fGlitchType;
246ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
247ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            return;
248ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
249ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
250ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    *fDict.append() = key;
251ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
252ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
253ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
254ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
255ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
256ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkstatic void missing_coincidence(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) {
257ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpContour* contour = contourList;
258ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    // bool result = false;
259ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    do {
260ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        /* result |= */ contour->debugMissingCoincidence(glitches);
261ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((contour = contour->next()));
262ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return;
263ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
264ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
265ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkstatic void move_multiples(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) {
266ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpContour* contour = contourList;
267ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    do {
268ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (contour->debugMoveMultiples(glitches), false) {
269ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            return;
270ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
271ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((contour = contour->next()));
272ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return;
273ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
274ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
275ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkstatic void move_nearby(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) {
276ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpContour* contour = contourList;
277ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    do {
278ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        contour->debugMoveNearby(glitches);
279ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((contour = contour->next()));
280ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
281ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
282ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
283ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
284ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
285ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
286ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpGlobalState::debugAddToCoinChangedDict() {
287ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
288ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COINCIDENCE
289e6522ea38fa3bcfdf2d718ea5ad898b3b3d46e00caryclark    SkPathOpsDebug::CheckHealth(fContourHead);
290ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
291ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    // see if next coincident operation makes a change; if so, record it
292ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkPathOpsDebug::GlitchLog glitches;
293ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const char* funcName = fCoinDictEntry.fFunctionName;
294ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (!strcmp("calc_angles", funcName)) {
295ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        ;
296ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("missing_coincidence", funcName)) {
297ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        missing_coincidence(&glitches, fContourHead);
298ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("move_multiples", funcName)) {
299ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        move_multiples(&glitches, fContourHead);
300ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("move_nearby", funcName)) {
301ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        move_nearby(&glitches, fContourHead);
302ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("addExpanded", funcName)) {
303ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fCoincidence->debugAddExpanded(&glitches);
304ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("addMissing", funcName)) {
305ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        bool added;
306ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fCoincidence->debugAddMissing(&glitches, &added);
307ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("addEndMovedSpans", funcName)) {
308ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fCoincidence->debugAddEndMovedSpans(&glitches);
309ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("correctEnds", funcName)) {
310ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fCoincidence->debugCorrectEnds(&glitches);
311ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("expand", funcName)) {
312ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fCoincidence->debugExpand(&glitches);
313ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("findOverlaps", funcName)) {
314ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        ;
315ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("mark", funcName)) {
316ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fCoincidence->debugMark(&glitches);
317ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else if (!strcmp("apply", funcName)) {
318ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        ;
319ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } else {
320ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkASSERT(0);   // add missing case
321ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
322ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (glitches.fGlitches.count()) {
323ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        fCoinDictEntry.fGlitchType = glitches.fGlitches[0].fType;
324ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
325ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    fCoinChangedDict.add(fCoinDictEntry);
326ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
32755888e44171ffd48b591d19256884a969fe4da17caryclark#endif
32826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
32955888e44171ffd48b591d19256884a969fe4da17caryclarkvoid SkPathOpsDebug::ShowActiveSpans(SkOpContourHead* contourList) {
33055888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_ACTIVE_SPANS
331ff11428526843d3e03feb6843bd21f2d80536415Cary Clark    SkString str;
33255888e44171ffd48b591d19256884a969fe4da17caryclark    SkOpContour* contour = contourList;
33355888e44171ffd48b591d19256884a969fe4da17caryclark    do {
334ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        contour->debugShowActiveSpans(&str);
33555888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((contour = contour->next()));
336ff11428526843d3e03feb6843bd21f2d80536415Cary Clark    if (!gActiveSpans.equals(str)) {
337ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        const char* s = str.c_str();
338ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        const char* end;
339ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        while ((end = strchr(s, '\n'))) {
340ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            SkDebugf("%.*s", end - s + 1, s);
341ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            s = end + 1;
342ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        }
343ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        gActiveSpans.set(str);
344ff11428526843d3e03feb6843bd21f2d80536415Cary Clark    }
34555888e44171ffd48b591d19256884a969fe4da17caryclark#endif
34655888e44171ffd48b591d19256884a969fe4da17caryclark}
34755888e44171ffd48b591d19256884a969fe4da17caryclark
348ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COINCIDENCE || DEBUG_COIN
349ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList) {
35055888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
35155888e44171ffd48b591d19256884a969fe4da17caryclark    contourList->globalState()->debugSetCheckHealth(true);
352ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
353ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
35426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    GlitchLog glitches;
35526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpContour* contour = contourList;
35626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpCoincidence* coincidence = contour->globalState()->coincidence();
357ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    coincidence->debugCheckValid(&glitches); // don't call validate; spans may be inconsistent
35826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
359ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        contour->debugCheckHealth(&glitches);
360ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        contour->debugMissingCoincidence(&glitches);
36126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    } while ((contour = contour->next()));
36281a478ca6c36aac3e53ce0373a281ac8940f4780caryclark    bool added;
363ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    coincidence->debugAddMissing(&glitches, &added);
364ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    coincidence->debugExpand(&glitches);
365ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    coincidence->debugAddExpanded(&glitches);
366ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    coincidence->debugMark(&glitches);
36726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    unsigned mask = 0;
36826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    for (int index = 0; index < glitches.fGlitches.count(); ++index) {
36926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SpanGlitch& glitch = glitches.fGlitches[index];
37026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        mask |= 1 << glitch.fType;
37126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
37226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    for (int index = 0; index < kGlitchType_Count; ++index) {
37326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkDebugf(mask & (1 << index) ? "x" : "-");
37426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
375ff11428526843d3e03feb6843bd21f2d80536415Cary Clark    SkDebugf(" %s\n", contourList->globalState()->debugCoinDictEntry().fFunctionName);
37655888e44171ffd48b591d19256884a969fe4da17caryclark    for (int index = 0; index < glitches.fGlitches.count(); ++index) {
37755888e44171ffd48b591d19256884a969fe4da17caryclark        const SpanGlitch& glitch = glitches.fGlitches[index];
37855888e44171ffd48b591d19256884a969fe4da17caryclark        SkDebugf("%02d: ", index);
37955888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fBase) {
3808016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkDebugf(" seg/base=%d/%d", glitch.fBase->segment()->debugID(),
3818016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                    glitch.fBase->debugID());
38255888e44171ffd48b591d19256884a969fe4da17caryclark        }
38355888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fSuspect) {
3848016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkDebugf(" seg/base=%d/%d", glitch.fSuspect->segment()->debugID(),
3858016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                    glitch.fSuspect->debugID());
38655888e44171ffd48b591d19256884a969fe4da17caryclark        }
38755888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fSegment) {
38855888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" segment=%d", glitch.fSegment->debugID());
38955888e44171ffd48b591d19256884a969fe4da17caryclark        }
39055888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fCoinSpan) {
3918016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkDebugf(" coinSeg/Span/PtT=%d/%d/%d", glitch.fCoinSpan->segment()->debugID(),
3928016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                    glitch.fCoinSpan->span()->debugID(), glitch.fCoinSpan->debugID());
39355888e44171ffd48b591d19256884a969fe4da17caryclark        }
39455888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fEndSpan) {
39555888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" endSpan=%d", glitch.fEndSpan->debugID());
39655888e44171ffd48b591d19256884a969fe4da17caryclark        }
39755888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fOppSpan) {
3988016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkDebugf(" oppSeg/Span/PtT=%d/%d/%d", glitch.fOppSpan->segment()->debugID(),
3998016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                    glitch.fOppSpan->span()->debugID(), glitch.fOppSpan->debugID());
40055888e44171ffd48b591d19256884a969fe4da17caryclark        }
40155888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fOppEndSpan) {
40255888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" oppEndSpan=%d", glitch.fOppEndSpan->debugID());
40355888e44171ffd48b591d19256884a969fe4da17caryclark        }
40455888e44171ffd48b591d19256884a969fe4da17caryclark        if (!SkScalarIsNaN(glitch.fStartT)) {
40555888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" startT=%g", glitch.fStartT);
40655888e44171ffd48b591d19256884a969fe4da17caryclark        }
40755888e44171ffd48b591d19256884a969fe4da17caryclark        if (!SkScalarIsNaN(glitch.fEndT)) {
40855888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" endT=%g", glitch.fEndT);
40955888e44171ffd48b591d19256884a969fe4da17caryclark        }
41055888e44171ffd48b591d19256884a969fe4da17caryclark        if (glitch.fOppSegment) {
41155888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" segment=%d", glitch.fOppSegment->debugID());
41255888e44171ffd48b591d19256884a969fe4da17caryclark        }
41355888e44171ffd48b591d19256884a969fe4da17caryclark        if (!SkScalarIsNaN(glitch.fOppStartT)) {
41455888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" oppStartT=%g", glitch.fOppStartT);
41555888e44171ffd48b591d19256884a969fe4da17caryclark        }
41655888e44171ffd48b591d19256884a969fe4da17caryclark        if (!SkScalarIsNaN(glitch.fOppEndT)) {
41755888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" oppEndT=%g", glitch.fOppEndT);
41855888e44171ffd48b591d19256884a969fe4da17caryclark        }
41955888e44171ffd48b591d19256884a969fe4da17caryclark        if (!SkScalarIsNaN(glitch.fPt.fX) || !SkScalarIsNaN(glitch.fPt.fY)) {
42055888e44171ffd48b591d19256884a969fe4da17caryclark            SkDebugf(" pt=%g,%g", glitch.fPt.fX, glitch.fPt.fY);
42155888e44171ffd48b591d19256884a969fe4da17caryclark        }
422ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        DumpGlitchType(glitch.fType);
42355888e44171ffd48b591d19256884a969fe4da17caryclark        SkDebugf("\n");
42455888e44171ffd48b591d19256884a969fe4da17caryclark    }
425ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COINCIDENCE
42655888e44171ffd48b591d19256884a969fe4da17caryclark    contourList->globalState()->debugSetCheckHealth(false);
427ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
4286c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark#if 01 && DEBUG_ACTIVE_SPANS
429ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark//    SkDebugf("active after %s:\n", id);
43055888e44171ffd48b591d19256884a969fe4da17caryclark    ShowActiveSpans(contourList);
43155888e44171ffd48b591d19256884a969fe4da17caryclark#endif
43255888e44171ffd48b591d19256884a969fe4da17caryclark#endif
43326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
43426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
4354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
436ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
437ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkPathOpsDebug::DumpGlitchType(GlitchType glitchType) {
438ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    switch (glitchType) {
439ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddCorruptCoin_Glitch: SkDebugf(" AddCorruptCoin"); break;
440ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddExpandedCoin_Glitch: SkDebugf(" AddExpandedCoin"); break;
441ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddExpandedFail_Glitch: SkDebugf(" AddExpandedFail"); break;
442ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddIfCollapsed_Glitch: SkDebugf(" AddIfCollapsed"); break;; break;
443ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddIfMissingCoin_Glitch: SkDebugf(" AddIfMissingCoin"); break;
444ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddMissingCoin_Glitch: SkDebugf(" AddMissingCoin"); break;
445ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddMissingExtend_Glitch: SkDebugf(" AddMissingExtend"); break;
446ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kAddOrOverlap_Glitch: SkDebugf(" AAddOrOverlap"); break;
447ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kCollapsedCoin_Glitch: SkDebugf(" CollapsedCoin"); break;
448ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kCollapsedDone_Glitch: SkDebugf(" CollapsedDone"); break;
449ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kCollapsedOppValue_Glitch: SkDebugf(" CollapsedOppValue"); break;
450ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kCollapsedSpan_Glitch: SkDebugf(" CollapsedSpan"); break;
451ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kCollapsedWindValue_Glitch: SkDebugf(" CollapsedWindValue"); break;
452ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kCorrectEnd_Glitch: SkDebugf(" CorrectEnd"); break;
453ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kDeletedCoin_Glitch: SkDebugf(" DeletedCoin"); break;
454ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kExpandCoin_Glitch: SkDebugf(" ExpandCoin"); break;
455ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kFail_Glitch: SkDebugf(" Fail"); break;
456ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMarkCoinEnd_Glitch: SkDebugf(" MarkCoinEnd"); break;
457ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMarkCoinInsert_Glitch: SkDebugf(" MarkCoinInsert"); break;
458ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMarkCoinMissing_Glitch: SkDebugf(" MarkCoinMissing"); break;
459ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMarkCoinStart_Glitch: SkDebugf(" MarkCoinStart"); break;
460ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMergeMatches_Glitch: SkDebugf(" MergeMatches"); break;
461ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMissingCoin_Glitch: SkDebugf(" MissingCoin"); break;
462ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMissingDone_Glitch: SkDebugf(" MissingDone"); break;
463ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMissingIntersection_Glitch: SkDebugf(" MissingIntersection"); break;
464ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMoveMultiple_Glitch: SkDebugf(" MoveMultiple"); break;
465ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMoveNearbyClearAll_Glitch: SkDebugf(" MoveNearbyClearAll"); break;
466ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMoveNearbyClearAll2_Glitch: SkDebugf(" MoveNearbyClearAll2"); break;
467ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMoveNearbyMerge_Glitch: SkDebugf(" MoveNearbyMerge"); break;
468ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMoveNearbyMergeFinal_Glitch: SkDebugf(" MoveNearbyMergeFinal"); break;
469ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMoveNearbyRelease_Glitch: SkDebugf(" MoveNearbyRelease"); break;
470ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kMoveNearbyReleaseFinal_Glitch: SkDebugf(" MoveNearbyReleaseFinal"); break;
471ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kReleasedSpan_Glitch: SkDebugf(" ReleasedSpan"); break;
472ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kReturnFalse_Glitch: SkDebugf(" ReturnFalse"); break;
473ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kUnaligned_Glitch: SkDebugf(" Unaligned"); break;
474ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kUnalignedHead_Glitch: SkDebugf(" UnalignedHead"); break;
475ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kUnalignedTail_Glitch: SkDebugf(" UnalignedTail"); break;
476ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        case kUninitialized_Glitch: break;
477ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        default: SkASSERT(0);
478ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
479ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
480ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
481ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
48226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#if defined SK_DEBUG || !FORCE_RELEASE
483570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) {
48407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    size_t len = strlen(str);
48507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool num = false;
48607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    for (size_t idx = 0; idx < len; ++idx) {
48707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (num && str[idx] == 'e') {
48807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            if (len + 2 >= bufferLen) {
48907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                return;
49007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            }
49107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            memmove(&str[idx + 2], &str[idx + 1], len - idx);
49207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            str[idx] = '*';
49307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            str[idx + 1] = '^';
49407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            ++len;
49507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
49607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        num = str[idx] >= '0' && str[idx] <= '9';
49707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
49807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
49907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
500570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.combool SkPathOpsDebug::ValidWind(int wind) {
50107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF;
50207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
50307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
504570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkPathOpsDebug::WindingPrintf(int wind) {
50507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    if (wind == SK_MinS32) {
50607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDebugf("?");
50707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    } else {
50807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SkDebugf("%d", wind);
50907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
51007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com}
51154359294a7c9dc54802d512a5d891a35c1663392caryclark#endif //  defined SK_DEBUG || !FORCE_RELEASE
51254359294a7c9dc54802d512a5d891a35c1663392caryclark
513a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com
51407e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com#if DEBUG_SHOW_TEST_NAME
515385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanaryvoid* SkPathOpsDebug::CreateNameStr() { return new char[DEBUG_FILENAME_STRING_LENGTH]; }
516cffbcc3b9665f2c928544b6fc6b8a0e22a4210fbcaryclark@google.com
517385fe4d4b62d7d1dd76116dd570df3290a2f487bhalcanaryvoid SkPathOpsDebug::DeleteNameStr(void* v) { delete[] reinterpret_cast<char*>(v); }
518a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com
519570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.comvoid SkPathOpsDebug::BumpTestName(char* test) {
52007e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    char* num = test + strlen(test);
52107e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    while (num[-1] >= '0' && num[-1] <= '9') {
52207e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com        --num;
52307e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    }
52407e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    if (num[0] == '\0') {
52507e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com        return;
52607e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    }
52707e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    int dec = atoi(num);
52807e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    if (dec == 0) {
52907e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com        return;
53007e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    }
53107e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    ++dec;
53207e97fccd2d85076cd22ef411b0773ab92a18abecaryclark@google.com    SK_SNPRINTF(num, DEBUG_FILENAME_STRING_LENGTH - (num - test), "%d", dec);
533a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com}
534a5e55925ea03e76885804bda77408a1d6f04c335caryclark@google.com#endif
535570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
5361049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkstatic void show_function_header(const char* functionName) {
5371049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName);
5381049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    if (strcmp("skphealth_com76", functionName) == 0) {
5391049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkDebugf("found it\n");
5401049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    }
5411049f1246e7be4ccb68001361efceb8933e6f81ccaryclark}
5421049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
5431049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkstatic const char* gOpStrs[] = {
5441049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kDifference_SkPathOp",
5451049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kIntersect_SkPathOp",
5461049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kUnion_SkPathOp",
54755888e44171ffd48b591d19256884a969fe4da17caryclark    "kXOR_PathOp",
5481049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kReverseDifference_SkPathOp",
5491049f1246e7be4ccb68001361efceb8933e6f81ccaryclark};
5501049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
55103b03cad01628146bbb8d4f33c073bd0c77ee558caryclarkconst char* SkPathOpsDebug::OpStr(SkPathOp op) {
55203b03cad01628146bbb8d4f33c073bd0c77ee558caryclark    return gOpStrs[op];
55303b03cad01628146bbb8d4f33c073bd0c77ee558caryclark}
55403b03cad01628146bbb8d4f33c073bd0c77ee558caryclark
5551049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkstatic void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) {
5561049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkDebugf("    testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]);
5571049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkDebugf("}\n");
5581049f1246e7be4ccb68001361efceb8933e6f81ccaryclark}
5591049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
560086eea93b1f8253420c233c33cdabc0e74b08091reedSK_DECLARE_STATIC_MUTEX(gTestMutex);
5611049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
5621049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkvoid SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp,
5631049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        const char* testName) {
5641049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkAutoMutexAcquire ac(gTestMutex);
5651049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    show_function_header(testName);
5661049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    ShowOnePath(a, "path", true);
5671049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    ShowOnePath(b, "pathB", true);
5681049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    show_op(shapeOp, "path", "pathB");
5694431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
5704431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
57127c8eb8ffd7e221693d840c2b9279d53fe6f03d4caryclark#include "SkPathOpsTypes.h"
57226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#include "SkIntersectionHelper.h"
57326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#include "SkIntersections.h"
57426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
575ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
576ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
577ab87d7abf1df007c90bef2e916294ca325d81c81Cary ClarkSK_DECLARE_STATIC_MUTEX(gCoinDictMutex);
578ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
579ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpGlobalState::debugAddToGlobalCoinDicts() {
580ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkAutoMutexAcquire ac(&gCoinDictMutex);
581ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkPathOpsDebug::gCoinSumChangedDict.add(fCoinChangedDict);
582ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkPathOpsDebug::gCoinSumVisitedDict.add(fCoinVisitedDict);
583ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
584ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
585ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
586ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
58726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#if DEBUG_T_SECT_LOOP_COUNT
58826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkOpGlobalState::debugAddLoopCount(SkIntersections* i, const SkIntersectionHelper& wt,
58926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkIntersectionHelper& wn) {
59026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) {
59126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkIntersections::DebugLoop looper = (SkIntersections::DebugLoop) index;
59226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (fDebugLoopCount[index] >= i->debugLoopCount(looper)) {
59326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            continue;
59426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
59526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugLoopCount[index] = i->debugLoopCount(looper);
59626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstVerb[index * 2] = wt.segment()->verb();
59726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstVerb[index * 2 + 1] = wn.segment()->verb();
59826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        sk_bzero(&fDebugWorstPts[index * 8], sizeof(SkPoint) * 8);
59926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        memcpy(&fDebugWorstPts[index * 2 * 4], wt.pts(),
60026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                (SkPathOpsVerbToPoints(wt.segment()->verb()) + 1) * sizeof(SkPoint));
60126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        memcpy(&fDebugWorstPts[(index * 2 + 1) * 4], wn.pts(),
60226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                (SkPathOpsVerbToPoints(wn.segment()->verb()) + 1) * sizeof(SkPoint));
60326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstWeight[index * 2] = wt.weight();
60426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstWeight[index * 2 + 1] = wn.weight();
60526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
60626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    i->debugResetLoopCount();
60726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
60826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
60926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkOpGlobalState::debugDoYourWorst(SkOpGlobalState* local) {
61026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) {
61126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (fDebugLoopCount[index] >= local->fDebugLoopCount[index]) {
61226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            continue;
61326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
61426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugLoopCount[index] = local->fDebugLoopCount[index];
61526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstVerb[index * 2] = local->fDebugWorstVerb[index * 2];
61626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstVerb[index * 2 + 1] = local->fDebugWorstVerb[index * 2 + 1];
61726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        memcpy(&fDebugWorstPts[index * 2 * 4], &local->fDebugWorstPts[index * 2 * 4],
61826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                sizeof(SkPoint) * 8);
61926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstWeight[index * 2] = local->fDebugWorstWeight[index * 2];
62026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        fDebugWorstWeight[index * 2 + 1] = local->fDebugWorstWeight[index * 2 + 1];
62126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
62226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    local->debugResetLoopCounts();
62326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
62426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
62526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkstatic void dump_curve(SkPath::Verb verb, const SkPoint& pts, float weight) {
62626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (!verb) {
62726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        return;
62826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
62926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const char* verbs[] = { "", "line", "quad", "conic", "cubic" };
63026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkDebugf("%s: {{", verbs[verb]);
63126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    int ptCount = SkPathOpsVerbToPoints(verb);
63226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    for (int index = 0; index <= ptCount; ++index) {
63326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkDPoint::Dump((&pts)[index]);
63426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (index < ptCount - 1) {
63526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf(", ");
63626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
63726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
63826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkDebugf("}");
63926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (weight != 1) {
64026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkDebugf(", ");
64126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (weight == floorf(weight)) {
64226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%.0f", weight);
64326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        } else {
64426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%1.9gf", weight);
64526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
64626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
64726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkDebugf("}\n");
64826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
64926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
65026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkOpGlobalState::debugLoopReport() {
65126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const char* loops[] = { "iterations", "coinChecks", "perpCalcs" };
65226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkDebugf("\n");
65326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) {
65426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkDebugf("%s: %d\n", loops[index], fDebugLoopCount[index]);
65526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        dump_curve(fDebugWorstVerb[index * 2], fDebugWorstPts[index * 2 * 4],
65626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                fDebugWorstWeight[index * 2]);
65726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        dump_curve(fDebugWorstVerb[index * 2 + 1], fDebugWorstPts[(index * 2 + 1) * 4],
65826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                fDebugWorstWeight[index * 2 + 1]);
65926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
66026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
66126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
66226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkOpGlobalState::debugResetLoopCounts() {
66326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount));
66426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    sk_bzero(fDebugWorstVerb, sizeof(fDebugWorstVerb));
66526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    sk_bzero(fDebugWorstPts, sizeof(fDebugWorstPts));
66626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    sk_bzero(fDebugWorstWeight, sizeof(fDebugWorstWeight));
66726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
66826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
66927c8eb8ffd7e221693d840c2b9279d53fe6f03d4caryclark
67059d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clarkbool SkOpGlobalState::DebugRunFail() {
67159d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clark    return SkPathOpsDebug::gRunFail;
67259d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clark}
67359d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clark
674ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark// this is const so it can be called by const methods that overwise don't alter state
675ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_VALIDATE || DEBUG_COIN
676ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpGlobalState::debugSetPhase(const char* funcName  DEBUG_COIN_DECLARE_PARAMS()) const {
677ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    auto writable = const_cast<SkOpGlobalState*>(this);
678ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_VALIDATE
679ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    writable->setPhase(phase);
680ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
681ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
682ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkPathOpsDebug::CoinDictEntry* entry = &writable->fCoinDictEntry;
683ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    writable->fPreviousFuncName = entry->fFunctionName;
684ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    entry->fIteration = iteration;
685ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    entry->fLineNumber = lineNo;
686ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    entry->fGlitchType = SkPathOpsDebug::kUninitialized_Glitch;
687ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    entry->fFunctionName = funcName;
688ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    writable->fCoinVisitedDict.add(*entry);
689ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    writable->debugAddToCoinChangedDict();
690ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
691ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
692ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#endif
693ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
69426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#if DEBUG_T_SECT_LOOP_COUNT
69526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkIntersections::debugBumpLoopCount(DebugLoop index) {
69626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    fDebugLoopCount[index]++;
69726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
69826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
69926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkint SkIntersections::debugLoopCount(DebugLoop index) const {
70026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    return fDebugLoopCount[index];
70126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
70226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
70326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkIntersections::debugResetLoopCount() {
70426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount));
70526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
70626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
70726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
708a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark#include "SkPathOpsConic.h"
709624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#include "SkPathOpsCubic.h"
710624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark
711624637cc8ec22c000409704d0b403ac1b81ad4b0caryclarkSkDCubic SkDQuad::debugToCubic() const {
712624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    SkDCubic cubic;
713624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    cubic[0] = fPts[0];
714624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    cubic[2] = fPts[1];
715624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    cubic[3] = fPts[2];
716624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3;
717624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3;
718624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3;
719624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    cubic[2].fY = (cubic[3].fY + cubic[2].fY * 2) / 3;
720624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    return cubic;
721624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark}
722624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark
723a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclarkvoid SkDQuad::debugSet(const SkDPoint* pts) {
724a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark    memcpy(fPts, pts, sizeof(fPts));
725a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark    SkDEBUGCODE(fDebugGlobalState = nullptr);
726a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark}
727a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark
728a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclarkvoid SkDCubic::debugSet(const SkDPoint* pts) {
729a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark    memcpy(fPts, pts, sizeof(fPts));
730a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark    SkDEBUGCODE(fDebugGlobalState = nullptr);
731a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark}
732a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark
733a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclarkvoid SkDConic::debugSet(const SkDPoint* pts, SkScalar weight) {
734a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark    fPts.debugSet(pts);
735a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark    fWeight = weight;
736a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark}
737a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark
738ed0935a28a29af7d3b16ac8d9365f291a335c6bdcaryclarkvoid SkDRect::debugInit() {
739ed0935a28a29af7d3b16ac8d9365f291a335c6bdcaryclark    fLeft = fTop = fRight = fBottom = SK_ScalarNaN;
740ed0935a28a29af7d3b16ac8d9365f291a335c6bdcaryclark}
741ed0935a28a29af7d3b16ac8d9365f291a335c6bdcaryclark
7424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#include "SkOpAngle.h"
743570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com#include "SkOpSegment.h"
744570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
745ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
74655888e44171ffd48b591d19256884a969fe4da17caryclark// commented-out lines keep this in sync with addT()
747ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark const SkOpPtT* SkOpSegment::debugAddT(double t, SkPathOpsDebug::GlitchLog* log) const {
74855888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
74955888e44171ffd48b591d19256884a969fe4da17caryclark    SkPoint pt = this->ptAtT(t);
75055888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSpanBase* span = &fHead;
75126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
75255888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* result = span->ptT();
75329b2563afb1677515739f1d24fb27733626eca92caryclark        if (t == result->fT || this->match(result, this, t, pt)) {
75455888e44171ffd48b591d19256884a969fe4da17caryclark//             span->bumpSpanAdds();
755ef4f32ac858825dc443cfe4739ea878fb0bf550fcaryclark             return result;
75655888e44171ffd48b591d19256884a969fe4da17caryclark        }
75755888e44171ffd48b591d19256884a969fe4da17caryclark        if (t < result->fT) {
75855888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpSpan* prev = result->span()->prev();
75930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            FAIL_WITH_NULL_IF(!prev, span);
76029b2563afb1677515739f1d24fb27733626eca92caryclark            // marks in global state that new op span has been allocated
76129b2563afb1677515739f1d24fb27733626eca92caryclark            this->globalState()->setAllocatedOpSpan();
76255888e44171ffd48b591d19256884a969fe4da17caryclark//             span->init(this, prev, t, pt);
76355888e44171ffd48b591d19256884a969fe4da17caryclark            this->debugValidate();
76455888e44171ffd48b591d19256884a969fe4da17caryclark// #if DEBUG_ADD_T
76555888e44171ffd48b591d19256884a969fe4da17caryclark//             SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
76655888e44171ffd48b591d19256884a969fe4da17caryclark//                     span->segment()->debugID(), span->debugID());
76755888e44171ffd48b591d19256884a969fe4da17caryclark// #endif
76855888e44171ffd48b591d19256884a969fe4da17caryclark//             span->bumpSpanAdds();
76955888e44171ffd48b591d19256884a969fe4da17caryclark            return nullptr;
77055888e44171ffd48b591d19256884a969fe4da17caryclark        }
77130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        FAIL_WITH_NULL_IF(span != &fTail, span);
77255888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((span = span->upCast()->next()));
77355888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(0);
77429b2563afb1677515739f1d24fb27733626eca92caryclark    return nullptr;  // we never get here, but need this to satisfy compiler
77526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
77626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
77726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
77826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#if DEBUG_ANGLE
77926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkOpSegment::debugCheckAngleCoin() const {
78026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpanBase* base = &fHead;
78126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpan* span;
78226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
78326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpAngle* angle = base->fromAngle();
78455888e44171ffd48b591d19256884a969fe4da17caryclark        if (angle && angle->debugCheckCoincidence()) {
78526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            angle->debugCheckNearCoincidence();
78626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
78726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (base->final()) {
78826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark             break;
78926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
79026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        span = base->upCast();
79126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        angle = span->toAngle();
79255888e44171ffd48b591d19256884a969fe4da17caryclark        if (angle && angle->debugCheckCoincidence()) {
79326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            angle->debugCheckNearCoincidence();
79426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
79526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    } while ((base = span->next()));
79626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
79726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
79826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
799ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
80026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark// this mimics the order of the checks in handle coincidence
801ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSegment::debugCheckHealth(SkPathOpsDebug::GlitchLog* glitches) const {
802ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    debugMoveMultiples(glitches);
803ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    debugMoveNearby(glitches);
804ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    debugMissingCoincidence(glitches);
80555888e44171ffd48b591d19256884a969fe4da17caryclark}
80626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
80755888e44171ffd48b591d19256884a969fe4da17caryclark// commented-out lines keep this in sync with clearAll()
808ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSegment::debugClearAll(SkPathOpsDebug::GlitchLog* glitches) const {
80955888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSpan* span = &fHead;
81055888e44171ffd48b591d19256884a969fe4da17caryclark    do {
811ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        this->debugClearOne(span, glitches);
81255888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((span = span->next()->upCastable()));
813ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->globalState()->coincidence()->debugRelease(glitches, this);
81426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
81526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
81655888e44171ffd48b591d19256884a969fe4da17caryclark// commented-out lines keep this in sync with clearOne()
817ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSegment::debugClearOne(const SkOpSpan* span, SkPathOpsDebug::GlitchLog* glitches) const {
818ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (span->windValue()) glitches->record(SkPathOpsDebug::kCollapsedWindValue_Glitch, span);
819ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (span->oppValue()) glitches->record(SkPathOpsDebug::kCollapsedOppValue_Glitch, span);
820ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (!span->done()) glitches->record(SkPathOpsDebug::kCollapsedDone_Glitch, span);
82126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
82226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
82326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
82454359294a7c9dc54802d512a5d891a35c1663392caryclarkSkOpAngle* SkOpSegment::debugLastAngle() {
82596fcdcc219d2a0d3579719b84b28bede76efba64halcanary    SkOpAngle* result = nullptr;
82654359294a7c9dc54802d512a5d891a35c1663392caryclark    SkOpSpan* span = this->head();
82754359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
82854359294a7c9dc54802d512a5d891a35c1663392caryclark        if (span->toAngle()) {
829dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkASSERT(!result);
83054359294a7c9dc54802d512a5d891a35c1663392caryclark            result = span->toAngle();
831dac1d17027dcaa5596885a9f333979418b35001ccaryclark        }
83254359294a7c9dc54802d512a5d891a35c1663392caryclark    } while ((span = span->next()->upCastable()));
833dac1d17027dcaa5596885a9f333979418b35001ccaryclark    SkASSERT(result);
834dac1d17027dcaa5596885a9f333979418b35001ccaryclark    return result;
835dac1d17027dcaa5596885a9f333979418b35001ccaryclark}
836dac1d17027dcaa5596885a9f333979418b35001ccaryclark
837ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
83855888e44171ffd48b591d19256884a969fe4da17caryclark// commented-out lines keep this in sync with ClearVisited
83955888e44171ffd48b591d19256884a969fe4da17caryclarkvoid SkOpSegment::DebugClearVisited(const SkOpSpanBase* span) {
84055888e44171ffd48b591d19256884a969fe4da17caryclark    // reset visited flag back to false
84155888e44171ffd48b591d19256884a969fe4da17caryclark    do {
84255888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
84355888e44171ffd48b591d19256884a969fe4da17caryclark        while ((ptT = ptT->next()) != stopPtT) {
84455888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpSegment* opp = ptT->segment();
84555888e44171ffd48b591d19256884a969fe4da17caryclark            opp->resetDebugVisited();
84655888e44171ffd48b591d19256884a969fe4da17caryclark        }
84755888e44171ffd48b591d19256884a969fe4da17caryclark    } while (!span->final() && (span = span->upCast()->next()));
84855888e44171ffd48b591d19256884a969fe4da17caryclark}
84955888e44171ffd48b591d19256884a969fe4da17caryclark#endif
85055888e44171ffd48b591d19256884a969fe4da17caryclark
851ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
85255888e44171ffd48b591d19256884a969fe4da17caryclark// commented-out lines keep this in sync with missingCoincidence()
85355888e44171ffd48b591d19256884a969fe4da17caryclark// look for pairs of undetected coincident curves
85455888e44171ffd48b591d19256884a969fe4da17caryclark// assumes that segments going in have visited flag clear
85555888e44171ffd48b591d19256884a969fe4da17caryclark// Even though pairs of curves correct detect coincident runs, a run may be missed
85655888e44171ffd48b591d19256884a969fe4da17caryclark// if the coincidence is a product of multiple intersections. For instance, given
85755888e44171ffd48b591d19256884a969fe4da17caryclark// curves A, B, and C:
85855888e44171ffd48b591d19256884a969fe4da17caryclark// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
85955888e44171ffd48b591d19256884a969fe4da17caryclark// the end of C that the intersection is replaced with the end of C.
86055888e44171ffd48b591d19256884a969fe4da17caryclark// Even though A-B correctly do not detect an intersection at point 2,
86155888e44171ffd48b591d19256884a969fe4da17caryclark// the resulting run from point 1 to point 2 is coincident on A and B.
862ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSegment::debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const {
86326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (this->done()) {
86426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        return;
86526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
86626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpan* prior = nullptr;
86726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpanBase* spanBase = &fHead;
86855888e44171ffd48b591d19256884a969fe4da17caryclark//    bool result = false;
86926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
87026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
87126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkASSERT(ptT->span() == spanBase);
87226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        while ((ptT = ptT->next()) != spanStopPtT) {
87326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (ptT->deleted()) {
87426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
87526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
87655888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpSegment* opp = ptT->span()->segment();
87726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (opp->done()) {
87826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
87926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
88026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence
88155888e44171ffd48b591d19256884a969fe4da17caryclark            if (!opp->debugVisited()) {
88226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
88326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
88426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (spanBase == &fHead) {
88526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
88626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
88755888e44171ffd48b591d19256884a969fe4da17caryclark            if (ptT->segment() == this) {
88855888e44171ffd48b591d19256884a969fe4da17caryclark                continue;
88955888e44171ffd48b591d19256884a969fe4da17caryclark            }
89026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpan* span = spanBase->upCastable();
89126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            // FIXME?: this assumes that if the opposite segment is coincident then no more
89226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            // coincidence needs to be detected. This may not be true.
89355888e44171ffd48b591d19256884a969fe4da17caryclark            if (span && span->segment() != opp && span->containsCoincidence(opp)) {  // debug has additional condition since it may be called before inner duplicate points have been deleted
89426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
89526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
89655888e44171ffd48b591d19256884a969fe4da17caryclark            if (spanBase->segment() != opp && spanBase->containsCoinEnd(opp)) {  // debug has additional condition since it may be called before inner duplicate points have been deleted
89726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
89855888e44171ffd48b591d19256884a969fe4da17caryclark            }
89926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpPtT* priorPtT = nullptr, * priorStopPtT;
90026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            // find prior span containing opp segment
90126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSegment* priorOpp = nullptr;
90226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpan* priorTest = spanBase->prev();
90326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            while (!priorOpp && priorTest) {
90426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                priorStopPtT = priorPtT = priorTest->ptT();
90526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                while ((priorPtT = priorPtT->next()) != priorStopPtT) {
90626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    if (priorPtT->deleted()) {
90726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                        continue;
90826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    }
909ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    const SkOpSegment* segment = priorPtT->span()->segment();
91026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    if (segment == opp) {
91126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                        prior = priorTest;
91226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                        priorOpp = opp;
91326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                        break;
91426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    }
91526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
91626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                priorTest = priorTest->prev();
91726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
91826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (!priorOpp) {
91926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
92026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
92155888e44171ffd48b591d19256884a969fe4da17caryclark            if (priorPtT == ptT) {
92255888e44171ffd48b591d19256884a969fe4da17caryclark                continue;
92355888e44171ffd48b591d19256884a969fe4da17caryclark            }
92426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpPtT* oppStart = prior->ptT();
92526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpPtT* oppEnd = spanBase->ptT();
92626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            bool swapped = priorPtT->fT > ptT->fT;
92726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (swapped) {
92826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                SkTSwap(priorPtT, ptT);
92926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                SkTSwap(oppStart, oppEnd);
93026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
93155888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpCoincidence* coincidence = this->globalState()->coincidence();
93255888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
93355888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpPtT* rootPtT = ptT->span()->ptT();
93455888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpPtT* rootOppStart = oppStart->span()->ptT();
93555888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
93655888e44171ffd48b591d19256884a969fe4da17caryclark            if (coincidence->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
93726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                goto swapBack;
93826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
93955888e44171ffd48b591d19256884a969fe4da17caryclark            if (testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
94055888e44171ffd48b591d19256884a969fe4da17caryclark            // mark coincidence
94130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#if DEBUG_COINCIDENCE_VERBOSE
94255888e44171ffd48b591d19256884a969fe4da17caryclark//                 SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__,
94355888e44171ffd48b591d19256884a969fe4da17caryclark//                         rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(),
94455888e44171ffd48b591d19256884a969fe4da17caryclark//                         rootOppEnd->debugID());
94555888e44171ffd48b591d19256884a969fe4da17caryclark#endif
946ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                log->record(SkPathOpsDebug::kMissingCoin_Glitch, priorPtT, ptT, oppStart, oppEnd);
94755888e44171ffd48b591d19256884a969fe4da17caryclark                //   coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
94855888e44171ffd48b591d19256884a969fe4da17caryclark                // }
94955888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
950d6562000efca50bc2bfddae8dcb69dce6b8c0950caryclark//                SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd);
95155888e44171ffd48b591d19256884a969fe4da17caryclark#endif
95255888e44171ffd48b591d19256884a969fe4da17caryclark                // result = true;
95326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
95426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    swapBack:
95526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (swapped) {
95626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                SkTSwap(priorPtT, ptT);
95726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
95826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
95926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next()));
96055888e44171ffd48b591d19256884a969fe4da17caryclark    DebugClearVisited(&fHead);
96155888e44171ffd48b591d19256884a969fe4da17caryclark    return;
96226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
96326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
96455888e44171ffd48b591d19256884a969fe4da17caryclark// commented-out lines keep this in sync with moveMultiples()
96555888e44171ffd48b591d19256884a969fe4da17caryclark// if a span has more than one intersection, merge the other segments' span as needed
966ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSegment::debugMoveMultiples(SkPathOpsDebug::GlitchLog* glitches) const {
96755888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
96826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpanBase* test = &fHead;
96926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
97026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        int addCount = test->spanAddsCount();
971ff11428526843d3e03feb6843bd21f2d80536415Cary Clark//        SkASSERT(addCount >= 1);
972ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        if (addCount <= 1) {
97326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            continue;
97426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
97526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpPtT* startPtT = test->ptT();
97626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpPtT* testPtT = startPtT;
97726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        do {  // iterate through all spans associated with start
97826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpanBase* oppSpan = testPtT->span();
97926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (oppSpan->spanAddsCount() == addCount) {
98026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
98126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
98226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (oppSpan->deleted()) {
98326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
98426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
98526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSegment* oppSegment = oppSpan->segment();
98626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (oppSegment == this) {
98726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
98826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
98926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            // find range of spans to consider merging
99026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpanBase* oppPrev = oppSpan;
99126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpanBase* oppFirst = oppSpan;
99226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            while ((oppPrev = oppPrev->prev())) {
99326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                if (!roughly_equal(oppPrev->t(), oppSpan->t())) {
99426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    break;
99526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
99626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                if (oppPrev->spanAddsCount() == addCount) {
99726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    continue;
99826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
99926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                if (oppPrev->deleted()) {
100026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    continue;
100126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
100226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                oppFirst = oppPrev;
100326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
100426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpanBase* oppNext = oppSpan;
100526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpanBase* oppLast = oppSpan;
100626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) {
100726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                if (!roughly_equal(oppNext->t(), oppSpan->t())) {
100826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    break;
100926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
101026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                if (oppNext->spanAddsCount() == addCount) {
101126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    continue;
101226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
101326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                if (oppNext->deleted()) {
101426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    continue;
101526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
101626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                oppLast = oppNext;
101726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
101826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (oppFirst == oppLast) {
101926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                continue;
102026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
102126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            const SkOpSpanBase* oppTest = oppFirst;
102226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            do {
102326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                if (oppTest == oppSpan) {
102426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    continue;
102526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
102626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                // check to see if the candidate meets specific criteria:
102726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                // it contains spans of segments in test's loop but not including 'this'
102826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                const SkOpPtT* oppStartPtT = oppTest->ptT();
102926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                const SkOpPtT* oppPtT = oppStartPtT;
103026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                while ((oppPtT = oppPtT->next()) != oppStartPtT) {
103126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    const SkOpSegment* oppPtTSegment = oppPtT->segment();
103226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    if (oppPtTSegment == this) {
103326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                        goto tryNextSpan;
103426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    }
103526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    const SkOpPtT* matchPtT = startPtT;
103626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    do {
103726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                        if (matchPtT->segment() == oppPtTSegment) {
103826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                            goto foundMatch;
103926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                        }
104026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    } while ((matchPtT = matchPtT->next()) != startPtT);
104126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    goto tryNextSpan;
104226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            foundMatch:  // merge oppTest and oppSpan
104355888e44171ffd48b591d19256884a969fe4da17caryclark                    oppSegment->debugValidate();
1044ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    oppTest->debugMergeMatches(glitches, oppSpan);
1045ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    oppTest->debugAddOpp(glitches, oppSpan);
104655888e44171ffd48b591d19256884a969fe4da17caryclark                    oppSegment->debugValidate();
104726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    goto checkNextSpan;
104826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
104955888e44171ffd48b591d19256884a969fe4da17caryclark        tryNextSpan:
105026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                ;
105126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()));
105226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        } while ((testPtT = testPtT->next()) != startPtT);
105355888e44171ffd48b591d19256884a969fe4da17caryclarkcheckNextSpan:
105426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        ;
105526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    } while ((test = test->final() ? nullptr : test->upCast()->next()));
105655888e44171ffd48b591d19256884a969fe4da17caryclark   debugValidate();
105755888e44171ffd48b591d19256884a969fe4da17caryclark   return;
105826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
105926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
106055888e44171ffd48b591d19256884a969fe4da17caryclark// commented-out lines keep this in sync with moveNearby()
106155888e44171ffd48b591d19256884a969fe4da17caryclark// Move nearby t values and pts so they all hang off the same span. Alignment happens later.
1062ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSegment::debugMoveNearby(SkPathOpsDebug::GlitchLog* glitches) const {
106355888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
106455888e44171ffd48b591d19256884a969fe4da17caryclark    // release undeleted spans pointing to this seg that are linked to the primary span
106555888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSpanBase* spanBase = &fHead;
106626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
106755888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* ptT = spanBase->ptT();
106855888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* headPtT = ptT;
106955888e44171ffd48b591d19256884a969fe4da17caryclark        while ((ptT = ptT->next()) != headPtT) {
107055888e44171ffd48b591d19256884a969fe4da17caryclark              const SkOpSpanBase* test = ptT->span();
107155888e44171ffd48b591d19256884a969fe4da17caryclark            if (ptT->segment() == this && !ptT->deleted() && test != spanBase
107255888e44171ffd48b591d19256884a969fe4da17caryclark                    && test->ptT() == ptT) {
107355888e44171ffd48b591d19256884a969fe4da17caryclark                if (test->final()) {
107455888e44171ffd48b591d19256884a969fe4da17caryclark                    if (spanBase == &fHead) {
1075ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        glitches->record(SkPathOpsDebug::kMoveNearbyClearAll_Glitch, this);
107655888e44171ffd48b591d19256884a969fe4da17caryclark//                        return;
107755888e44171ffd48b591d19256884a969fe4da17caryclark                    }
1078ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    glitches->record(SkPathOpsDebug::kMoveNearbyReleaseFinal_Glitch, spanBase, ptT);
107955888e44171ffd48b591d19256884a969fe4da17caryclark                } else if (test->prev()) {
1080ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    glitches->record(SkPathOpsDebug::kMoveNearbyRelease_Glitch, test, headPtT);
108155888e44171ffd48b591d19256884a969fe4da17caryclark                }
108255888e44171ffd48b591d19256884a969fe4da17caryclark//                break;
108326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
108426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
108555888e44171ffd48b591d19256884a969fe4da17caryclark        spanBase = spanBase->upCast()->next();
108655888e44171ffd48b591d19256884a969fe4da17caryclark    } while (!spanBase->final());
108755888e44171ffd48b591d19256884a969fe4da17caryclark
108855888e44171ffd48b591d19256884a969fe4da17caryclark    // This loop looks for adjacent spans which are near by
108955888e44171ffd48b591d19256884a969fe4da17caryclark    spanBase = &fHead;
109055888e44171ffd48b591d19256884a969fe4da17caryclark    do {  // iterate through all spans associated with start
109155888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* test = spanBase->upCast()->next();
1092c7c76d81fd09332a9a1d4b9f19b2a2dab3c723c3Cary Clark        bool found;
1093c7c76d81fd09332a9a1d4b9f19b2a2dab3c723c3Cary Clark        if (!this->spansNearby(spanBase, test, &found)) {
1094c7c76d81fd09332a9a1d4b9f19b2a2dab3c723c3Cary Clark            glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch, test);
1095c7c76d81fd09332a9a1d4b9f19b2a2dab3c723c3Cary Clark        }
1096c7c76d81fd09332a9a1d4b9f19b2a2dab3c723c3Cary Clark        if (found) {
109755888e44171ffd48b591d19256884a969fe4da17caryclark            if (test->final()) {
109855888e44171ffd48b591d19256884a969fe4da17caryclark                if (spanBase->prev()) {
1099ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch, test);
110055888e44171ffd48b591d19256884a969fe4da17caryclark                } else {
1101ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    glitches->record(SkPathOpsDebug::kMoveNearbyClearAll2_Glitch, this);
110255888e44171ffd48b591d19256884a969fe4da17caryclark                    // return
110355888e44171ffd48b591d19256884a969fe4da17caryclark                }
110455888e44171ffd48b591d19256884a969fe4da17caryclark            } else {
1105ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                glitches->record(SkPathOpsDebug::kMoveNearbyMerge_Glitch, spanBase);
110655888e44171ffd48b591d19256884a969fe4da17caryclark            }
110755888e44171ffd48b591d19256884a969fe4da17caryclark        }
110855888e44171ffd48b591d19256884a969fe4da17caryclark        spanBase = test;
110955888e44171ffd48b591d19256884a969fe4da17caryclark    } while (!spanBase->final());
111055888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
111126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
111226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
111326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
11144431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::debugReset() {
11151049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    this->init(this->fPts, this->fWeight, this->contour(), this->verb());
11164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
11174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
1118025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#if DEBUG_COINCIDENCE_ORDER
1119025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclarkvoid SkOpSegment::debugSetCoinT(int index, SkScalar t) const {
1120025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    if (fDebugBaseMax < 0 || fDebugBaseIndex == index) {
1121025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        fDebugBaseIndex = index;
1122025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        fDebugBaseMin = SkTMin(t, fDebugBaseMin);
1123025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        fDebugBaseMax = SkTMax(t, fDebugBaseMax);
1124025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        return;
1125025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    }
1126025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    SkASSERT(fDebugBaseMin >= t || t >= fDebugBaseMax);
1127025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    if (fDebugLastMax < 0 || fDebugLastIndex == index) {
1128025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        fDebugLastIndex = index;
1129025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        fDebugLastMin = SkTMin(t, fDebugLastMin);
1130025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        fDebugLastMax = SkTMax(t, fDebugLastMax);
1131025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        return;
1132025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    }
1133025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    SkASSERT(fDebugLastMin >= t || t >= fDebugLastMax);
1134025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    SkASSERT((t - fDebugBaseMin > 0) == (fDebugLastMin - fDebugBaseMin > 0));
1135025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark}
1136025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#endif
1137025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark
113854359294a7c9dc54802d512a5d891a35c1663392caryclark#if DEBUG_ACTIVE_SPANS
1139ff11428526843d3e03feb6843bd21f2d80536415Cary Clarkvoid SkOpSegment::debugShowActiveSpans(SkString* str) const {
11404431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    debugValidate();
11414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    if (done()) {
11424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return;
11434431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
11444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int lastId = -1;
11454431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    double lastT = -1;
114654359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpSpan* span = &fHead;
114754359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
114854359294a7c9dc54802d512a5d891a35c1663392caryclark        if (span->done()) {
11494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
11504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
11511049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        if (lastId == this->debugID() && lastT == span->t()) {
11524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            continue;
11534431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
11541049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        lastId = this->debugID();
115554359294a7c9dc54802d512a5d891a35c1663392caryclark        lastT = span->t();
1156ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        str->appendf("%s id=%d", __FUNCTION__, this->debugID());
115755888e44171ffd48b591d19256884a969fe4da17caryclark        // since endpoints may have be adjusted, show actual computed curves
115855888e44171ffd48b591d19256884a969fe4da17caryclark        SkDCurve curvePart;
115955888e44171ffd48b591d19256884a969fe4da17caryclark        this->subDivide(span, span->next(), &curvePart);
116055888e44171ffd48b591d19256884a969fe4da17caryclark        const SkDPoint* pts = curvePart.fCubic.fPts;
1161ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        str->appendf(" (%1.9g,%1.9g", pts[0].fX, pts[0].fY);
11624431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
1163ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            str->appendf(" %1.9g,%1.9g", pts[vIndex].fX, pts[vIndex].fY);
11644431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
11651049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        if (SkPath::kConic_Verb == fVerb) {
1166ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            str->appendf(" %1.9gf", curvePart.fConic.fWeight);
11671049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        }
1168ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        str->appendf(") t=%1.9g tEnd=%1.9g", span->t(), span->next()->t());
116954359294a7c9dc54802d512a5d891a35c1663392caryclark        if (span->windSum() == SK_MinS32) {
1170ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            str->appendf(" windSum=?");
11714431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        } else {
1172ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            str->appendf(" windSum=%d", span->windSum());
1173624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        }
1174624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        if (span->oppValue() && span->oppSum() == SK_MinS32) {
1175ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            str->appendf(" oppSum=?");
1176624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        } else if (span->oppValue() || span->oppSum() != SK_MinS32) {
1177ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            str->appendf(" oppSum=%d", span->oppSum());
1178624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        }
1179ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        str->appendf(" windValue=%d", span->windValue());
1180624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        if (span->oppValue() || span->oppSum() != SK_MinS32) {
1181ff11428526843d3e03feb6843bd21f2d80536415Cary Clark            str->appendf(" oppValue=%d", span->oppValue());
11824431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
1183ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        str->appendf("\n");
118454359294a7c9dc54802d512a5d891a35c1663392caryclark   } while ((span = span->next()->upCastable()));
11854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
11864431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
11874431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
118854359294a7c9dc54802d512a5d891a35c1663392caryclark#if DEBUG_MARK_DONE
118954359294a7c9dc54802d512a5d891a35c1663392caryclarkvoid SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding) {
119054359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkPoint& pt = span->ptT()->fPt;
11911049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkDebugf("%s id=%d", fun, this->debugID());
11924431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
11934431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
11944431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
11954431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
119654359294a7c9dc54802d512a5d891a35c1663392caryclark    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
119754359294a7c9dc54802d512a5d891a35c1663392caryclark            span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t());
119854359294a7c9dc54802d512a5d891a35c1663392caryclark    if (winding == SK_MinS32) {
11994431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkDebugf("?");
12004431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
120154359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("%d", winding);
12024431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
120354359294a7c9dc54802d512a5d891a35c1663392caryclark    SkDebugf(" windSum=");
120454359294a7c9dc54802d512a5d891a35c1663392caryclark    if (span->windSum() == SK_MinS32) {
120554359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("?");
120654359294a7c9dc54802d512a5d891a35c1663392caryclark    } else {
120754359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("%d", span->windSum());
120854359294a7c9dc54802d512a5d891a35c1663392caryclark    }
120954359294a7c9dc54802d512a5d891a35c1663392caryclark    SkDebugf(" windValue=%d\n", span->windValue());
12104431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
12114431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
121254359294a7c9dc54802d512a5d891a35c1663392caryclarkvoid SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding,
12134431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org                                      int oppWinding) {
121454359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkPoint& pt = span->ptT()->fPt;
12151049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkDebugf("%s id=%d", fun, this->debugID());
12164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
12174431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
12184431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
12194431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
122054359294a7c9dc54802d512a5d891a35c1663392caryclark    SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
122154359294a7c9dc54802d512a5d891a35c1663392caryclark            span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t(), winding, oppWinding);
122254359294a7c9dc54802d512a5d891a35c1663392caryclark    if (winding == SK_MinS32) {
122354359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("?");
122454359294a7c9dc54802d512a5d891a35c1663392caryclark    } else {
122554359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("%d", winding);
122654359294a7c9dc54802d512a5d891a35c1663392caryclark    }
122754359294a7c9dc54802d512a5d891a35c1663392caryclark    SkDebugf(" newOppSum=");
122854359294a7c9dc54802d512a5d891a35c1663392caryclark    if (oppWinding == SK_MinS32) {
122954359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("?");
123054359294a7c9dc54802d512a5d891a35c1663392caryclark    } else {
123154359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("%d", oppWinding);
123254359294a7c9dc54802d512a5d891a35c1663392caryclark    }
123354359294a7c9dc54802d512a5d891a35c1663392caryclark    SkDebugf(" oppSum=");
123454359294a7c9dc54802d512a5d891a35c1663392caryclark    if (span->oppSum() == SK_MinS32) {
12354431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkDebugf("?");
12364431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
123754359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("%d", span->oppSum());
12384431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
12394431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    SkDebugf(" windSum=");
124054359294a7c9dc54802d512a5d891a35c1663392caryclark    if (span->windSum() == SK_MinS32) {
12414431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        SkDebugf("?");
12424431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    } else {
124354359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("%d", span->windSum());
12444431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
124554359294a7c9dc54802d512a5d891a35c1663392caryclark    SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue());
12464431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
124754359294a7c9dc54802d512a5d891a35c1663392caryclark
12484431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
12494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
125026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark// loop looking for a pair of angle parts that are too close to be sorted
125126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark/* This is called after other more simple intersection and angle sorting tests have been exhausted.
125226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark   This should be rarely called -- the test below is thorough and time consuming.
125355888e44171ffd48b591d19256884a969fe4da17caryclark   This checks the distance between start points; the distance between
125426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark*/
125526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#if DEBUG_ANGLE
125626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkvoid SkOpAngle::debugCheckNearCoincidence() const {
125726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpAngle* test = this;
125826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
125926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpSegment* testSegment = test->segment();
126026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        double testStartT = test->start()->t();
126126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkDPoint testStartPt = testSegment->dPtAtT(testStartT);
126226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        double testEndT = test->end()->t();
126326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkDPoint testEndPt = testSegment->dPtAtT(testEndT);
126426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        double testLenSq = testStartPt.distanceSquared(testEndPt);
126526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkDebugf("%s testLenSq=%1.9g id=%d\n", __FUNCTION__, testLenSq, testSegment->debugID());
126626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        double testMidT = (testStartT + testEndT) / 2;
126726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpAngle* next = test;
126826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        while ((next = next->fNext) != this) {
126926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkOpSegment* nextSegment = next->segment();
127026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double testMidDistSq = testSegment->distSq(testMidT, next);
127126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double testEndDistSq = testSegment->distSq(testEndT, next);
127226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double nextStartT = next->start()->t();
127326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDPoint nextStartPt = nextSegment->dPtAtT(nextStartT);
127426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double distSq = testStartPt.distanceSquared(nextStartPt);
127526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double nextEndT = next->end()->t();
127626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double nextMidT = (nextStartT + nextEndT) / 2;
127726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double nextMidDistSq = nextSegment->distSq(nextMidT, test);
127826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double nextEndDistSq = nextSegment->distSq(nextEndT, test);
127926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%s distSq=%1.9g testId=%d nextId=%d\n", __FUNCTION__, distSq,
128026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                    testSegment->debugID(), nextSegment->debugID());
128126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq);
128226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq);
128326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq);
128426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq);
128526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT);
128626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double nextLenSq = nextStartPt.distanceSquared(nextEndPt);
128726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq);
128826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("\n");
128926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
129026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        test = test->fNext;
129155888e44171ffd48b591d19256884a969fe4da17caryclark    } while (test->fNext != this);
129226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
129326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
129426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
129554359294a7c9dc54802d512a5d891a35c1663392caryclark#if DEBUG_ANGLE
129654359294a7c9dc54802d512a5d891a35c1663392caryclarkSkString SkOpAngle::debugPart() const {
129754359294a7c9dc54802d512a5d891a35c1663392caryclark    SkString result;
129854359294a7c9dc54802d512a5d891a35c1663392caryclark    switch (this->segment()->verb()) {
129954359294a7c9dc54802d512a5d891a35c1663392caryclark        case SkPath::kLine_Verb:
1300eed356d281adbf93ecbd89cb23913a7861cd8578caryclark            result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fPart.fCurve),
130154359294a7c9dc54802d512a5d891a35c1663392caryclark                    this->segment()->debugID());
130254359294a7c9dc54802d512a5d891a35c1663392caryclark            break;
130354359294a7c9dc54802d512a5d891a35c1663392caryclark        case SkPath::kQuad_Verb:
1304eed356d281adbf93ecbd89cb23913a7861cd8578caryclark            result.printf(QUAD_DEBUG_STR " id=%d", QUAD_DEBUG_DATA(fPart.fCurve),
130554359294a7c9dc54802d512a5d891a35c1663392caryclark                    this->segment()->debugID());
130654359294a7c9dc54802d512a5d891a35c1663392caryclark            break;
13071049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        case SkPath::kConic_Verb:
13081049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            result.printf(CONIC_DEBUG_STR " id=%d",
1309eed356d281adbf93ecbd89cb23913a7861cd8578caryclark                    CONIC_DEBUG_DATA(fPart.fCurve, fPart.fCurve.fConic.fWeight),
13101049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                    this->segment()->debugID());
13111049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            break;
131254359294a7c9dc54802d512a5d891a35c1663392caryclark        case SkPath::kCubic_Verb:
1313eed356d281adbf93ecbd89cb23913a7861cd8578caryclark            result.printf(CUBIC_DEBUG_STR " id=%d", CUBIC_DEBUG_DATA(fPart.fCurve),
131454359294a7c9dc54802d512a5d891a35c1663392caryclark                    this->segment()->debugID());
131554359294a7c9dc54802d512a5d891a35c1663392caryclark            break;
131654359294a7c9dc54802d512a5d891a35c1663392caryclark        default:
131754359294a7c9dc54802d512a5d891a35c1663392caryclark            SkASSERT(0);
13181b24933e52f50773de29332387a12721811f3012mtklein    }
131954359294a7c9dc54802d512a5d891a35c1663392caryclark    return result;
132054359294a7c9dc54802d512a5d891a35c1663392caryclark}
132154359294a7c9dc54802d512a5d891a35c1663392caryclark#endif
132254359294a7c9dc54802d512a5d891a35c1663392caryclark
1323624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#if DEBUG_SORT
132454359294a7c9dc54802d512a5d891a35c1663392caryclarkvoid SkOpAngle::debugLoop() const {
132554359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpAngle* first = this;
132654359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpAngle* next = this;
132754359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
132854359294a7c9dc54802d512a5d891a35c1663392caryclark        next->dumpOne(true);
132954359294a7c9dc54802d512a5d891a35c1663392caryclark        SkDebugf("\n");
133054359294a7c9dc54802d512a5d891a35c1663392caryclark        next = next->fNext;
133154359294a7c9dc54802d512a5d891a35c1663392caryclark    } while (next && next != first);
133254359294a7c9dc54802d512a5d891a35c1663392caryclark    next = first;
133354359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
133454359294a7c9dc54802d512a5d891a35c1663392caryclark        next->debugValidate();
133554359294a7c9dc54802d512a5d891a35c1663392caryclark        next = next->fNext;
133654359294a7c9dc54802d512a5d891a35c1663392caryclark    } while (next && next != first);
1337ccec0f958ffc71a9986d236bc2eb335cb2111119caryclark}
1338ccec0f958ffc71a9986d236bc2eb335cb2111119caryclark#endif
1339ccec0f958ffc71a9986d236bc2eb335cb2111119caryclark
134054359294a7c9dc54802d512a5d891a35c1663392caryclarkvoid SkOpAngle::debugValidate() const {
134155888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
134255888e44171ffd48b591d19256884a969fe4da17caryclark    if (this->globalState()->debugCheckHealth()) {
134355888e44171ffd48b591d19256884a969fe4da17caryclark        return;
134455888e44171ffd48b591d19256884a969fe4da17caryclark    }
134555888e44171ffd48b591d19256884a969fe4da17caryclark#endif
134654359294a7c9dc54802d512a5d891a35c1663392caryclark#if DEBUG_VALIDATE
134754359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpAngle* first = this;
134854359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpAngle* next = this;
134954359294a7c9dc54802d512a5d891a35c1663392caryclark    int wind = 0;
135054359294a7c9dc54802d512a5d891a35c1663392caryclark    int opp = 0;
135154359294a7c9dc54802d512a5d891a35c1663392caryclark    int lastXor = -1;
135254359294a7c9dc54802d512a5d891a35c1663392caryclark    int lastOppXor = -1;
135354359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
135454359294a7c9dc54802d512a5d891a35c1663392caryclark        if (next->unorderable()) {
135554359294a7c9dc54802d512a5d891a35c1663392caryclark            return;
135654359294a7c9dc54802d512a5d891a35c1663392caryclark        }
135754359294a7c9dc54802d512a5d891a35c1663392caryclark        const SkOpSpan* minSpan = next->start()->starter(next->end());
135854359294a7c9dc54802d512a5d891a35c1663392caryclark        if (minSpan->windValue() == SK_MinS32) {
135954359294a7c9dc54802d512a5d891a35c1663392caryclark            return;
136054359294a7c9dc54802d512a5d891a35c1663392caryclark        }
136154359294a7c9dc54802d512a5d891a35c1663392caryclark        bool op = next->segment()->operand();
136254359294a7c9dc54802d512a5d891a35c1663392caryclark        bool isXor = next->segment()->isXor();
136354359294a7c9dc54802d512a5d891a35c1663392caryclark        bool oppXor = next->segment()->oppXor();
136454359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(!DEBUG_LIMIT_WIND_SUM || between(0, minSpan->windValue(), DEBUG_LIMIT_WIND_SUM));
136554359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(!DEBUG_LIMIT_WIND_SUM
136654359294a7c9dc54802d512a5d891a35c1663392caryclark                || between(-DEBUG_LIMIT_WIND_SUM, minSpan->oppValue(), DEBUG_LIMIT_WIND_SUM));
136754359294a7c9dc54802d512a5d891a35c1663392caryclark        bool useXor = op ? oppXor : isXor;
136854359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(lastXor == -1 || lastXor == (int) useXor);
136954359294a7c9dc54802d512a5d891a35c1663392caryclark        lastXor = (int) useXor;
1370624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        wind += next->debugSign() * (op ? minSpan->oppValue() : minSpan->windValue());
137154359294a7c9dc54802d512a5d891a35c1663392caryclark        if (useXor) {
137254359294a7c9dc54802d512a5d891a35c1663392caryclark            wind &= 1;
137354359294a7c9dc54802d512a5d891a35c1663392caryclark        }
137454359294a7c9dc54802d512a5d891a35c1663392caryclark        useXor = op ? isXor : oppXor;
137554359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor);
137654359294a7c9dc54802d512a5d891a35c1663392caryclark        lastOppXor = (int) useXor;
1377624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        opp += next->debugSign() * (op ? minSpan->windValue() : minSpan->oppValue());
137854359294a7c9dc54802d512a5d891a35c1663392caryclark        if (useXor) {
137954359294a7c9dc54802d512a5d891a35c1663392caryclark            opp &= 1;
138054359294a7c9dc54802d512a5d891a35c1663392caryclark        }
138154359294a7c9dc54802d512a5d891a35c1663392caryclark        next = next->fNext;
138254359294a7c9dc54802d512a5d891a35c1663392caryclark    } while (next && next != first);
138359d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clark    SkASSERT(wind == 0 || !SkPathOpsDebug::gRunFail);
138459d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clark    SkASSERT(opp == 0 || !SkPathOpsDebug::gRunFail);
138554359294a7c9dc54802d512a5d891a35c1663392caryclark#endif
138654359294a7c9dc54802d512a5d891a35c1663392caryclark}
138754359294a7c9dc54802d512a5d891a35c1663392caryclark
138854359294a7c9dc54802d512a5d891a35c1663392caryclarkvoid SkOpAngle::debugValidateNext() const {
138954359294a7c9dc54802d512a5d891a35c1663392caryclark#if !FORCE_RELEASE
139054359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpAngle* first = this;
139154359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpAngle* next = first;
139254359294a7c9dc54802d512a5d891a35c1663392caryclark    SkTDArray<const SkOpAngle*>(angles);
139354359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
1394f2b340fc885ad2a12d2d73974eff9c8f4c94192cdjsollen//        SkASSERT_RELEASE(next->fSegment->debugContains(next));
139554359294a7c9dc54802d512a5d891a35c1663392caryclark        angles.push(next);
139654359294a7c9dc54802d512a5d891a35c1663392caryclark        next = next->next();
139754359294a7c9dc54802d512a5d891a35c1663392caryclark        if (next == first) {
139854359294a7c9dc54802d512a5d891a35c1663392caryclark            break;
139954359294a7c9dc54802d512a5d891a35c1663392caryclark        }
1400f2b340fc885ad2a12d2d73974eff9c8f4c94192cdjsollen        SkASSERT_RELEASE(!angles.contains(next));
140154359294a7c9dc54802d512a5d891a35c1663392caryclark        if (!next) {
140254359294a7c9dc54802d512a5d891a35c1663392caryclark            return;
140354359294a7c9dc54802d512a5d891a35c1663392caryclark        }
140454359294a7c9dc54802d512a5d891a35c1663392caryclark    } while (true);
140554359294a7c9dc54802d512a5d891a35c1663392caryclark#endif
140654359294a7c9dc54802d512a5d891a35c1663392caryclark}
140754359294a7c9dc54802d512a5d891a35c1663392caryclark
140855888e44171ffd48b591d19256884a969fe4da17caryclark#ifdef SK_DEBUG
140955888e44171ffd48b591d19256884a969fe4da17caryclarkvoid SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over,
141055888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpGlobalState* debugState) const {
141159d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clark    SkASSERT(coinPtTEnd()->span() == over || !SkOpGlobalState::DebugRunFail());
141259d5a0e3f560da40e0ae7036a01d7d58ce3718d8Cary Clark    SkASSERT(oppPtTEnd()->span() == outer || !SkOpGlobalState::DebugRunFail());
141355888e44171ffd48b591d19256884a969fe4da17caryclark}
141455888e44171ffd48b591d19256884a969fe4da17caryclark#endif
141526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
1416ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
1417ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark// sets the span's end to the ptT referenced by the previous-next
1418ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkCoincidentSpans::debugCorrectOneEnd(SkPathOpsDebug::GlitchLog* log,
1419ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
1420ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) const ) const {
1421ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpPtT* origPtT = (this->*getEnd)();
1422ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSpanBase* origSpan = origPtT->span();
1423ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSpan* prev = origSpan->prev();
1424ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpPtT* testPtT = prev ? prev->next()->ptT()
1425ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            : origSpan->upCast()->next()->prev()->ptT();
1426ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (origPtT != testPtT) {
1427ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        log->record(SkPathOpsDebug::kCorrectEnd_Glitch, this, origPtT, testPtT);
1428ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
1429ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
1430ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
1431ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
1432ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark/* Commented-out lines keep this in sync with correctEnds */
1433ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark// FIXME: member pointers have fallen out of favor and can be replaced with
1434ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark// an alternative approach.
1435ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark// makes all span ends agree with the segment's spans that define them
1436ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkCoincidentSpans::debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const {
1437ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugCorrectOneEnd(log, &SkCoincidentSpans::coinPtTStart, nullptr);
1438ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugCorrectOneEnd(log, &SkCoincidentSpans::coinPtTEnd, nullptr);
1439ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugCorrectOneEnd(log, &SkCoincidentSpans::oppPtTStart, nullptr);
1440ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugCorrectOneEnd(log, &SkCoincidentSpans::oppPtTEnd, nullptr);
1441ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
1442ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
144355888e44171ffd48b591d19256884a969fe4da17caryclark/* Commented-out lines keep this in sync with expand */
144430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// expand the range by checking adjacent spans for coincidence
1445ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkbool SkCoincidentSpans::debugExpand(SkPathOpsDebug::GlitchLog* log) const {
144655888e44171ffd48b591d19256884a969fe4da17caryclark    bool expanded = false;
144755888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSegment* segment = coinPtTStart()->segment();
144855888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSegment* oppSegment = oppPtTStart()->segment();
144955888e44171ffd48b591d19256884a969fe4da17caryclark    do {
145055888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpan* start = coinPtTStart()->span()->upCast();
145155888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpan* prev = start->prev();
145255888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* oppPtT;
145355888e44171ffd48b591d19256884a969fe4da17caryclark        if (!prev || !(oppPtT = prev->contains(oppSegment))) {
145455888e44171ffd48b591d19256884a969fe4da17caryclark            break;
145555888e44171ffd48b591d19256884a969fe4da17caryclark        }
145655888e44171ffd48b591d19256884a969fe4da17caryclark        double midT = (prev->t() + start->t()) / 2;
145755888e44171ffd48b591d19256884a969fe4da17caryclark        if (!segment->isClose(midT, oppSegment)) {
145855888e44171ffd48b591d19256884a969fe4da17caryclark            break;
145955888e44171ffd48b591d19256884a969fe4da17caryclark        }
1460ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, this, prev->ptT(), oppPtT);
146155888e44171ffd48b591d19256884a969fe4da17caryclark        expanded = true;
146255888e44171ffd48b591d19256884a969fe4da17caryclark    } while (false);  // actual continues while expansion is possible
146355888e44171ffd48b591d19256884a969fe4da17caryclark    do {
146455888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* end = coinPtTEnd()->span();
146555888e44171ffd48b591d19256884a969fe4da17caryclark        SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
146630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        if (next && next->deleted()) {
146730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            break;
146830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        }
146955888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* oppPtT;
147055888e44171ffd48b591d19256884a969fe4da17caryclark        if (!next || !(oppPtT = next->contains(oppSegment))) {
147155888e44171ffd48b591d19256884a969fe4da17caryclark            break;
147255888e44171ffd48b591d19256884a969fe4da17caryclark        }
147355888e44171ffd48b591d19256884a969fe4da17caryclark        double midT = (end->t() + next->t()) / 2;
147455888e44171ffd48b591d19256884a969fe4da17caryclark        if (!segment->isClose(midT, oppSegment)) {
147555888e44171ffd48b591d19256884a969fe4da17caryclark            break;
147655888e44171ffd48b591d19256884a969fe4da17caryclark        }
1477ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, this, next->ptT(), oppPtT);
147855888e44171ffd48b591d19256884a969fe4da17caryclark        expanded = true;
147955888e44171ffd48b591d19256884a969fe4da17caryclark    } while (false);  // actual continues while expansion is possible
148055888e44171ffd48b591d19256884a969fe4da17caryclark    return expanded;
148155888e44171ffd48b591d19256884a969fe4da17caryclark}
148255888e44171ffd48b591d19256884a969fe4da17caryclark
1483ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark// description below
1484ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log, const SkOpSpan* base, const SkOpSpanBase* testSpan) const {
1485ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpPtT* testPtT = testSpan->ptT();
1486ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpPtT* stopPtT = testPtT;
1487ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSegment* baseSeg = base->segment();
1488ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    while ((testPtT = testPtT->next()) != stopPtT) {
1489ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        const SkOpSegment* testSeg = testPtT->segment();
1490ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (testPtT->deleted()) {
1491ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            continue;
1492ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1493ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (testSeg == baseSeg) {
1494ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            continue;
1495ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1496ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (testPtT->span()->ptT() != testPtT) {
1497ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            continue;
1498ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1499ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (this->contains(baseSeg, testSeg, testPtT->fT)) {
1500ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            continue;
1501ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1502ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        // intersect perp with base->ptT() with testPtT->segment()
1503ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkDVector dxdy = baseSeg->dSlopeAtT(base->t());
1504ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        const SkPoint& pt = base->pt();
1505ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}};
1506ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkIntersections i;
1507ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i);
1508ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        for (int index = 0; index < i.used(); ++index) {
1509ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            double t = i[0][index];
1510ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (!between(0, t, 1)) {
1511ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                continue;
1512ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1513ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            SkDPoint oppPt = i.pt(index);
1514ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (!oppPt.approximatelyEqual(pt)) {
1515ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                continue;
1516ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1517ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
1518ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            SkOpPtT* oppStart = writableSeg->addT(t);
1519ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (oppStart == testPtT) {
1520ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                continue;
1521ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1522ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
1523ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            oppStart->span()->addOpp(writableBase);
1524ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (oppStart->deleted()) {
1525ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                continue;
1526ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1527ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            SkOpSegment* coinSeg = base->segment();
1528ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            SkOpSegment* oppSeg = oppStart->segment();
1529ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            double coinTs, coinTe, oppTs, oppTe;
1530ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (Ordered(coinSeg, oppSeg)) {
1531ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                coinTs = base->t();
1532ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                coinTe = testSpan->t();
1533ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                oppTs = oppStart->fT;
1534ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                oppTe = testPtT->fT;
1535ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            } else {
1536ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                SkTSwap(coinSeg, oppSeg);
1537ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                coinTs = oppStart->fT;
1538ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                coinTe = testPtT->fT;
1539ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                oppTs = base->t();
1540ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                oppTe = testSpan->t();
1541ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1542ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (coinTs > coinTe) {
1543ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                SkTSwap(coinTs, coinTe);
1544ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                SkTSwap(oppTs, oppTe);
1545ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1546ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            bool added;
1547ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (this->debugAddOrOverlap(log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added), false) {
1548ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                return;
1549ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1550ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1551ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
1552ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return;
1553ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
1554ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
1555ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark// description below
1556ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* ptT) const {
1557ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    FAIL_IF(!ptT->span()->upCastable(), ptT->span());
1558ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSpan* base = ptT->span()->upCast();
1559ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSpan* prev = base->prev();
1560ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    FAIL_IF(!prev, ptT->span());
1561ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (!prev->isCanceled()) {
1562ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (this->debugAddEndMovedSpans(log, base, base->prev()), false) {
1563ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            return;
1564ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1565ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
1566ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (!base->isCanceled()) {
1567ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (this->debugAddEndMovedSpans(log, base, base->next()), false) {
1568ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            return;
1569ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1570ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
1571ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return;
1572ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
1573ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
1574ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark/*  If A is coincident with B and B includes an endpoint, and A's matching point
1575ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    is not the endpoint (i.e., there's an implied line connecting B-end and A)
1576ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    then assume that the same implied line may intersect another curve close to B.
1577ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    Since we only care about coincidence that was undetected, look at the
1578ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but
1579ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    next door) and see if the A matching point is close enough to form another
1580ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    coincident pair. If so, check for a new coincident span between B-end/A ptT loop
1581ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    and the adjacent ptT loop.
1582ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark*/
1583ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) const {
1584ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkCoincidentSpans* span = fHead;
1585ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (!span) {
1586ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        return;
1587ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
1588ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark//    fTop = span;
1589ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark//    fHead = nullptr;
1590ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    do {
1591ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) {
1592ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            FAIL_IF(1 == span->coinPtTStart()->fT, span);
1593ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            bool onEnd = span->coinPtTStart()->fT == 0;
1594ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            bool oOnEnd = zero_or_one(span->oppPtTStart()->fT);
1595ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (onEnd) {
1596ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                if (!oOnEnd) {  // if both are on end, any nearby intersect was already found
1597ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    if (this->debugAddEndMovedSpans(log, span->oppPtTStart()), false) {
1598ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        return;
1599ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    }
1600ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                }
1601ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            } else if (oOnEnd) {
1602ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                if (this->debugAddEndMovedSpans(log, span->coinPtTStart()), false) {
1603ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    return;
1604ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                }
1605ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1606ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1607ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) {
1608ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            bool onEnd = span->coinPtTEnd()->fT == 1;
1609ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT);
1610ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (onEnd) {
1611ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                if (!oOnEnd) {
1612ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    if (this->debugAddEndMovedSpans(log, span->oppPtTEnd()), false) {
1613ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        return;
1614ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    }
1615ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                }
1616ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            } else if (oOnEnd) {
1617ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                if (this->debugAddEndMovedSpans(log, span->coinPtTEnd()), false) {
1618ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    return;
1619ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                }
1620ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
1621ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
1622ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((span = span->next()));
1623ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark//    this->restoreHead();
1624ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return;
1625ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
1626ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
162755888e44171ffd48b591d19256884a969fe4da17caryclark/* Commented-out lines keep this in sync with addExpanded */
162855888e44171ffd48b591d19256884a969fe4da17caryclark// for each coincident pair, match the spans
162955888e44171ffd48b591d19256884a969fe4da17caryclark// if the spans don't match, add the mssing pt to the segment and loop it in the opposite span
1630ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const {
1631a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark//    DEBUG_SET_PHASE();
163226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkCoincidentSpans* coin = this->fHead;
163326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (!coin) {
1634ed0935a28a29af7d3b16ac8d9365f291a335c6bdcaryclark        return;
1635ed0935a28a29af7d3b16ac8d9365f291a335c6bdcaryclark    }
163626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
163755888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* startPtT = coin->coinPtTStart();
163855888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* oStartPtT = coin->oppPtTStart();
1639ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        double priorT = startPtT->fT;
1640ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        double oPriorT = oStartPtT->fT;
1641ff11428526843d3e03feb6843bd21f2d80536415Cary Clark        FAIL_IF(!startPtT->contains(oStartPtT), coin);
1642ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
164326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpSpanBase* start = startPtT->span();
164426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpSpanBase* oStart = oStartPtT->span();
164555888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* end = coin->coinPtTEnd()->span();
164655888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
164730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        FAIL_IF(oEnd->deleted(), coin);
164830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        FAIL_IF(!start->upCastable(), coin);
164926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpSpanBase* test = start->upCast()->next();
1650ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        FAIL_IF(!coin->flipped() && !oStart->upCastable(), coin);
165155888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next();
1652ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        FAIL_IF(!oTest, coin);
1653ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        const SkOpSegment* seg = start->segment();
1654ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        const SkOpSegment* oSeg = oStart->segment();
165526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        while (test != end || oTest != oEnd) {
1656ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            const SkOpPtT* containedOpp = test->ptT()->contains(oSeg);
1657ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            const SkOpPtT* containedThis = oTest->ptT()->contains(seg);
1658ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (!containedOpp || !containedThis) {
1659ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                // choose the ends, or the first common pt-t list shared by both
1660ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                double nextT, oNextT;
1661ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                if (containedOpp) {
1662ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    nextT = test->t();
1663ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    oNextT = containedOpp->fT;
1664ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                } else if (containedThis) {
1665ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    nextT = containedThis->fT;
1666ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    oNextT = oTest->t();
1667ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                } else {
1668ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    // iterate through until a pt-t list found that contains the other
1669ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    const SkOpSpanBase* walk = test;
1670ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    const SkOpPtT* walkOpp;
1671ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    do {
1672ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        FAIL_IF(!walk->upCastable(), coin);
1673ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        walk = walk->upCast()->next();
1674ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    } while (!(walkOpp = walk->ptT()->contains(oSeg))
1675ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                            && walk != coin->coinPtTEnd()->span());
1676a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark                    FAIL_IF(!walkOpp, coin);
1677ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    nextT = walk->t();
1678ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    oNextT = walkOpp->fT;
1679ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                }
168026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                // use t ranges to guess which one is missing
1681a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark                double startRange = nextT - priorT;
168230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                FAIL_IF(!startRange, coin);
1683a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark                double startPart = (test->t() - priorT) / startRange;
1684a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark                double oStartRange = oNextT - oPriorT;
168530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                FAIL_IF(!oStartRange, coin);
168626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange;
168730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                FAIL_IF(startPart == oStartPart, coin);
1688ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
1689ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        : !!containedThis;
169055888e44171ffd48b591d19256884a969fe4da17caryclark                bool startOver = false;
1691ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                addToOpp ? log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch,
1692ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        oPriorT + oStartRange * startPart, test)
1693ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        : log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch,
1694ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        priorT + startRange * oStartPart, oTest);
1695ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark         //       FAIL_IF(!success, coin);
169655888e44171ffd48b591d19256884a969fe4da17caryclark                if (startOver) {
169755888e44171ffd48b591d19256884a969fe4da17caryclark                    test = start;
169855888e44171ffd48b591d19256884a969fe4da17caryclark                    oTest = oStart;
169926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
1700ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                end = coin->coinPtTEnd()->span();
1701ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                oEnd = coin->oppPtTEnd()->span();
170226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
170355888e44171ffd48b591d19256884a969fe4da17caryclark            if (test != end) {
1704ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                FAIL_IF(!test->upCastable(), coin);
1705ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                priorT = test->t();
170626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                test = test->upCast()->next();
170726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
170855888e44171ffd48b591d19256884a969fe4da17caryclark            if (oTest != oEnd) {
1709ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                oPriorT = oTest->t();
171055888e44171ffd48b591d19256884a969fe4da17caryclark                oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next();
1711ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                FAIL_IF(!oTest, coin);
171226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
171326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
171455888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((coin = coin->next()));
171555888e44171ffd48b591d19256884a969fe4da17caryclark    return;
171655888e44171ffd48b591d19256884a969fe4da17caryclark}
171755888e44171ffd48b591d19256884a969fe4da17caryclark
171855888e44171ffd48b591d19256884a969fe4da17caryclark/* Commented-out lines keep this in sync addIfMissing() */
17198016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark// note that over1s, over1e, over2s, over2e are ordered
1720ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugAddIfMissing(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* over1s, const SkOpPtT* over2s,
172181a478ca6c36aac3e53ce0373a281ac8940f4780caryclark        double tStart, double tEnd, const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, bool* added,
17228016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        const SkOpPtT* over1e, const SkOpPtT* over2e) const {
17238016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(tStart < tEnd);
17248016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(over1s->fT < over1e->fT);
17258016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(between(over1s->fT, tStart, over1e->fT));
17268016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(between(over1s->fT, tEnd, over1e->fT));
17278016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(over2s->fT < over2e->fT);
17288016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(between(over2s->fT, tStart, over2e->fT));
17298016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(between(over2s->fT, tEnd, over2e->fT));
17308016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(over1s->segment() == over1e->segment());
17318016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(over2s->segment() == over2e->segment());
17328016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(over1s->segment() == over2s->segment());
17338016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(over1s->segment() != coinSeg);
17348016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(over1s->segment() != oppSeg);
17358016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    SkASSERT(coinSeg != oppSeg);
173626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    double coinTs, coinTe, oppTs, oppTe;
17378016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    coinTs = TRange(over1s, tStart, coinSeg  SkDEBUGPARAMS(over1e));
17388016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    coinTe = TRange(over1s, tEnd, coinSeg  SkDEBUGPARAMS(over1e));
17398016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    if (coinSeg->collapsed(coinTs, coinTe)) {
1740ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, coinSeg);
174126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
17428016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    oppTs = TRange(over2s, tStart, oppSeg  SkDEBUGPARAMS(over2e));
17438016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    oppTe = TRange(over2s, tEnd, oppSeg  SkDEBUGPARAMS(over2e));
17448016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    if (oppSeg->collapsed(oppTs, oppTe)) {
1745ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, oppSeg);
174626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
17478016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    if (coinTs > coinTe) {
17488016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        SkTSwap(coinTs, coinTe);
174926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        SkTSwap(oppTs, oppTe);
175026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
1751ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return this->debugAddOrOverlap(log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added
17528016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            );
175355888e44171ffd48b591d19256884a969fe4da17caryclark}
175455888e44171ffd48b591d19256884a969fe4da17caryclark
175555888e44171ffd48b591d19256884a969fe4da17caryclark/* Commented-out lines keep this in sync addOrOverlap() */
175630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// If this is called by addEndMovedSpans(), a returned false propogates out to an abort.
175730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// If this is called by AddIfMissing(), a returned false indicates there was nothing to add
1758ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugAddOrOverlap(SkPathOpsDebug::GlitchLog* log,
175930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
176081a478ca6c36aac3e53ce0373a281ac8940f4780caryclark        double coinTs, double coinTe, double oppTs, double oppTe, bool* added) const {
176155888e44171ffd48b591d19256884a969fe4da17caryclark    SkTDArray<SkCoincidentSpans*> overlaps;
1762ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkOPASSERT(!fTop);   // this is (correctly) reversed in addifMissing()
176381a478ca6c36aac3e53ce0373a281ac8940f4780caryclark    if (fTop && !this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe,
176481a478ca6c36aac3e53ce0373a281ac8940f4780caryclark            &overlaps)) {
176555888e44171ffd48b591d19256884a969fe4da17caryclark        return;
176655888e44171ffd48b591d19256884a969fe4da17caryclark    }
176755888e44171ffd48b591d19256884a969fe4da17caryclark    if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
176855888e44171ffd48b591d19256884a969fe4da17caryclark            coinTe, oppTs, oppTe, &overlaps)) {
176955888e44171ffd48b591d19256884a969fe4da17caryclark        return;
177055888e44171ffd48b591d19256884a969fe4da17caryclark    }
177155888e44171ffd48b591d19256884a969fe4da17caryclark    const SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
177255888e44171ffd48b591d19256884a969fe4da17caryclark    for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
177355888e44171ffd48b591d19256884a969fe4da17caryclark        const SkCoincidentSpans* test = overlaps[index];
177455888e44171ffd48b591d19256884a969fe4da17caryclark        if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
1775ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->coinPtTStart());
177655888e44171ffd48b591d19256884a969fe4da17caryclark        }
177755888e44171ffd48b591d19256884a969fe4da17caryclark        if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
1778ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->coinPtTEnd());
177955888e44171ffd48b591d19256884a969fe4da17caryclark        }
178055888e44171ffd48b591d19256884a969fe4da17caryclark        if (overlap->flipped()
178155888e44171ffd48b591d19256884a969fe4da17caryclark                ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
178255888e44171ffd48b591d19256884a969fe4da17caryclark                : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
1783ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->oppPtTStart());
178455888e44171ffd48b591d19256884a969fe4da17caryclark        }
178555888e44171ffd48b591d19256884a969fe4da17caryclark        if (overlap->flipped()
178655888e44171ffd48b591d19256884a969fe4da17caryclark                ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
178755888e44171ffd48b591d19256884a969fe4da17caryclark                : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
1788ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->oppPtTEnd());
178955888e44171ffd48b591d19256884a969fe4da17caryclark        }
1790ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (!fHead) { this->debugRelease(log, fHead, test);
1791ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            this->debugRelease(log, fTop, test);
179255888e44171ffd48b591d19256884a969fe4da17caryclark        }
179355888e44171ffd48b591d19256884a969fe4da17caryclark    }
179455888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
179555888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
179630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(overlap && cs && ce && overlap->contains(cs, ce), coinSeg);
179730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(cs != ce || !cs, coinSeg);
179855888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
179955888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
180030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(overlap && os && oe && overlap->contains(os, oe), oppSeg);
180155888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(true || !cs || !cs->deleted());
180255888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(true || !os || !os->deleted());
180355888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(true || !ce || !ce->deleted());
180455888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(true || !oe || !oe->deleted());
180555888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
180655888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
180730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(csExisting && csExisting == ceExisting, coinSeg);
180830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(csExisting && (csExisting == ce ||
180930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            csExisting->contains(ceExisting ? ceExisting : ce)), coinSeg);
181030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(ceExisting && (ceExisting == cs ||
181130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            ceExisting->contains(csExisting ? csExisting : cs)), coinSeg);
181255888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
181355888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr;
181430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(osExisting && osExisting == oeExisting, oppSeg);
181530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(osExisting && (osExisting == oe ||
181630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            osExisting->contains(oeExisting ? oeExisting : oe)), oppSeg);
181730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(oeExisting && (oeExisting == os ||
181830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            oeExisting->contains(osExisting ? osExisting : os)), oppSeg);
181955888e44171ffd48b591d19256884a969fe4da17caryclark    bool csDeleted = false, osDeleted = false, ceDeleted = false,  oeDeleted = false;
182055888e44171ffd48b591d19256884a969fe4da17caryclark    this->debugValidate();
182155888e44171ffd48b591d19256884a969fe4da17caryclark    if (!cs || !os) {
182255888e44171ffd48b591d19256884a969fe4da17caryclark        if (!cs)
1823ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            cs = coinSeg->debugAddT(coinTs, log);
182455888e44171ffd48b591d19256884a969fe4da17caryclark        if (!os)
1825ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            os = oppSeg->debugAddT(oppTs, log);
182630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//      RETURN_FALSE_IF(callerAborts, !csWritable || !osWritable);
1827ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (cs && os) cs->span()->debugAddOpp(log, os->span());
182855888e44171ffd48b591d19256884a969fe4da17caryclark//         cs = csWritable;
182930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//         os = osWritable->active();
183030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        RETURN_FALSE_IF((ce && ce->deleted()) || (oe && oe->deleted()), coinSeg);
183155888e44171ffd48b591d19256884a969fe4da17caryclark    }
183255888e44171ffd48b591d19256884a969fe4da17caryclark    if (!ce || !oe) {
183355888e44171ffd48b591d19256884a969fe4da17caryclark        if (!ce)
1834ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            ce = coinSeg->debugAddT(coinTe, log);
183555888e44171ffd48b591d19256884a969fe4da17caryclark        if (!oe)
1836ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            oe = oppSeg->debugAddT(oppTe, log);
1837ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (ce && oe) ce->span()->debugAddOpp(log, oe->span());
183855888e44171ffd48b591d19256884a969fe4da17caryclark//         ce = ceWritable;
183955888e44171ffd48b591d19256884a969fe4da17caryclark//         oe = oeWritable;
184055888e44171ffd48b591d19256884a969fe4da17caryclark    }
184155888e44171ffd48b591d19256884a969fe4da17caryclark    this->debugValidate();
184230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(csDeleted, coinSeg);
184330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(osDeleted, oppSeg);
184430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(ceDeleted, coinSeg);
184530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    RETURN_FALSE_IF(oeDeleted, oppSeg);
18468016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    RETURN_FALSE_IF(!cs || !ce || cs == ce || cs->contains(ce) || !os || !oe || os == oe || os->contains(oe), coinSeg);
18478016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    bool result = true;
184855888e44171ffd48b591d19256884a969fe4da17caryclark    if (overlap) {
184955888e44171ffd48b591d19256884a969fe4da17caryclark        if (overlap->coinPtTStart()->segment() == coinSeg) {
1850ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe);
185155888e44171ffd48b591d19256884a969fe4da17caryclark        } else {
185255888e44171ffd48b591d19256884a969fe4da17caryclark            if (oppTs > oppTe) {
185355888e44171ffd48b591d19256884a969fe4da17caryclark                SkTSwap(coinTs, coinTe);
185455888e44171ffd48b591d19256884a969fe4da17caryclark                SkTSwap(oppTs, oppTe);
185555888e44171ffd48b591d19256884a969fe4da17caryclark            }
1856ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, oppSeg, oppTs, oppTe, coinSeg, coinTs, coinTe);
185755888e44171ffd48b591d19256884a969fe4da17caryclark        }
18588016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark#if 0 && DEBUG_COINCIDENCE_VERBOSE
18598016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        if (result) {
18608016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark             overlap->debugShow();
18618016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        }
186255888e44171ffd48b591d19256884a969fe4da17caryclark#endif
186355888e44171ffd48b591d19256884a969fe4da17caryclark    } else {
1864ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        log->record(SkPathOpsDebug::kAddMissingCoin_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe);
18658016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark#if 0 && DEBUG_COINCIDENCE_VERBOSE
18668016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        fHead->debugShow();
186755888e44171ffd48b591d19256884a969fe4da17caryclark#endif
186855888e44171ffd48b591d19256884a969fe4da17caryclark    }
186955888e44171ffd48b591d19256884a969fe4da17caryclark    this->debugValidate();
18708016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    return (void) result;
187126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
187226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
187355888e44171ffd48b591d19256884a969fe4da17caryclark// Extra commented-out lines keep this in sync with addMissing()
187455888e44171ffd48b591d19256884a969fe4da17caryclark/* detects overlaps of different coincident runs on same segment */
187555888e44171ffd48b591d19256884a969fe4da17caryclark/* does not detect overlaps for pairs without any segments in common */
187655888e44171ffd48b591d19256884a969fe4da17caryclark// returns true if caller should loop again
1877ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugAddMissing(SkPathOpsDebug::GlitchLog* log, bool* added) const {
187826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkCoincidentSpans* outer = fHead;
1879ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    *added = false;
188026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (!outer) {
188126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        return;
188226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
188355888e44171ffd48b591d19256884a969fe4da17caryclark    // fTop = outer;
188455888e44171ffd48b591d19256884a969fe4da17caryclark    // fHead = nullptr;
188526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
188626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    // addifmissing can modify the list that this is walking
188726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    // save head so that walker can iterate over old data unperturbed
188826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    // addifmissing adds to head freely then add saved head in the end
18898016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        const SkOpPtT* ocs = outer->coinPtTStart();
18908016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        SkASSERT(!ocs->deleted());
18918016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        const SkOpSegment* outerCoin = ocs->segment();
18928016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        SkASSERT(!outerCoin->done());  // if it's done, should have already been removed from list
18938016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        const SkOpPtT* oos = outer->oppPtTStart();
1894ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (oos->deleted()) {
1895ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            return;
1896ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
18978016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        const SkOpSegment* outerOpp = oos->segment();
18988016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark        SkASSERT(!outerOpp->done());
18998016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark//        SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin);
19008016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark//        SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp);
190126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkCoincidentSpans* inner = outer;
190255888e44171ffd48b591d19256884a969fe4da17caryclark        while ((inner = inner->next())) {
190355888e44171ffd48b591d19256884a969fe4da17caryclark            this->debugValidate();
190426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            double overS, overE;
19058016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            const SkOpPtT* ics = inner->coinPtTStart();
19068016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkASSERT(!ics->deleted());
19078016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            const SkOpSegment* innerCoin = ics->segment();
19088016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkASSERT(!innerCoin->done());
19098016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            const SkOpPtT* ios = inner->oppPtTStart();
19108016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkASSERT(!ios->deleted());
19118016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            const SkOpSegment* innerOpp = ios->segment();
19128016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark            SkASSERT(!innerOpp->done());
19138016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark//            SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin);
19148016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark//            SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp);
191555888e44171ffd48b591d19256884a969fe4da17caryclark            if (outerCoin == innerCoin) {
19168016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* oce = outer->coinPtTEnd();
1917ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                if (oce->deleted()) {
1918ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    return;
1919ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                }
19208016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* ice = inner->coinPtTEnd();
19218016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                SkASSERT(!ice->deleted());
19228016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
1923ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    this->debugAddIfMissing(log, ocs->starter(oce), ics->starter(ice),
192481a478ca6c36aac3e53ce0373a281ac8940f4780caryclark                            overS, overE, outerOpp, innerOpp, added,
19258016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            ocs->debugEnder(oce),
19268016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            ics->debugEnder(ice));
192726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
192855888e44171ffd48b591d19256884a969fe4da17caryclark            } else if (outerCoin == innerOpp) {
19298016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* oce = outer->coinPtTEnd();
19308016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                SkASSERT(!oce->deleted());
19318016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* ioe = inner->oppPtTEnd();
19328016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                SkASSERT(!ioe->deleted());
19338016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) {
1934ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    this->debugAddIfMissing(log, ocs->starter(oce), ios->starter(ioe),
193581a478ca6c36aac3e53ce0373a281ac8940f4780caryclark                            overS, overE, outerOpp, innerCoin, added,
19368016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            ocs->debugEnder(oce),
19378016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            ios->debugEnder(ioe));
193826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
193955888e44171ffd48b591d19256884a969fe4da17caryclark            } else if (outerOpp == innerCoin) {
19408016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* ooe = outer->oppPtTEnd();
19418016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                SkASSERT(!ooe->deleted());
19428016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* ice = inner->coinPtTEnd();
19438016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                SkASSERT(!ice->deleted());
194455888e44171ffd48b591d19256884a969fe4da17caryclark                SkASSERT(outerCoin != innerOpp);
19458016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
1946ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    this->debugAddIfMissing(log, oos->starter(ooe), ics->starter(ice),
194781a478ca6c36aac3e53ce0373a281ac8940f4780caryclark                            overS, overE, outerCoin, innerOpp, added,
19488016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            oos->debugEnder(ooe),
19498016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            ics->debugEnder(ice));
195026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
195155888e44171ffd48b591d19256884a969fe4da17caryclark            } else if (outerOpp == innerOpp) {
19528016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* ooe = outer->oppPtTEnd();
19538016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                SkASSERT(!ooe->deleted());
19548016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                const SkOpPtT* ioe = inner->oppPtTEnd();
1955ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                if (ioe->deleted()) {
1956ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    return;
1957ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                }
195855888e44171ffd48b591d19256884a969fe4da17caryclark                SkASSERT(outerCoin != innerCoin);
19598016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) {
1960ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    this->debugAddIfMissing(log, oos->starter(ooe), ios->starter(ioe),
196181a478ca6c36aac3e53ce0373a281ac8940f4780caryclark                            overS, overE, outerCoin, innerCoin, added,
19628016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            oos->debugEnder(ooe),
19638016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark                            ios->debugEnder(ioe));
196426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                }
196526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
196655888e44171ffd48b591d19256884a969fe4da17caryclark            this->debugValidate();
196755888e44171ffd48b591d19256884a969fe4da17caryclark        }
196855888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((outer = outer->next()));
196955888e44171ffd48b591d19256884a969fe4da17caryclark    // this->restoreHead();
197055888e44171ffd48b591d19256884a969fe4da17caryclark    return;
197155888e44171ffd48b591d19256884a969fe4da17caryclark}
197255888e44171ffd48b591d19256884a969fe4da17caryclark
197355888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with release()
1974ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugRelease(SkPathOpsDebug::GlitchLog* log, const SkCoincidentSpans* coin, const SkCoincidentSpans* remove) const {
197530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkCoincidentSpans* head = coin;
197630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkCoincidentSpans* prev = nullptr;
197730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkCoincidentSpans* next;
197830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    do {
197930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        next = coin->next();
198030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        if (coin == remove) {
198130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            if (prev) {
198230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//                prev->setNext(next);
198330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            } else if (head == fHead) {
198430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//                fHead = next;
198530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            } else {
198630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//                fTop = next;
198730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            }
1988ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin);
198930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        }
199030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        prev = coin;
199130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    } while ((coin = next));
199230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    return;
199330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark}
199430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark
1995ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugRelease(SkPathOpsDebug::GlitchLog* log, const SkOpSegment* deleted) const {
199655888e44171ffd48b591d19256884a969fe4da17caryclark    const SkCoincidentSpans* coin = fHead;
199755888e44171ffd48b591d19256884a969fe4da17caryclark    if (!coin) {
199855888e44171ffd48b591d19256884a969fe4da17caryclark        return;
199955888e44171ffd48b591d19256884a969fe4da17caryclark    }
200055888e44171ffd48b591d19256884a969fe4da17caryclark    do {
200155888e44171ffd48b591d19256884a969fe4da17caryclark        if (coin->coinPtTStart()->segment() == deleted
200255888e44171ffd48b591d19256884a969fe4da17caryclark                || coin->coinPtTEnd()->segment() == deleted
200355888e44171ffd48b591d19256884a969fe4da17caryclark                || coin->oppPtTStart()->segment() == deleted
200455888e44171ffd48b591d19256884a969fe4da17caryclark                || coin->oppPtTEnd()->segment() == deleted) {
2005ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin);
200630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        }
200755888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((coin = coin->next()));
200826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
200926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
201055888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with expand()
201155888e44171ffd48b591d19256884a969fe4da17caryclark// expand the range by checking adjacent spans for coincidence
2012ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkbool SkOpCoincidence::debugExpand(SkPathOpsDebug::GlitchLog* log) const {
201326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkCoincidentSpans* coin = fHead;
201426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (!coin) {
201526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        return false;
201626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
201726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    bool expanded = false;
201826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
2019ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (coin->debugExpand(log)) {
202055888e44171ffd48b591d19256884a969fe4da17caryclark            // check to see if multiple spans expanded so they are now identical
202155888e44171ffd48b591d19256884a969fe4da17caryclark            const SkCoincidentSpans* test = fHead;
202255888e44171ffd48b591d19256884a969fe4da17caryclark            do {
202355888e44171ffd48b591d19256884a969fe4da17caryclark                if (coin == test) {
202455888e44171ffd48b591d19256884a969fe4da17caryclark                    continue;
202555888e44171ffd48b591d19256884a969fe4da17caryclark                }
202655888e44171ffd48b591d19256884a969fe4da17caryclark                if (coin->coinPtTStart() == test->coinPtTStart()
202755888e44171ffd48b591d19256884a969fe4da17caryclark                        && coin->oppPtTStart() == test->oppPtTStart()) {
2028ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, fHead, test->coinPtTStart());
202955888e44171ffd48b591d19256884a969fe4da17caryclark                    break;
203055888e44171ffd48b591d19256884a969fe4da17caryclark                }
203155888e44171ffd48b591d19256884a969fe4da17caryclark            } while ((test = test->next()));
203255888e44171ffd48b591d19256884a969fe4da17caryclark            expanded = true;
203326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
203455888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((coin = coin->next()));
203526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    return expanded;
203626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
203726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
203855888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with mark()
203955888e44171ffd48b591d19256884a969fe4da17caryclark/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */
2040ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugMark(SkPathOpsDebug::GlitchLog* log) const {
204126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkCoincidentSpans* coin = fHead;
204226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (!coin) {
204326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        return;
204426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
204526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
2046ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        FAIL_IF(!coin->coinPtTStartWritable()->span()->upCastable(), coin);
204755888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast();
204855888e44171ffd48b591d19256884a969fe4da17caryclark//         SkASSERT(start->deleted());
204955888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
205055888e44171ffd48b591d19256884a969fe4da17caryclark//         SkASSERT(end->deleted());
205155888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
205255888e44171ffd48b591d19256884a969fe4da17caryclark//         SkASSERT(oStart->deleted());
205355888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
205455888e44171ffd48b591d19256884a969fe4da17caryclark//         SkASSERT(oEnd->deleted());
205555888e44171ffd48b591d19256884a969fe4da17caryclark        bool flipped = coin->flipped();
205626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (flipped) {
205726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkTSwap(oStart, oEnd);
205826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
205955888e44171ffd48b591d19256884a969fe4da17caryclark        /* coin and opp spans may not match up. Mark the ends, and then let the interior
206055888e44171ffd48b591d19256884a969fe4da17caryclark           get marked as many times as the spans allow */
2061ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        start->debugInsertCoincidence(log, oStart->upCast());
2062ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        end->debugInsertCoinEnd(log, oEnd);
206355888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSegment* segment = start->segment();
206455888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpSegment* oSegment = oStart->segment();
206526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpSpanBase* next = start;
206626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpSpanBase* oNext = oStart;
2067a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark        bool ordered;
2068a35ab3e6e024d0b548ded26a2e3b8ecd838ead93caryclark        FAIL_IF(!coin->ordered(&ordered), coin);
206955888e44171ffd48b591d19256884a969fe4da17caryclark        while ((next = next->upCast()->next()) != end) {
2070ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            FAIL_IF(!next->upCastable(), coin);
2071ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (next->upCast()->debugInsertCoincidence(log, oSegment, flipped, ordered), false) {
207255888e44171ffd48b591d19256884a969fe4da17caryclark                return;
207326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
207455888e44171ffd48b591d19256884a969fe4da17caryclark        }
207555888e44171ffd48b591d19256884a969fe4da17caryclark        while ((oNext = oNext->upCast()->next()) != oEnd) {
2076ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            FAIL_IF(!oNext->upCastable(), coin);
2077ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (oNext->upCast()->debugInsertCoincidence(log, segment, flipped, ordered), false) {
207855888e44171ffd48b591d19256884a969fe4da17caryclark                return;
207926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
208055888e44171ffd48b591d19256884a969fe4da17caryclark        }
208155888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((coin = coin->next()));
208255888e44171ffd48b591d19256884a969fe4da17caryclark    return;
208355888e44171ffd48b591d19256884a969fe4da17caryclark}
208455888e44171ffd48b591d19256884a969fe4da17caryclark#endif
208555888e44171ffd48b591d19256884a969fe4da17caryclark
2086ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
208755888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with markCollapsed()
2088ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugMarkCollapsed(SkPathOpsDebug::GlitchLog* log, const SkCoincidentSpans* coin, const SkOpPtT* test) const {
208930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkCoincidentSpans* head = coin;
209055888e44171ffd48b591d19256884a969fe4da17caryclark    while (coin) {
209155888e44171ffd48b591d19256884a969fe4da17caryclark        if (coin->collapsed(test)) {
209255888e44171ffd48b591d19256884a969fe4da17caryclark            if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) {
2093ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin);
209426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
209555888e44171ffd48b591d19256884a969fe4da17caryclark            if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) {
2096ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin);
209755888e44171ffd48b591d19256884a969fe4da17caryclark            }
2098ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            this->debugRelease(log, head, coin);
209955888e44171ffd48b591d19256884a969fe4da17caryclark        }
210055888e44171ffd48b591d19256884a969fe4da17caryclark        coin = coin->next();
210155888e44171ffd48b591d19256884a969fe4da17caryclark    }
210255888e44171ffd48b591d19256884a969fe4da17caryclark}
210355888e44171ffd48b591d19256884a969fe4da17caryclark
210455888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with markCollapsed()
2105ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugMarkCollapsed(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* test) const {
2106ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugMarkCollapsed(log, fHead, test);
2107ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugMarkCollapsed(log, fTop, test);
210826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
210926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
211026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
211155888e44171ffd48b591d19256884a969fe4da17caryclarkvoid SkCoincidentSpans::debugShow() const {
21126c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    SkDebugf("coinSpan - id=%d t=%1.9g tEnd=%1.9g\n", coinPtTStart()->segment()->debugID(),
211355888e44171ffd48b591d19256884a969fe4da17caryclark            coinPtTStart()->fT, coinPtTEnd()->fT);
21146c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    SkDebugf("coinSpan + id=%d t=%1.9g tEnd=%1.9g\n", oppPtTStart()->segment()->debugID(),
211555888e44171ffd48b591d19256884a969fe4da17caryclark            oppPtTStart()->fT, oppPtTEnd()->fT);
211655888e44171ffd48b591d19256884a969fe4da17caryclark}
211755888e44171ffd48b591d19256884a969fe4da17caryclark
2118624637cc8ec22c000409704d0b403ac1b81ad4b0caryclarkvoid SkOpCoincidence::debugShowCoincidence() const {
211955888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
212055888e44171ffd48b591d19256884a969fe4da17caryclark    const SkCoincidentSpans* span = fHead;
2121624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    while (span) {
212255888e44171ffd48b591d19256884a969fe4da17caryclark        span->debugShow();
212355888e44171ffd48b591d19256884a969fe4da17caryclark        span = span->next();
2124624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    }
212555888e44171ffd48b591d19256884a969fe4da17caryclark#endif
2126624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark}
2127624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark
2128ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
21296c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclarkstatic void DebugCheckBetween(const SkOpSpanBase* next, const SkOpSpanBase* end,
213055888e44171ffd48b591d19256884a969fe4da17caryclark        double oStart, double oEnd, const SkOpSegment* oSegment,
2131ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkPathOpsDebug::GlitchLog* log) {
213255888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(next != end);
213355888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(!next->contains(end) || log);
213455888e44171ffd48b591d19256884a969fe4da17caryclark    if (next->t() > end->t()) {
213555888e44171ffd48b591d19256884a969fe4da17caryclark        SkTSwap(next, end);
213655888e44171ffd48b591d19256884a969fe4da17caryclark    }
213755888e44171ffd48b591d19256884a969fe4da17caryclark    do {
213855888e44171ffd48b591d19256884a969fe4da17caryclark        const SkOpPtT* ptT = next->ptT();
213955888e44171ffd48b591d19256884a969fe4da17caryclark        int index = 0;
214027c015dfcf4e2b8fb1abe327cc40204e2a4f452acaryclark        bool somethingBetween = false;
214155888e44171ffd48b591d19256884a969fe4da17caryclark        do {
214255888e44171ffd48b591d19256884a969fe4da17caryclark            ++index;
214355888e44171ffd48b591d19256884a969fe4da17caryclark            ptT = ptT->next();
214455888e44171ffd48b591d19256884a969fe4da17caryclark            const SkOpPtT* checkPtT = next->ptT();
214555888e44171ffd48b591d19256884a969fe4da17caryclark            if (ptT == checkPtT) {
214655888e44171ffd48b591d19256884a969fe4da17caryclark                break;
214755888e44171ffd48b591d19256884a969fe4da17caryclark            }
214855888e44171ffd48b591d19256884a969fe4da17caryclark            bool looped = false;
214955888e44171ffd48b591d19256884a969fe4da17caryclark            for (int check = 0; check < index; ++check) {
215055888e44171ffd48b591d19256884a969fe4da17caryclark                if ((looped = checkPtT == ptT)) {
215155888e44171ffd48b591d19256884a969fe4da17caryclark                    break;
215255888e44171ffd48b591d19256884a969fe4da17caryclark                }
215355888e44171ffd48b591d19256884a969fe4da17caryclark                checkPtT = checkPtT->next();
215455888e44171ffd48b591d19256884a969fe4da17caryclark            }
215555888e44171ffd48b591d19256884a969fe4da17caryclark            if (looped) {
215655888e44171ffd48b591d19256884a969fe4da17caryclark                SkASSERT(0);
215755888e44171ffd48b591d19256884a969fe4da17caryclark                break;
215855888e44171ffd48b591d19256884a969fe4da17caryclark            }
215955888e44171ffd48b591d19256884a969fe4da17caryclark            if (ptT->deleted()) {
216055888e44171ffd48b591d19256884a969fe4da17caryclark                continue;
216155888e44171ffd48b591d19256884a969fe4da17caryclark            }
216255888e44171ffd48b591d19256884a969fe4da17caryclark            if (ptT->segment() != oSegment) {
216355888e44171ffd48b591d19256884a969fe4da17caryclark                continue;
216455888e44171ffd48b591d19256884a969fe4da17caryclark            }
216555888e44171ffd48b591d19256884a969fe4da17caryclark            somethingBetween |= between(oStart, ptT->fT, oEnd);
216655888e44171ffd48b591d19256884a969fe4da17caryclark        } while (true);
216755888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(somethingBetween);
216855888e44171ffd48b591d19256884a969fe4da17caryclark    } while (next != end && (next = next->upCast()->next()));
216955888e44171ffd48b591d19256884a969fe4da17caryclark}
217055888e44171ffd48b591d19256884a969fe4da17caryclark
217155888e44171ffd48b591d19256884a969fe4da17caryclarkstatic void DebugCheckOverlap(const SkCoincidentSpans* test, const SkCoincidentSpans* list,
2172ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkPathOpsDebug::GlitchLog* log) {
217355888e44171ffd48b591d19256884a969fe4da17caryclark    if (!list) {
217455888e44171ffd48b591d19256884a969fe4da17caryclark        return;
217555888e44171ffd48b591d19256884a969fe4da17caryclark    }
217655888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSegment* coinSeg = test->coinPtTStart()->segment();
217755888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(coinSeg == test->coinPtTEnd()->segment());
217855888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpSegment* oppSeg = test->oppPtTStart()->segment();
217955888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(oppSeg == test->oppPtTEnd()->segment());
218055888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(coinSeg != test->oppPtTStart()->segment());
218155888e44171ffd48b591d19256884a969fe4da17caryclark    SkDEBUGCODE(double tcs = test->coinPtTStart()->fT);
218255888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(between(0, tcs, 1));
218355888e44171ffd48b591d19256884a969fe4da17caryclark    SkDEBUGCODE(double tce = test->coinPtTEnd()->fT);
218455888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(between(0, tce, 1));
218555888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(tcs < tce);
218655888e44171ffd48b591d19256884a969fe4da17caryclark    double tos = test->oppPtTStart()->fT;
218755888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(between(0, tos, 1));
218855888e44171ffd48b591d19256884a969fe4da17caryclark    double toe = test->oppPtTEnd()->fT;
218955888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(between(0, toe, 1));
219055888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(tos != toe);
219155888e44171ffd48b591d19256884a969fe4da17caryclark    if (tos > toe) {
219255888e44171ffd48b591d19256884a969fe4da17caryclark        SkTSwap(tos, toe);
219355888e44171ffd48b591d19256884a969fe4da17caryclark    }
219455888e44171ffd48b591d19256884a969fe4da17caryclark    do {
219555888e44171ffd48b591d19256884a969fe4da17caryclark        double lcs, lce, los, loe;
219655888e44171ffd48b591d19256884a969fe4da17caryclark        if (coinSeg == list->coinPtTStart()->segment()) {
219755888e44171ffd48b591d19256884a969fe4da17caryclark            if (oppSeg != list->oppPtTStart()->segment()) {
219855888e44171ffd48b591d19256884a969fe4da17caryclark                continue;
219955888e44171ffd48b591d19256884a969fe4da17caryclark            }
220055888e44171ffd48b591d19256884a969fe4da17caryclark            lcs = list->coinPtTStart()->fT;
220155888e44171ffd48b591d19256884a969fe4da17caryclark            lce = list->coinPtTEnd()->fT;
220255888e44171ffd48b591d19256884a969fe4da17caryclark            los = list->oppPtTStart()->fT;
220355888e44171ffd48b591d19256884a969fe4da17caryclark            loe = list->oppPtTEnd()->fT;
220455888e44171ffd48b591d19256884a969fe4da17caryclark            if (los > loe) {
220555888e44171ffd48b591d19256884a969fe4da17caryclark                SkTSwap(los, loe);
220655888e44171ffd48b591d19256884a969fe4da17caryclark            }
220755888e44171ffd48b591d19256884a969fe4da17caryclark        } else if (coinSeg == list->oppPtTStart()->segment()) {
220855888e44171ffd48b591d19256884a969fe4da17caryclark            if (oppSeg != list->coinPtTStart()->segment()) {
220955888e44171ffd48b591d19256884a969fe4da17caryclark                continue;
221055888e44171ffd48b591d19256884a969fe4da17caryclark            }
221155888e44171ffd48b591d19256884a969fe4da17caryclark            lcs = list->oppPtTStart()->fT;
221255888e44171ffd48b591d19256884a969fe4da17caryclark            lce = list->oppPtTEnd()->fT;
221355888e44171ffd48b591d19256884a969fe4da17caryclark            if (lcs > lce) {
221455888e44171ffd48b591d19256884a969fe4da17caryclark                SkTSwap(lcs, lce);
221555888e44171ffd48b591d19256884a969fe4da17caryclark            }
221655888e44171ffd48b591d19256884a969fe4da17caryclark            los = list->coinPtTStart()->fT;
221755888e44171ffd48b591d19256884a969fe4da17caryclark            loe = list->coinPtTEnd()->fT;
221855888e44171ffd48b591d19256884a969fe4da17caryclark        } else {
221955888e44171ffd48b591d19256884a969fe4da17caryclark            continue;
222055888e44171ffd48b591d19256884a969fe4da17caryclark        }
222155888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(tce < lcs || lce < tcs);
222255888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(toe < los || loe < tos);
222355888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((list = list->next()));
222455888e44171ffd48b591d19256884a969fe4da17caryclark}
222555888e44171ffd48b591d19256884a969fe4da17caryclark
222655888e44171ffd48b591d19256884a969fe4da17caryclark
222755888e44171ffd48b591d19256884a969fe4da17caryclarkstatic void DebugCheckOverlapTop(const SkCoincidentSpans* head, const SkCoincidentSpans* opt,
2228ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkPathOpsDebug::GlitchLog* log) {
222955888e44171ffd48b591d19256884a969fe4da17caryclark    // check for overlapping coincident spans
223055888e44171ffd48b591d19256884a969fe4da17caryclark    const SkCoincidentSpans* test = head;
223155888e44171ffd48b591d19256884a969fe4da17caryclark    while (test) {
223255888e44171ffd48b591d19256884a969fe4da17caryclark        const SkCoincidentSpans* next = test->next();
2233ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        DebugCheckOverlap(test, next, log);
2234ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        DebugCheckOverlap(test, opt, log);
223555888e44171ffd48b591d19256884a969fe4da17caryclark        test = next;
223655888e44171ffd48b591d19256884a969fe4da17caryclark    }
223755888e44171ffd48b591d19256884a969fe4da17caryclark}
223855888e44171ffd48b591d19256884a969fe4da17caryclark
223955888e44171ffd48b591d19256884a969fe4da17caryclarkstatic void DebugValidate(const SkCoincidentSpans* head, const SkCoincidentSpans* opt,
2240ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkPathOpsDebug::GlitchLog* log) {
224155888e44171ffd48b591d19256884a969fe4da17caryclark    // look for pts inside coincident spans that are not inside the opposite spans
224255888e44171ffd48b591d19256884a969fe4da17caryclark    const SkCoincidentSpans* coin = head;
224355888e44171ffd48b591d19256884a969fe4da17caryclark    while (coin) {
224455888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(SkOpCoincidence::Ordered(coin->coinPtTStart()->segment(),
224555888e44171ffd48b591d19256884a969fe4da17caryclark                coin->oppPtTStart()->segment()));
224655888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(coin->coinPtTStart()->span()->ptT() == coin->coinPtTStart());
224755888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(coin->coinPtTEnd()->span()->ptT() == coin->coinPtTEnd());
224855888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(coin->oppPtTStart()->span()->ptT() == coin->oppPtTStart());
224955888e44171ffd48b591d19256884a969fe4da17caryclark        SkASSERT(coin->oppPtTEnd()->span()->ptT() == coin->oppPtTEnd());
22506c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark        coin = coin->next();
22516c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    }
2252ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugCheckOverlapTop(head, opt, log);
22536c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark}
22546c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark#endif
22556c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark
22566c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclarkvoid SkOpCoincidence::debugValidate() const {
22576c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark#if DEBUG_COINCIDENCE
2258ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugValidate(fHead, fTop, nullptr);
2259ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugValidate(fTop, nullptr, nullptr);
22606c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark#endif
22616c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark}
22626c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark
2263ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
22646c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclarkstatic void DebugCheckBetween(const SkCoincidentSpans* head, const SkCoincidentSpans* opt,
2265ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        SkPathOpsDebug::GlitchLog* log) {
22666c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    // look for pts inside coincident spans that are not inside the opposite spans
22676c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    const SkCoincidentSpans* coin = head;
22686c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    while (coin) {
22696c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark        DebugCheckBetween(coin->coinPtTStart()->span(), coin->coinPtTEnd()->span(),
227055888e44171ffd48b591d19256884a969fe4da17caryclark                coin->oppPtTStart()->fT, coin->oppPtTEnd()->fT, coin->oppPtTStart()->segment(),
2271ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                log);
22726c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark        DebugCheckBetween(coin->oppPtTStart()->span(), coin->oppPtTEnd()->span(),
227355888e44171ffd48b591d19256884a969fe4da17caryclark                coin->coinPtTStart()->fT, coin->coinPtTEnd()->fT, coin->coinPtTStart()->segment(),
2274ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                log);
227555888e44171ffd48b591d19256884a969fe4da17caryclark        coin = coin->next();
227655888e44171ffd48b591d19256884a969fe4da17caryclark    }
2277ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugCheckOverlapTop(head, opt, log);
227855888e44171ffd48b591d19256884a969fe4da17caryclark}
227955888e44171ffd48b591d19256884a969fe4da17caryclark#endif
228055888e44171ffd48b591d19256884a969fe4da17caryclark
22816c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclarkvoid SkOpCoincidence::debugCheckBetween() const {
228255888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
22836c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    if (fGlobalState->debugCheckHealth()) {
22846c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark        return;
22856c3b9cdcb047afe963c7bcf34834ba2ecccacc33caryclark    }
2286ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugCheckBetween(fHead, fTop, nullptr);
2287ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugCheckBetween(fTop, nullptr, nullptr);
228855888e44171ffd48b591d19256884a969fe4da17caryclark#endif
228955888e44171ffd48b591d19256884a969fe4da17caryclark}
229055888e44171ffd48b591d19256884a969fe4da17caryclark
2291ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
2292ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpContour::debugCheckHealth(SkPathOpsDebug::GlitchLog* log) const {
2293ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSegment* segment = &fHead;
2294ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    do {
2295ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        segment->debugCheckHealth(log);
2296ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((segment = segment->next()));
229755888e44171ffd48b591d19256884a969fe4da17caryclark}
2298ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
2299ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugCheckValid(SkPathOpsDebug::GlitchLog* log) const {
2300ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_VALIDATE
2301ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugValidate(fHead, fTop, log);
2302ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    DebugValidate(fTop, nullptr, log);
230355888e44171ffd48b591d19256884a969fe4da17caryclark#endif
2304ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
230555888e44171ffd48b591d19256884a969fe4da17caryclark
2306ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpCoincidence::debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const {
2307ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkCoincidentSpans* coin = fHead;
2308ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (!coin) {
2309ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        return;
2310ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    }
231126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
2312ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        coin->debugCorrectEnds(log);
2313ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((coin = coin->next()));
231426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
231526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
231655888e44171ffd48b591d19256884a969fe4da17caryclark// commmented-out lines keep this aligned with missingCoincidence()
2317ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpContour::debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const {
231855888e44171ffd48b591d19256884a969fe4da17caryclark//    SkASSERT(fCount > 0);
231926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSegment* segment = &fHead;
232055888e44171ffd48b591d19256884a969fe4da17caryclark//    bool result = false;
232126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
2322e47ae2998c1cf944db5743a416583dd0f042b6d9Cary Clark        if (segment->debugMissingCoincidence(log), false) {
232355888e44171ffd48b591d19256884a969fe4da17caryclark//          result = true;
232455888e44171ffd48b591d19256884a969fe4da17caryclark        }
232555888e44171ffd48b591d19256884a969fe4da17caryclark        segment = segment->next();
232655888e44171ffd48b591d19256884a969fe4da17caryclark    } while (segment);
232755888e44171ffd48b591d19256884a969fe4da17caryclark    return;
232826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
2329ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
2330ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpContour::debugMoveMultiples(SkPathOpsDebug::GlitchLog* log) const {
2331ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkASSERT(fCount > 0);
2332ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSegment* segment = &fHead;
2333ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    do {
2334ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        if (segment->debugMoveMultiples(log), false) {
2335ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            return;
2336ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        }
2337ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((segment = segment->next()));
2338ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return;
2339ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
2340ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark
2341ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpContour::debugMoveNearby(SkPathOpsDebug::GlitchLog* log) const {
2342ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkASSERT(fCount > 0);
2343ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    const SkOpSegment* segment = &fHead;
2344ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    do {
2345ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        segment->debugMoveNearby(log);
2346ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    } while ((segment = segment->next()));
2347ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark}
234826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark#endif
234926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
2350025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#if DEBUG_COINCIDENCE_ORDER
2351025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclarkvoid SkOpSegment::debugResetCoinT() const {
2352025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    fDebugBaseIndex = -1;
2353025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    fDebugBaseMin = 1;
2354025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    fDebugBaseMax = -1;
2355025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    fDebugLastIndex = -1;
2356025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    fDebugLastMin = 1;
2357025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    fDebugLastMax = -1;
2358025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark}
2359025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#endif
2360025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark
23614431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.orgvoid SkOpSegment::debugValidate() const {
2362025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#if DEBUG_COINCIDENCE_ORDER
2363025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    {
2364025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        const SkOpSpanBase* span = &fHead;
2365025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        do {
2366025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark            span->debugResetCoinT();
2367025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        } while (!span->final() && (span = span->upCast()->next()));
2368025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        span = &fHead;
2369025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        int index = 0;
2370025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        do {
2371025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark            span->debugSetCoinT(index++);
2372025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        } while (!span->final() && (span = span->upCast()->next()));
2373025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    }
2374025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#endif
237555888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
237655888e44171ffd48b591d19256884a969fe4da17caryclark    if (this->globalState()->debugCheckHealth()) {
237755888e44171ffd48b591d19256884a969fe4da17caryclark        return;
237855888e44171ffd48b591d19256884a969fe4da17caryclark    }
237955888e44171ffd48b591d19256884a969fe4da17caryclark#endif
23804431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#if DEBUG_VALIDATE
238154359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpSpanBase* span = &fHead;
238254359294a7c9dc54802d512a5d891a35c1663392caryclark    double lastT = -1;
238396fcdcc219d2a0d3579719b84b28bede76efba64halcanary    const SkOpSpanBase* prev = nullptr;
238454359294a7c9dc54802d512a5d891a35c1663392caryclark    int count = 0;
23854431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int done = 0;
238654359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
238754359294a7c9dc54802d512a5d891a35c1663392caryclark        if (!span->final()) {
238854359294a7c9dc54802d512a5d891a35c1663392caryclark            ++count;
238954359294a7c9dc54802d512a5d891a35c1663392caryclark            done += span->upCast()->done() ? 1 : 0;
239054359294a7c9dc54802d512a5d891a35c1663392caryclark        }
239154359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(span->segment() == this);
239254359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(!prev || prev->upCast()->next() == span);
239354359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(!prev || prev == span->prev());
239454359294a7c9dc54802d512a5d891a35c1663392caryclark        prev = span;
239554359294a7c9dc54802d512a5d891a35c1663392caryclark        double t = span->ptT()->fT;
239654359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(lastT < t);
239754359294a7c9dc54802d512a5d891a35c1663392caryclark        lastT = t;
239854359294a7c9dc54802d512a5d891a35c1663392caryclark        span->debugValidate();
239954359294a7c9dc54802d512a5d891a35c1663392caryclark    } while (!span->final() && (span = span->upCast()->next()));
240054359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(count == fCount);
240154359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(done == fDoneCount);
240208bc8488fa2ea2d2a17efb1443f0ec6579d5a3c8caryclark    SkASSERT(count >= fDoneCount);
240354359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(span->final());
240454359294a7c9dc54802d512a5d891a35c1663392caryclark    span->debugValidate();
240554359294a7c9dc54802d512a5d891a35c1663392caryclark#endif
240654359294a7c9dc54802d512a5d891a35c1663392caryclark}
240754359294a7c9dc54802d512a5d891a35c1663392caryclark
2408ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
240930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark
241030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// Commented-out lines keep this in sync with addOpp()
2411ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSpanBase::debugAddOpp(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* opp) const {
241230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT());
241330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    if (!oppPrev) {
241455888e44171ffd48b591d19256884a969fe4da17caryclark        return;
241526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
2416ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugMergeMatches(log, opp);
241730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    this->ptT()->debugAddOpp(opp->ptT(), oppPrev);
2418ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugCheckForCollapsedCoincidence(log);
241926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
242026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
242155888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with checkForCollapsedCoincidence()
2422ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSpanBase::debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog* log) const {
242355888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpCoincidence* coins = this->globalState()->coincidence();
242455888e44171ffd48b591d19256884a969fe4da17caryclark    if (coins->isEmpty()) {
242555888e44171ffd48b591d19256884a969fe4da17caryclark        return;
242655888e44171ffd48b591d19256884a969fe4da17caryclark    }
242755888e44171ffd48b591d19256884a969fe4da17caryclark// the insert above may have put both ends of a coincident run in the same span
242855888e44171ffd48b591d19256884a969fe4da17caryclark// for each coincident ptT in loop; see if its opposite in is also in the loop
242955888e44171ffd48b591d19256884a969fe4da17caryclark// this implementation is the motivation for marking that a ptT is referenced by a coincident span
243055888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* head = this->ptT();
243155888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* test = head;
243226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
243355888e44171ffd48b591d19256884a969fe4da17caryclark        if (!test->coincident()) {
243455888e44171ffd48b591d19256884a969fe4da17caryclark            continue;
243526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
2436ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark        coins->debugMarkCollapsed(log, test);
243755888e44171ffd48b591d19256884a969fe4da17caryclark    } while ((test = test->next()) != head);
243826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
243955888e44171ffd48b591d19256884a969fe4da17caryclark#endif
244026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
244154359294a7c9dc54802d512a5d891a35c1663392caryclarkbool SkOpSpanBase::debugCoinEndLoopCheck() const {
244254359294a7c9dc54802d512a5d891a35c1663392caryclark    int loop = 0;
244354359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpSpanBase* next = this;
244454359294a7c9dc54802d512a5d891a35c1663392caryclark    SkOpSpanBase* nextCoin;
244554359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
244654359294a7c9dc54802d512a5d891a35c1663392caryclark        nextCoin = next->fCoinEnd;
244754359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin);
244854359294a7c9dc54802d512a5d891a35c1663392caryclark        for (int check = 1; check < loop - 1; ++check) {
244954359294a7c9dc54802d512a5d891a35c1663392caryclark            const SkOpSpanBase* checkCoin = this->fCoinEnd;
245054359294a7c9dc54802d512a5d891a35c1663392caryclark            const SkOpSpanBase* innerCoin = checkCoin;
245154359294a7c9dc54802d512a5d891a35c1663392caryclark            for (int inner = check + 1; inner < loop; ++inner) {
245254359294a7c9dc54802d512a5d891a35c1663392caryclark                innerCoin = innerCoin->fCoinEnd;
245354359294a7c9dc54802d512a5d891a35c1663392caryclark                if (checkCoin == innerCoin) {
245454359294a7c9dc54802d512a5d891a35c1663392caryclark                    SkDebugf("*** bad coincident end loop ***\n");
245554359294a7c9dc54802d512a5d891a35c1663392caryclark                    return false;
245654359294a7c9dc54802d512a5d891a35c1663392caryclark                }
245754359294a7c9dc54802d512a5d891a35c1663392caryclark            }
245854359294a7c9dc54802d512a5d891a35c1663392caryclark        }
245954359294a7c9dc54802d512a5d891a35c1663392caryclark        ++loop;
246054359294a7c9dc54802d512a5d891a35c1663392caryclark    } while ((next = nextCoin) && next != this);
246154359294a7c9dc54802d512a5d891a35c1663392caryclark    return true;
246254359294a7c9dc54802d512a5d891a35c1663392caryclark}
246354359294a7c9dc54802d512a5d891a35c1663392caryclark
2464ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
246555888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with insertCoinEnd()
2466ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSpanBase::debugInsertCoinEnd(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* coin) const {
246755888e44171ffd48b591d19256884a969fe4da17caryclark    if (containsCoinEnd(coin)) {
246855888e44171ffd48b591d19256884a969fe4da17caryclark//         SkASSERT(coin->containsCoinEnd(this));
246955888e44171ffd48b591d19256884a969fe4da17caryclark        return;
247055888e44171ffd48b591d19256884a969fe4da17caryclark    }
247155888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
247255888e44171ffd48b591d19256884a969fe4da17caryclark//     SkASSERT(this != coin);
2473ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    log->record(SkPathOpsDebug::kMarkCoinEnd_Glitch, this, coin);
247455888e44171ffd48b591d19256884a969fe4da17caryclark//     coin->fCoinEnd = this->fCoinEnd;
247555888e44171ffd48b591d19256884a969fe4da17caryclark//     this->fCoinEnd = coinNext;
247655888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
247755888e44171ffd48b591d19256884a969fe4da17caryclark}
247855888e44171ffd48b591d19256884a969fe4da17caryclark
247930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// Commented-out lines keep this in sync with mergeMatches()
248030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// Look to see if pt-t linked list contains same segment more than once
248130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// if so, and if each pt-t is directly pointed to by spans in that segment,
248230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// merge them
248330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// keep the points, but remove spans so that the segment doesn't have 2 or more
248430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark// spans pointing to the same pt-t loop at different loop elements
2485ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSpanBase::debugMergeMatches(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* opp) const {
248630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkOpPtT* test = &fPtT;
248730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkOpPtT* testNext;
248830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    const SkOpPtT* stop = test;
248930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    do {
249030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        testNext = test->next();
249130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        if (test->deleted()) {
249230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            continue;
249330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        }
249430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        const SkOpSpanBase* testBase = test->span();
249530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        SkASSERT(testBase->ptT() == test);
249630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        const SkOpSegment* segment = test->segment();
249730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        if (segment->done()) {
249830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            continue;
249930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        }
250030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        const SkOpPtT* inner = opp->ptT();
250130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        const SkOpPtT* innerStop = inner;
250230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        do {
250330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            if (inner->segment() != segment) {
250430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                continue;
250530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            }
250630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            if (inner->deleted()) {
250730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                continue;
250830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            }
250930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            const SkOpSpanBase* innerBase = inner->span();
251030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            SkASSERT(innerBase->ptT() == inner);
251130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            // when the intersection is first detected, the span base is marked if there are
251230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            // more than one point in the intersection.
251330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//            if (!innerBase->hasMultipleHint() && !testBase->hasMultipleHint()) {
251430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                if (!zero_or_one(inner->fT)) {
2515ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                    log->record(SkPathOpsDebug::kMergeMatches_Glitch, innerBase, test);
251630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                } else {
251730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    SkASSERT(inner->fT != test->fT);
251830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    if (!zero_or_one(test->fT)) {
2519ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        log->record(SkPathOpsDebug::kMergeMatches_Glitch, testBase, inner);
252030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    } else {
2521ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                        log->record(SkPathOpsDebug::kMergeMatches_Glitch, segment);
252230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//                        SkDEBUGCODE(testBase->debugSetDeleted());
252330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//                        test->setDeleted();
252430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//                        SkDEBUGCODE(innerBase->debugSetDeleted());
252530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//                        inner->setDeleted();
252630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    }
252730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                }
252830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#ifdef SK_DEBUG   // assert if another undeleted entry points to segment
252930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                const SkOpPtT* debugInner = inner;
253030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                while ((debugInner = debugInner->next()) != innerStop) {
253130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    if (debugInner->segment() != segment) {
253230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                        continue;
253330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    }
253430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    if (debugInner->deleted()) {
253530b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                        continue;
253630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    }
253730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                    SkOPASSERT(0);
253830b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                }
253930b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark#endif
254030b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark                break;
254130b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark//            }
254230b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark            break;
254330b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark        } while ((inner = inner->next()) != innerStop);
254430b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark    } while ((test = testNext) != stop);
2545ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    this->debugCheckForCollapsedCoincidence(log);
254630b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark}
254730b9fdd6a1d607bde20c793af65b5e2e8a1737cacaryclark
254855888e44171ffd48b591d19256884a969fe4da17caryclark#endif
254926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
2550025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclarkvoid SkOpSpanBase::debugResetCoinT() const {
2551025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#if DEBUG_COINCIDENCE_ORDER
2552025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    const SkOpPtT* ptT = &fPtT;
2553025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    do {
2554025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        ptT->debugResetCoinT();
2555025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        ptT = ptT->next();
2556025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    } while (ptT != &fPtT);
2557025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#endif
2558025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark}
2559025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark
2560025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclarkvoid SkOpSpanBase::debugSetCoinT(int index) const {
2561025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#if DEBUG_COINCIDENCE_ORDER
2562025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    const SkOpPtT* ptT = &fPtT;
2563025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    do {
2564025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        if (!ptT->deleted()) {
2565025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark            ptT->debugSetCoinT(index);
2566025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        }
2567025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark        ptT = ptT->next();
2568025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    } while (ptT != &fPtT);
2569025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#endif
2570025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark}
2571025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark
257226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkconst SkOpSpan* SkOpSpanBase::debugStarter(SkOpSpanBase const** endPtr) const {
257326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpanBase* end = *endPtr;
257426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkASSERT(this->segment() == end->segment());
257526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpSpanBase* result;
257626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    if (t() < end->t()) {
257726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        result = this;
257826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    } else {
257926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        result = end;
258026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        *endPtr = this;
258126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    }
258226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    return result->upCast();
258326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
258426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
258554359294a7c9dc54802d512a5d891a35c1663392caryclarkvoid SkOpSpanBase::debugValidate() const {
258655888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
258755888e44171ffd48b591d19256884a969fe4da17caryclark    if (this->globalState()->debugCheckHealth()) {
258855888e44171ffd48b591d19256884a969fe4da17caryclark        return;
258955888e44171ffd48b591d19256884a969fe4da17caryclark    }
259055888e44171ffd48b591d19256884a969fe4da17caryclark#endif
259154359294a7c9dc54802d512a5d891a35c1663392caryclark#if DEBUG_VALIDATE
259254359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpPtT* ptT = &fPtT;
259354359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(ptT->span() == this);
259454359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
259554359294a7c9dc54802d512a5d891a35c1663392caryclark//        SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt));
259654359294a7c9dc54802d512a5d891a35c1663392caryclark        ptT->debugValidate();
259754359294a7c9dc54802d512a5d891a35c1663392caryclark        ptT = ptT->next();
259854359294a7c9dc54802d512a5d891a35c1663392caryclark    } while (ptT != &fPtT);
259954359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(this->debugCoinEndLoopCheck());
260054359294a7c9dc54802d512a5d891a35c1663392caryclark    if (!this->final()) {
260154359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(this->upCast()->debugCoinLoopCheck());
260254359294a7c9dc54802d512a5d891a35c1663392caryclark    }
260354359294a7c9dc54802d512a5d891a35c1663392caryclark    if (fFromAngle) {
260454359294a7c9dc54802d512a5d891a35c1663392caryclark        fFromAngle->debugValidate();
260554359294a7c9dc54802d512a5d891a35c1663392caryclark    }
260654359294a7c9dc54802d512a5d891a35c1663392caryclark    if (!this->final() && this->upCast()->toAngle()) {
260754359294a7c9dc54802d512a5d891a35c1663392caryclark        this->upCast()->toAngle()->debugValidate();
260854359294a7c9dc54802d512a5d891a35c1663392caryclark    }
26094431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
261054359294a7c9dc54802d512a5d891a35c1663392caryclark}
261154359294a7c9dc54802d512a5d891a35c1663392caryclark
261254359294a7c9dc54802d512a5d891a35c1663392caryclarkbool SkOpSpan::debugCoinLoopCheck() const {
261354359294a7c9dc54802d512a5d891a35c1663392caryclark    int loop = 0;
261454359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpSpan* next = this;
261554359294a7c9dc54802d512a5d891a35c1663392caryclark    SkOpSpan* nextCoin;
261654359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
261754359294a7c9dc54802d512a5d891a35c1663392caryclark        nextCoin = next->fCoincident;
261854359294a7c9dc54802d512a5d891a35c1663392caryclark        SkASSERT(nextCoin == this || nextCoin->fCoincident != nextCoin);
261954359294a7c9dc54802d512a5d891a35c1663392caryclark        for (int check = 1; check < loop - 1; ++check) {
262054359294a7c9dc54802d512a5d891a35c1663392caryclark            const SkOpSpan* checkCoin = this->fCoincident;
262154359294a7c9dc54802d512a5d891a35c1663392caryclark            const SkOpSpan* innerCoin = checkCoin;
262254359294a7c9dc54802d512a5d891a35c1663392caryclark            for (int inner = check + 1; inner < loop; ++inner) {
262354359294a7c9dc54802d512a5d891a35c1663392caryclark                innerCoin = innerCoin->fCoincident;
262454359294a7c9dc54802d512a5d891a35c1663392caryclark                if (checkCoin == innerCoin) {
262554359294a7c9dc54802d512a5d891a35c1663392caryclark                    SkDebugf("*** bad coincident loop ***\n");
262654359294a7c9dc54802d512a5d891a35c1663392caryclark                    return false;
262754359294a7c9dc54802d512a5d891a35c1663392caryclark                }
262854359294a7c9dc54802d512a5d891a35c1663392caryclark            }
262954359294a7c9dc54802d512a5d891a35c1663392caryclark        }
263054359294a7c9dc54802d512a5d891a35c1663392caryclark        ++loop;
263154359294a7c9dc54802d512a5d891a35c1663392caryclark    } while ((next = nextCoin) && next != this);
263254359294a7c9dc54802d512a5d891a35c1663392caryclark    return true;
263354359294a7c9dc54802d512a5d891a35c1663392caryclark}
263454359294a7c9dc54802d512a5d891a35c1663392caryclark
2635ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
263655888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with insertCoincidence() in header
2637ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog* log, const SkOpSpan* coin) const {
263855888e44171ffd48b591d19256884a969fe4da17caryclark    if (containsCoincidence(coin)) {
263955888e44171ffd48b591d19256884a969fe4da17caryclark//         SkASSERT(coin->containsCoincidence(this));
264055888e44171ffd48b591d19256884a969fe4da17caryclark        return;
264155888e44171ffd48b591d19256884a969fe4da17caryclark    }
264255888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
264355888e44171ffd48b591d19256884a969fe4da17caryclark//     SkASSERT(this != coin);
2644ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    log->record(SkPathOpsDebug::kMarkCoinStart_Glitch, this, coin);
264555888e44171ffd48b591d19256884a969fe4da17caryclark//     coin->fCoincident = this->fCoincident;
264655888e44171ffd48b591d19256884a969fe4da17caryclark//     this->fCoincident = coinNext;
264755888e44171ffd48b591d19256884a969fe4da17caryclark    debugValidate();
264855888e44171ffd48b591d19256884a969fe4da17caryclark}
264955888e44171ffd48b591d19256884a969fe4da17caryclark
265055888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with insertCoincidence()
2651ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clarkvoid SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog* log, const SkOpSegment* segment, bool flipped, bool ordered) const {
265255888e44171ffd48b591d19256884a969fe4da17caryclark    if (this->containsCoincidence(segment)) {
265355888e44171ffd48b591d19256884a969fe4da17caryclark        return;
265455888e44171ffd48b591d19256884a969fe4da17caryclark    }
265555888e44171ffd48b591d19256884a969fe4da17caryclark    const SkOpPtT* next = &fPtT;
265655888e44171ffd48b591d19256884a969fe4da17caryclark    while ((next = next->next()) != &fPtT) {
265755888e44171ffd48b591d19256884a969fe4da17caryclark        if (next->segment() == segment) {
2658ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            const SkOpSpan* span;
2659ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            const SkOpSpanBase* base = next->span();
2660ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            if (!ordered) {
2661ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                const SkOpSpanBase* spanEnd = fNext->contains(segment)->span();
2662ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT());
2663ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                FAIL_IF(!start->span()->upCastable(), this);
2664ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                span = const_cast<SkOpSpan*>(start->span()->upCast());
2665ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
2666ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            else if (flipped) {
2667ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                span = base->prev();
2668ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                FAIL_IF(!span, this);
2669ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
2670ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            else {
2671ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                FAIL_IF(!base->upCastable(), this);
2672ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark                span = base->upCast();
2673ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            }
2674ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark            log->record(SkPathOpsDebug::kMarkCoinInsert_Glitch, span);
267555888e44171ffd48b591d19256884a969fe4da17caryclark            return;
267655888e44171ffd48b591d19256884a969fe4da17caryclark        }
267755888e44171ffd48b591d19256884a969fe4da17caryclark    }
2678ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark#if DEBUG_COIN
2679ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    log->record(SkPathOpsDebug::kMarkCoinMissing_Glitch, segment, this);
268055888e44171ffd48b591d19256884a969fe4da17caryclark#endif
2681ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    return;
268255888e44171ffd48b591d19256884a969fe4da17caryclark}
268355888e44171ffd48b591d19256884a969fe4da17caryclark#endif
268455888e44171ffd48b591d19256884a969fe4da17caryclark
2685624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark// called only by test code
2686624637cc8ec22c000409704d0b403ac1b81ad4b0caryclarkint SkIntersections::debugCoincidentUsed() const {
2687624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    if (!fIsCoincident[0]) {
2688624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        SkASSERT(!fIsCoincident[1]);
2689624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        return 0;
2690624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    }
2691624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    int count = 0;
2692624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    SkDEBUGCODE(int count2 = 0;)
2693624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    for (int index = 0; index < fUsed; ++index) {
2694624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        if (fIsCoincident[0] & (1 << index)) {
2695624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark            ++count;
2696624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        }
2697624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#ifdef SK_DEBUG
2698624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        if (fIsCoincident[1] & (1 << index)) {
2699624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark            ++count2;
2700624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark        }
2701624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark#endif
2702624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    }
2703624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    SkASSERT(count == count2);
2704624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark    return count;
2705624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark}
2706624637cc8ec22c000409704d0b403ac1b81ad4b0caryclark
270754359294a7c9dc54802d512a5d891a35c1663392caryclark#include "SkOpContour.h"
270854359294a7c9dc54802d512a5d891a35c1663392caryclark
270955888e44171ffd48b591d19256884a969fe4da17caryclark// Commented-out lines keep this in sync with addOpp()
271029b2563afb1677515739f1d24fb27733626eca92caryclarkvoid SkOpPtT::debugAddOpp(const SkOpPtT* opp, const SkOpPtT* oppPrev) const {
271129b2563afb1677515739f1d24fb27733626eca92caryclark    SkDEBUGCODE(const SkOpPtT* oldNext = this->fNext);
271255888e44171ffd48b591d19256884a969fe4da17caryclark    SkASSERT(this != opp);
271355888e44171ffd48b591d19256884a969fe4da17caryclark//    this->fNext = opp;
271429b2563afb1677515739f1d24fb27733626eca92caryclark    SkASSERT(oppPrev != oldNext);
271555888e44171ffd48b591d19256884a969fe4da17caryclark//    oppPrev->fNext = oldNext;
271655888e44171ffd48b591d19256884a969fe4da17caryclark}
271755888e44171ffd48b591d19256884a969fe4da17caryclark
271826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkbool SkOpPtT::debugContains(const SkOpPtT* check) const {
271926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkASSERT(this != check);
272026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpPtT* ptT = this;
272126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    int links = 0;
272226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
272326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        ptT = ptT->next();
272426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (ptT == check) {
272526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            return true;
272626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
272726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        ++links;
272826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpPtT* test = this;
272926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        for (int index = 0; index < links; ++index) {
273026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (ptT == test) {
273126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                return false;
273226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
273326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            test = test->next();
273426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
273526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    } while (true);
273626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
273726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
273826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclarkconst SkOpPtT* SkOpPtT::debugContains(const SkOpSegment* check) const {
273926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    SkASSERT(this->segment() != check);
274026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    const SkOpPtT* ptT = this;
274126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    int links = 0;
274226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    do {
274326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        ptT = ptT->next();
274426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (ptT->segment() == check) {
274526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            return ptT;
274626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
274726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        ++links;
274826ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        const SkOpPtT* test = this;
274926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        for (int index = 0; index < links; ++index) {
275026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            if (ptT == test) {
275126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark                return nullptr;
275226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            }
275326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            test = test->next();
275426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
275526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark    } while (true);
275626ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark}
275726ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark
27588016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclarkconst SkOpPtT* SkOpPtT::debugEnder(const SkOpPtT* end) const {
27598016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark    return fT < end->fT ? end : this;
27608016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark}
27618016b264ceec2b11d2acbeb77a9fbe66e48368b9caryclark
276254359294a7c9dc54802d512a5d891a35c1663392caryclarkint SkOpPtT::debugLoopLimit(bool report) const {
276354359294a7c9dc54802d512a5d891a35c1663392caryclark    int loop = 0;
276454359294a7c9dc54802d512a5d891a35c1663392caryclark    const SkOpPtT* next = this;
276554359294a7c9dc54802d512a5d891a35c1663392caryclark    do {
276654359294a7c9dc54802d512a5d891a35c1663392caryclark        for (int check = 1; check < loop - 1; ++check) {
276754359294a7c9dc54802d512a5d891a35c1663392caryclark            const SkOpPtT* checkPtT = this->fNext;
276854359294a7c9dc54802d512a5d891a35c1663392caryclark            const SkOpPtT* innerPtT = checkPtT;
276954359294a7c9dc54802d512a5d891a35c1663392caryclark            for (int inner = check + 1; inner < loop; ++inner) {
277054359294a7c9dc54802d512a5d891a35c1663392caryclark                innerPtT = innerPtT->fNext;
277154359294a7c9dc54802d512a5d891a35c1663392caryclark                if (checkPtT == innerPtT) {
277254359294a7c9dc54802d512a5d891a35c1663392caryclark                    if (report) {
277354359294a7c9dc54802d512a5d891a35c1663392caryclark                        SkDebugf("*** bad ptT loop ***\n");
277454359294a7c9dc54802d512a5d891a35c1663392caryclark                    }
277554359294a7c9dc54802d512a5d891a35c1663392caryclark                    return loop;
277654359294a7c9dc54802d512a5d891a35c1663392caryclark                }
27774431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org            }
27784431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        }
277926ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        // there's nothing wrong with extremely large loop counts -- but this may appear to hang
278026ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        // by taking a very long time to figure out that no loop entry is a duplicate
278126ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        // -- and it's likely that a large loop count is indicative of a bug somewhere
278226ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        if (++loop > 1000) {
278326ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            SkDebugf("*** loop count exceeds 1000 ***\n");
278426ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark            return 1000;
278526ad22ab61539e3d3b6bc5e0da8dcebbd52a53decaryclark        }
278654359294a7c9dc54802d512a5d891a35c1663392caryclark    } while ((next = next->fNext) && next != this);
278754359294a7c9dc54802d512a5d891a35c1663392caryclark    return 0;
278854359294a7c9dc54802d512a5d891a35c1663392caryclark}
278954359294a7c9dc54802d512a5d891a35c1663392caryclark
279029b2563afb1677515739f1d24fb27733626eca92caryclarkconst SkOpPtT* SkOpPtT::debugOppPrev(const SkOpPtT* opp) const {
279129b2563afb1677515739f1d24fb27733626eca92caryclark    return this->oppPrev(const_cast<SkOpPtT*>(opp));
279229b2563afb1677515739f1d24fb27733626eca92caryclark}
279329b2563afb1677515739f1d24fb27733626eca92caryclark
2794025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclarkvoid SkOpPtT::debugResetCoinT() const {
2795025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#if DEBUG_COINCIDENCE_ORDER
2796025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    this->segment()->debugResetCoinT();
2797025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#endif
2798025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark}
2799025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark
2800025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclarkvoid SkOpPtT::debugSetCoinT(int index) const {
2801025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#if DEBUG_COINCIDENCE_ORDER
2802025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark    this->segment()->debugSetCoinT(index, fT);
2803025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark#endif
2804025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark}
2805025b11ecde8733d9b3eee54e132cc50a5ce8eb78caryclark
280654359294a7c9dc54802d512a5d891a35c1663392caryclarkvoid SkOpPtT::debugValidate() const {
280755888e44171ffd48b591d19256884a969fe4da17caryclark#if DEBUG_COINCIDENCE
280855888e44171ffd48b591d19256884a969fe4da17caryclark    if (this->globalState()->debugCheckHealth()) {
280955888e44171ffd48b591d19256884a969fe4da17caryclark        return;
281055888e44171ffd48b591d19256884a969fe4da17caryclark    }
281155888e44171ffd48b591d19256884a969fe4da17caryclark#endif
281254359294a7c9dc54802d512a5d891a35c1663392caryclark#if DEBUG_VALIDATE
2813ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    SkOpPhase phase = contour()->globalState()->phase();
2814ab87d7abf1df007c90bef2e916294ca325d81c81Cary Clark    if (phase == SkOpPhase::kIntersecting || phase == SkOpPhase::kFixWinding) {
281554359294a7c9dc54802d512a5d891a35c1663392caryclark        return;
28164431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    }
281754359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(fNext);
281854359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(fNext != this);
281954359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(fNext->fNext);
282054359294a7c9dc54802d512a5d891a35c1663392caryclark    SkASSERT(debugLoopLimit(false) == 0);
28214431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org#endif
28224431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org}
28231049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
28241049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkstatic void output_scalar(SkScalar num) {
28251049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    if (num == (int) num) {
28261049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkDebugf("%d", (int) num);
28271049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    } else {
28281049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkString str;
28291049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        str.printf("%1.9g", num);
28301049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        int width = (int) str.size();
28311049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        const char* cStr = str.c_str();
28321049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        while (cStr[width - 1] == '0') {
28331049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            --width;
28341049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        }
28351049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        str.resize(width);
28361049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkDebugf("%sf", str.c_str());
28371049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    }
28381049f1246e7be4ccb68001361efceb8933e6f81ccaryclark}
28391049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
28401049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkstatic void output_points(const SkPoint* pts, int count) {
28411049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    for (int index = 0; index < count; ++index) {
28421049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        output_scalar(pts[index].fX);
28431049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkDebugf(", ");
28441049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        output_scalar(pts[index].fY);
28451049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        if (index + 1 < count) {
28461049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            SkDebugf(", ");
28471049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        }
28481049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    }
28491049f1246e7be4ccb68001361efceb8933e6f81ccaryclark}
28501049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
28511049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkstatic void showPathContours(SkPath::RawIter& iter, const char* pathName) {
28521049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    uint8_t verb;
28531049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkPoint pts[4];
28541049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
28551049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        switch (verb) {
28561049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            case SkPath::kMove_Verb:
28571049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf("    %s.moveTo(", pathName);
28581049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                output_points(&pts[0], 1);
28591049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf(");\n");
28601049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                continue;
28611049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            case SkPath::kLine_Verb:
28621049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf("    %s.lineTo(", pathName);
28631049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                output_points(&pts[1], 1);
28641049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf(");\n");
28651049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                break;
28661049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            case SkPath::kQuad_Verb:
28671049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf("    %s.quadTo(", pathName);
28681049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                output_points(&pts[1], 2);
28691049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf(");\n");
28701049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                break;
28711049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            case SkPath::kConic_Verb:
28721049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf("    %s.conicTo(", pathName);
28731049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                output_points(&pts[1], 2);
28741049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf(", %1.9gf);\n", iter.conicWeight());
28751049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                break;
28761049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            case SkPath::kCubic_Verb:
28771049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf("    %s.cubicTo(", pathName);
28781049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                output_points(&pts[1], 3);
28791049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf(");\n");
28801049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                break;
28811049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            case SkPath::kClose_Verb:
28821049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDebugf("    %s.close();\n", pathName);
28831049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                break;
28841049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            default:
28851049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                SkDEBUGFAIL("bad verb");
28861049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                return;
28871049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        }
28881049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    }
28891049f1246e7be4ccb68001361efceb8933e6f81ccaryclark}
28901049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
28911049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkstatic const char* gFillTypeStr[] = {
28921049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kWinding_FillType",
28931049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kEvenOdd_FillType",
28941049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kInverseWinding_FillType",
28951049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    "kInverseEvenOdd_FillType"
28961049f1246e7be4ccb68001361efceb8933e6f81ccaryclark};
28971049f1246e7be4ccb68001361efceb8933e6f81ccaryclark
28981049f1246e7be4ccb68001361efceb8933e6f81ccaryclarkvoid SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration) {
28991049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkPath::RawIter iter(path);
29001049f1246e7be4ccb68001361efceb8933e6f81ccaryclark#define SUPPORT_RECT_CONTOUR_DETECTION 0
29011049f1246e7be4ccb68001361efceb8933e6f81ccaryclark#if SUPPORT_RECT_CONTOUR_DETECTION
290296fcdcc219d2a0d3579719b84b28bede76efba64halcanary    int rectCount = path.isRectContours() ? path.rectContours(nullptr, nullptr) : 0;
29031049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    if (rectCount > 0) {
29041049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkTDArray<SkRect> rects;
29051049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkTDArray<SkPath::Direction> directions;
29061049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        rects.setCount(rectCount);
29071049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        directions.setCount(rectCount);
29081049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        path.rectContours(rects.begin(), directions.begin());
29091049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        for (int contour = 0; contour < rectCount; ++contour) {
29101049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            const SkRect& rect = rects[contour];
29111049f1246e7be4ccb68001361efceb8933e6f81ccaryclark            SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
29121049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                    rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
29131049f1246e7be4ccb68001361efceb8933e6f81ccaryclark                    ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
29141049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        }
29151049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        return;
29161049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    }
29171049f1246e7be4ccb68001361efceb8933e6f81ccaryclark#endif
29181049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkPath::FillType fillType = path.getFillType();
29191049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
29201049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    if (includeDeclaration) {
29211049f1246e7be4ccb68001361efceb8933e6f81ccaryclark        SkDebugf("    SkPath %s;\n", name);
29221049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    }
29231049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    SkDebugf("    %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]);
29241049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    iter.setPath(path);
29251049f1246e7be4ccb68001361efceb8933e6f81ccaryclark    showPathContours(iter, name);
29261049f1246e7be4ccb68001361efceb8933e6f81ccaryclark}
29271326068147ee60de138061a3fc1157fcfd5d017bcaryclark
2928918fb1fe6ff5349a2d1e5fb6872139f5fb931480Cary Clark#if DEBUG_DUMP_VERIFY
29291326068147ee60de138061a3fc1157fcfd5d017bcaryclark#include "SkData.h"
29301326068147ee60de138061a3fc1157fcfd5d017bcaryclark#include "SkStream.h"
29311326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29321326068147ee60de138061a3fc1157fcfd5d017bcaryclarkstatic void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) {
29331326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkDynamicMemoryWStream wStream;
29341326068147ee60de138061a3fc1157fcfd5d017bcaryclark    path.dump(&wStream, force, dumpAsHex);
29351326068147ee60de138061a3fc1157fcfd5d017bcaryclark    sk_sp<SkData> data(wStream.detachAsData());
29361326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data());
29371326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
29381326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29391326068147ee60de138061a3fc1157fcfd5d017bcaryclarkstatic int dumpID = 0;
29401326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29411326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
29421326068147ee60de138061a3fc1157fcfd5d017bcaryclark        const char* testName) {
29431326068147ee60de138061a3fc1157fcfd5d017bcaryclark    FILE* file = sk_fopen("op_dump.txt", kWrite_SkFILE_Flag);
29441326068147ee60de138061a3fc1157fcfd5d017bcaryclark    DumpOp(file, one, two, op, testName);
29451326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
29461326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29471326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
29481326068147ee60de138061a3fc1157fcfd5d017bcaryclark        const char* testName) {
29491326068147ee60de138061a3fc1157fcfd5d017bcaryclark    const char* name = testName ? testName : "op";
29501326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file,
29511326068147ee60de138061a3fc1157fcfd5d017bcaryclark            "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
29521326068147ee60de138061a3fc1157fcfd5d017bcaryclark            name, ++dumpID);
29531326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    SkPath path;\n");
29541326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    path.setFillType((SkPath::FillType) %d);\n", one.getFillType());
29551326068147ee60de138061a3fc1157fcfd5d017bcaryclark    dump_path(file, one, false, true);
29561326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    SkPath path1(path);\n");
29571326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    path.reset();\n");
29581326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    path.setFillType((SkPath::FillType) %d);\n", two.getFillType());
29591326068147ee60de138061a3fc1157fcfd5d017bcaryclark    dump_path(file, two, false, true);
29601326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    SkPath path2(path);\n");
29611326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op);
29621326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "}\n\n");
29631326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fclose(file);
29641326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
29651326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29661326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::DumpSimplify(const SkPath& path, const char* testName) {
29671326068147ee60de138061a3fc1157fcfd5d017bcaryclark    FILE* file = sk_fopen("simplify_dump.txt", kWrite_SkFILE_Flag);
29681326068147ee60de138061a3fc1157fcfd5d017bcaryclark    DumpSimplify(file, path, testName);
29691326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
29701326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29711326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::DumpSimplify(FILE* file, const SkPath& path, const char* testName) {
29721326068147ee60de138061a3fc1157fcfd5d017bcaryclark    const char* name = testName ? testName : "simplify";
29731326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file,
29741326068147ee60de138061a3fc1157fcfd5d017bcaryclark            "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
29751326068147ee60de138061a3fc1157fcfd5d017bcaryclark            name, ++dumpID);
29761326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    SkPath path;\n");
29771326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    path.setFillType((SkPath::FillType) %d);\n", path.getFillType());
29781326068147ee60de138061a3fc1157fcfd5d017bcaryclark    dump_path(file, path, false, true);
29791326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "    testSimplify(reporter, path, filename);\n");
29801326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fprintf(file, "}\n\n");
29811326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fclose(file);
29821326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
29831326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29841326068147ee60de138061a3fc1157fcfd5d017bcaryclark#include "SkBitmap.h"
29851326068147ee60de138061a3fc1157fcfd5d017bcaryclark#include "SkCanvas.h"
29861326068147ee60de138061a3fc1157fcfd5d017bcaryclark#include "SkPaint.h"
29871326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29881326068147ee60de138061a3fc1157fcfd5d017bcaryclarkconst int bitWidth = 64;
29891326068147ee60de138061a3fc1157fcfd5d017bcaryclarkconst int bitHeight = 64;
29901326068147ee60de138061a3fc1157fcfd5d017bcaryclark
29911326068147ee60de138061a3fc1157fcfd5d017bcaryclarkstatic void debug_scale_matrix(const SkPath& one, const SkPath* two, SkMatrix& scale) {
29921326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkRect larger = one.getBounds();
29931326068147ee60de138061a3fc1157fcfd5d017bcaryclark    if (two) {
29941326068147ee60de138061a3fc1157fcfd5d017bcaryclark        larger.join(two->getBounds());
29951326068147ee60de138061a3fc1157fcfd5d017bcaryclark    }
29961326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkScalar largerWidth = larger.width();
29971326068147ee60de138061a3fc1157fcfd5d017bcaryclark    if (largerWidth < 4) {
29981326068147ee60de138061a3fc1157fcfd5d017bcaryclark        largerWidth = 4;
29991326068147ee60de138061a3fc1157fcfd5d017bcaryclark    }
30001326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkScalar largerHeight = larger.height();
30011326068147ee60de138061a3fc1157fcfd5d017bcaryclark    if (largerHeight < 4) {
30021326068147ee60de138061a3fc1157fcfd5d017bcaryclark        largerHeight = 4;
30031326068147ee60de138061a3fc1157fcfd5d017bcaryclark    }
30041326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkScalar hScale = (bitWidth - 2) / largerWidth;
30051326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkScalar vScale = (bitHeight - 2) / largerHeight;
30061326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scale.reset();
30071326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scale.preScale(hScale, vScale);
30081326068147ee60de138061a3fc1157fcfd5d017bcaryclark    larger.fLeft *= hScale;
30091326068147ee60de138061a3fc1157fcfd5d017bcaryclark    larger.fRight *= hScale;
30101326068147ee60de138061a3fc1157fcfd5d017bcaryclark    larger.fTop *= vScale;
30111326068147ee60de138061a3fc1157fcfd5d017bcaryclark    larger.fBottom *= vScale;
30121326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
30131326068147ee60de138061a3fc1157fcfd5d017bcaryclark            : 16000 < larger.fRight ? 16000 - larger.fRight : 0;
30141326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
30151326068147ee60de138061a3fc1157fcfd5d017bcaryclark            : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
30161326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scale.preTranslate(dx, dy);
30171326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
30181326068147ee60de138061a3fc1157fcfd5d017bcaryclark
30191326068147ee60de138061a3fc1157fcfd5d017bcaryclarkstatic int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) {
30201326068147ee60de138061a3fc1157fcfd5d017bcaryclark    if (bits.width() == 0) {
30211326068147ee60de138061a3fc1157fcfd5d017bcaryclark        bits.allocN32Pixels(bitWidth * 2, bitHeight);
30221326068147ee60de138061a3fc1157fcfd5d017bcaryclark    }
30231326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkCanvas canvas(bits);
30241326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.drawColor(SK_ColorWHITE);
30251326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkPaint paint;
30261326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.save();
30271326068147ee60de138061a3fc1157fcfd5d017bcaryclark    const SkRect& bounds1 = one.getBounds();
30281326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
30291326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.drawPath(one, paint);
30301326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.restore();
30311326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.save();
30321326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
30331326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.drawPath(two, paint);
30341326068147ee60de138061a3fc1157fcfd5d017bcaryclark    canvas.restore();
30351326068147ee60de138061a3fc1157fcfd5d017bcaryclark    int errors = 0;
30361326068147ee60de138061a3fc1157fcfd5d017bcaryclark    for (int y = 0; y < bitHeight - 1; ++y) {
30371326068147ee60de138061a3fc1157fcfd5d017bcaryclark        uint32_t* addr1 = bits.getAddr32(0, y);
30381326068147ee60de138061a3fc1157fcfd5d017bcaryclark        uint32_t* addr2 = bits.getAddr32(0, y + 1);
30391326068147ee60de138061a3fc1157fcfd5d017bcaryclark        uint32_t* addr3 = bits.getAddr32(bitWidth, y);
30401326068147ee60de138061a3fc1157fcfd5d017bcaryclark        uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
30411326068147ee60de138061a3fc1157fcfd5d017bcaryclark        for (int x = 0; x < bitWidth - 1; ++x) {
30421326068147ee60de138061a3fc1157fcfd5d017bcaryclark            // count 2x2 blocks
30431326068147ee60de138061a3fc1157fcfd5d017bcaryclark            bool err = addr1[x] != addr3[x];
30441326068147ee60de138061a3fc1157fcfd5d017bcaryclark            if (err) {
30451326068147ee60de138061a3fc1157fcfd5d017bcaryclark                errors += addr1[x + 1] != addr3[x + 1]
30461326068147ee60de138061a3fc1157fcfd5d017bcaryclark                        && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
30471326068147ee60de138061a3fc1157fcfd5d017bcaryclark            }
30481326068147ee60de138061a3fc1157fcfd5d017bcaryclark        }
30491326068147ee60de138061a3fc1157fcfd5d017bcaryclark    }
30501326068147ee60de138061a3fc1157fcfd5d017bcaryclark    return errors;
30511326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
30521326068147ee60de138061a3fc1157fcfd5d017bcaryclark
30531326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op) {
30541326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkDebugf("// Op did not expect failure\n");
30551326068147ee60de138061a3fc1157fcfd5d017bcaryclark    DumpOp(stderr, one, two, op, "opTest");
30561326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fflush(stderr);
30571326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
30581326068147ee60de138061a3fc1157fcfd5d017bcaryclark
30591326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op,
30601326068147ee60de138061a3fc1157fcfd5d017bcaryclark        const SkPath& result) {
30611326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkPath pathOut, scaledPathOut;
30621326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkRegion rgnA, rgnB, openClip, rgnOut;
30631326068147ee60de138061a3fc1157fcfd5d017bcaryclark    openClip.setRect(-16000, -16000, 16000, 16000);
30641326068147ee60de138061a3fc1157fcfd5d017bcaryclark    rgnA.setPath(one, openClip);
30651326068147ee60de138061a3fc1157fcfd5d017bcaryclark    rgnB.setPath(two, openClip);
30661326068147ee60de138061a3fc1157fcfd5d017bcaryclark    rgnOut.op(rgnA, rgnB, (SkRegion::Op) op);
30671326068147ee60de138061a3fc1157fcfd5d017bcaryclark    rgnOut.getBoundaryPath(&pathOut);
30681326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkMatrix scale;
30691326068147ee60de138061a3fc1157fcfd5d017bcaryclark    debug_scale_matrix(one, &two, scale);
30701326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
30711326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkPath scaledA, scaledB;
30721326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledA.addPath(one, scale);
30731326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledA.setFillType(one.getFillType());
30741326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledB.addPath(two, scale);
30751326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledB.setFillType(two.getFillType());
30761326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledRgnA.setPath(scaledA, openClip);
30771326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledRgnB.setPath(scaledB, openClip);
30781326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op);
30791326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledRgnOut.getBoundaryPath(&scaledPathOut);
30801326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkBitmap bitmap;
30811326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkPath scaledOut;
30821326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledOut.addPath(result, scale);
30831326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledOut.setFillType(result.getFillType());
30841326068147ee60de138061a3fc1157fcfd5d017bcaryclark    int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
30851326068147ee60de138061a3fc1157fcfd5d017bcaryclark    const int MAX_ERRORS = 9;
30861326068147ee60de138061a3fc1157fcfd5d017bcaryclark    if (errors > MAX_ERRORS) {
30871326068147ee60de138061a3fc1157fcfd5d017bcaryclark        fprintf(stderr, "// Op did not expect errors=%d\n", errors);
30881326068147ee60de138061a3fc1157fcfd5d017bcaryclark        DumpOp(stderr, one, two, op, "opTest");
30891326068147ee60de138061a3fc1157fcfd5d017bcaryclark        fflush(stderr);
30901326068147ee60de138061a3fc1157fcfd5d017bcaryclark    }
30911326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
30921326068147ee60de138061a3fc1157fcfd5d017bcaryclark
30931326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::ReportSimplifyFail(const SkPath& path) {
30941326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkDebugf("// Simplify did not expect failure\n");
30951326068147ee60de138061a3fc1157fcfd5d017bcaryclark    DumpSimplify(stderr, path, "simplifyTest");
30961326068147ee60de138061a3fc1157fcfd5d017bcaryclark    fflush(stderr);
30971326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
30981326068147ee60de138061a3fc1157fcfd5d017bcaryclark
30991326068147ee60de138061a3fc1157fcfd5d017bcaryclarkvoid SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) {
31001326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkPath pathOut, scaledPathOut;
31011326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkRegion rgnA, openClip, rgnOut;
31021326068147ee60de138061a3fc1157fcfd5d017bcaryclark    openClip.setRect(-16000, -16000, 16000, 16000);
31031326068147ee60de138061a3fc1157fcfd5d017bcaryclark    rgnA.setPath(path, openClip);
31041326068147ee60de138061a3fc1157fcfd5d017bcaryclark    rgnOut.getBoundaryPath(&pathOut);
31051326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkMatrix scale;
31061326068147ee60de138061a3fc1157fcfd5d017bcaryclark    debug_scale_matrix(path, nullptr, scale);
31071326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkRegion scaledRgnA;
31081326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkPath scaledA;
31091326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledA.addPath(path, scale);
31101326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledA.setFillType(path.getFillType());
31111326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledRgnA.setPath(scaledA, openClip);
31121326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledRgnA.getBoundaryPath(&scaledPathOut);
31131326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkBitmap bitmap;
31141326068147ee60de138061a3fc1157fcfd5d017bcaryclark    SkPath scaledOut;
31151326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledOut.addPath(result, scale);
31161326068147ee60de138061a3fc1157fcfd5d017bcaryclark    scaledOut.setFillType(result.getFillType());
31171326068147ee60de138061a3fc1157fcfd5d017bcaryclark    int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
31181326068147ee60de138061a3fc1157fcfd5d017bcaryclark    const int MAX_ERRORS = 9;
31191326068147ee60de138061a3fc1157fcfd5d017bcaryclark    if (errors > MAX_ERRORS) {
31201326068147ee60de138061a3fc1157fcfd5d017bcaryclark        fprintf(stderr, "// Simplify did not expect errors=%d\n", errors);
31211326068147ee60de138061a3fc1157fcfd5d017bcaryclark        DumpSimplify(stderr, path, "simplifyTest");
31221326068147ee60de138061a3fc1157fcfd5d017bcaryclark        fflush(stderr);
31231326068147ee60de138061a3fc1157fcfd5d017bcaryclark    }
31241326068147ee60de138061a3fc1157fcfd5d017bcaryclark}
31251326068147ee60de138061a3fc1157fcfd5d017bcaryclark
31261326068147ee60de138061a3fc1157fcfd5d017bcaryclark#endif
3127