1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci#include "src/pathops/SkAddIntersections.h"
8cb93a386Sopenharmony_ci#include "src/pathops/SkOpCoincidence.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCommon.h"
11cb93a386Sopenharmony_ci#include "src/pathops/SkPathWriter.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ci#include <utility>
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cistatic bool findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr,
16cb93a386Sopenharmony_ci        SkOpSpanBase** endPtr, SkOpSegment** result) {
17cb93a386Sopenharmony_ci    while (chase.count()) {
18cb93a386Sopenharmony_ci        SkOpSpanBase* span;
19cb93a386Sopenharmony_ci        chase.pop(&span);
20cb93a386Sopenharmony_ci        // OPTIMIZE: prev makes this compatible with old code -- but is it necessary?
21cb93a386Sopenharmony_ci        *startPtr = span->ptT()->prev()->span();
22cb93a386Sopenharmony_ci        SkOpSegment* segment = (*startPtr)->segment();
23cb93a386Sopenharmony_ci        bool done = true;
24cb93a386Sopenharmony_ci        *endPtr = nullptr;
25cb93a386Sopenharmony_ci        if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
26cb93a386Sopenharmony_ci            *startPtr = last->start();
27cb93a386Sopenharmony_ci            *endPtr = last->end();
28cb93a386Sopenharmony_ci   #if TRY_ROTATE
29cb93a386Sopenharmony_ci            *chase.insert(0) = span;
30cb93a386Sopenharmony_ci   #else
31cb93a386Sopenharmony_ci            *chase.append() = span;
32cb93a386Sopenharmony_ci   #endif
33cb93a386Sopenharmony_ci            *result = last->segment();
34cb93a386Sopenharmony_ci            return true;
35cb93a386Sopenharmony_ci        }
36cb93a386Sopenharmony_ci        if (done) {
37cb93a386Sopenharmony_ci            continue;
38cb93a386Sopenharmony_ci        }
39cb93a386Sopenharmony_ci        int winding;
40cb93a386Sopenharmony_ci        bool sortable;
41cb93a386Sopenharmony_ci        const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
42cb93a386Sopenharmony_ci        if (!angle) {
43cb93a386Sopenharmony_ci            *result = nullptr;
44cb93a386Sopenharmony_ci            return true;
45cb93a386Sopenharmony_ci        }
46cb93a386Sopenharmony_ci        if (winding == SK_MinS32) {
47cb93a386Sopenharmony_ci            continue;
48cb93a386Sopenharmony_ci        }
49cb93a386Sopenharmony_ci        int sumMiWinding, sumSuWinding;
50cb93a386Sopenharmony_ci        if (sortable) {
51cb93a386Sopenharmony_ci            segment = angle->segment();
52cb93a386Sopenharmony_ci            sumMiWinding = segment->updateWindingReverse(angle);
53cb93a386Sopenharmony_ci            if (sumMiWinding == SK_MinS32) {
54cb93a386Sopenharmony_ci                SkASSERT(segment->globalState()->debugSkipAssert());
55cb93a386Sopenharmony_ci                *result = nullptr;
56cb93a386Sopenharmony_ci                return true;
57cb93a386Sopenharmony_ci            }
58cb93a386Sopenharmony_ci            sumSuWinding = segment->updateOppWindingReverse(angle);
59cb93a386Sopenharmony_ci            if (sumSuWinding == SK_MinS32) {
60cb93a386Sopenharmony_ci                SkASSERT(segment->globalState()->debugSkipAssert());
61cb93a386Sopenharmony_ci                *result = nullptr;
62cb93a386Sopenharmony_ci                return true;
63cb93a386Sopenharmony_ci            }
64cb93a386Sopenharmony_ci            if (segment->operand()) {
65cb93a386Sopenharmony_ci                using std::swap;
66cb93a386Sopenharmony_ci                swap(sumMiWinding, sumSuWinding);
67cb93a386Sopenharmony_ci            }
68cb93a386Sopenharmony_ci        }
69cb93a386Sopenharmony_ci        SkOpSegment* first = nullptr;
70cb93a386Sopenharmony_ci        const SkOpAngle* firstAngle = angle;
71cb93a386Sopenharmony_ci        while ((angle = angle->next()) != firstAngle) {
72cb93a386Sopenharmony_ci            segment = angle->segment();
73cb93a386Sopenharmony_ci            SkOpSpanBase* start = angle->start();
74cb93a386Sopenharmony_ci            SkOpSpanBase* end = angle->end();
75cb93a386Sopenharmony_ci            int maxWinding = 0, sumWinding = 0, oppMaxWinding = 0, oppSumWinding = 0;
76cb93a386Sopenharmony_ci            if (sortable) {
77cb93a386Sopenharmony_ci                segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding,
78cb93a386Sopenharmony_ci                        &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
79cb93a386Sopenharmony_ci            }
80cb93a386Sopenharmony_ci            if (!segment->done(angle)) {
81cb93a386Sopenharmony_ci                if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) {
82cb93a386Sopenharmony_ci                    first = segment;
83cb93a386Sopenharmony_ci                    *startPtr = start;
84cb93a386Sopenharmony_ci                    *endPtr = end;
85cb93a386Sopenharmony_ci                }
86cb93a386Sopenharmony_ci                // OPTIMIZATION: should this also add to the chase?
87cb93a386Sopenharmony_ci                if (sortable) {
88cb93a386Sopenharmony_ci                    if (!segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
89cb93a386Sopenharmony_ci                            oppSumWinding, angle, nullptr)) {
90cb93a386Sopenharmony_ci                        return false;
91cb93a386Sopenharmony_ci                    }
92cb93a386Sopenharmony_ci                }
93cb93a386Sopenharmony_ci            }
94cb93a386Sopenharmony_ci        }
95cb93a386Sopenharmony_ci        if (first) {
96cb93a386Sopenharmony_ci       #if TRY_ROTATE
97cb93a386Sopenharmony_ci            *chase.insert(0) = span;
98cb93a386Sopenharmony_ci       #else
99cb93a386Sopenharmony_ci            *chase.append() = span;
100cb93a386Sopenharmony_ci       #endif
101cb93a386Sopenharmony_ci            *result = first;
102cb93a386Sopenharmony_ci            return true;
103cb93a386Sopenharmony_ci        }
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci    *result = nullptr;
106cb93a386Sopenharmony_ci    return true;
107cb93a386Sopenharmony_ci}
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_cistatic bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op,
110cb93a386Sopenharmony_ci        const int xorMask, const int xorOpMask, SkPathWriter* writer) {
111cb93a386Sopenharmony_ci    bool unsortable = false;
112cb93a386Sopenharmony_ci    bool lastSimple = false;
113cb93a386Sopenharmony_ci    bool simple = false;
114cb93a386Sopenharmony_ci    do {
115cb93a386Sopenharmony_ci        SkOpSpan* span = FindSortableTop(contourList);
116cb93a386Sopenharmony_ci        if (!span) {
117cb93a386Sopenharmony_ci            break;
118cb93a386Sopenharmony_ci        }
119cb93a386Sopenharmony_ci        SkOpSegment* current = span->segment();
120cb93a386Sopenharmony_ci        SkOpSpanBase* start = span->next();
121cb93a386Sopenharmony_ci        SkOpSpanBase* end = span;
122cb93a386Sopenharmony_ci        SkTDArray<SkOpSpanBase*> chase;
123cb93a386Sopenharmony_ci        do {
124cb93a386Sopenharmony_ci            if (current->activeOp(start, end, xorMask, xorOpMask, op)) {
125cb93a386Sopenharmony_ci                do {
126cb93a386Sopenharmony_ci                    if (!unsortable && current->done()) {
127cb93a386Sopenharmony_ci                        break;
128cb93a386Sopenharmony_ci                    }
129cb93a386Sopenharmony_ci                    SkASSERT(unsortable || !current->done());
130cb93a386Sopenharmony_ci                    SkOpSpanBase* nextStart = start;
131cb93a386Sopenharmony_ci                    SkOpSpanBase* nextEnd = end;
132cb93a386Sopenharmony_ci                    lastSimple = simple;
133cb93a386Sopenharmony_ci                    SkOpSegment* next = current->findNextOp(&chase, &nextStart, &nextEnd,
134cb93a386Sopenharmony_ci                            &unsortable, &simple, op, xorMask, xorOpMask);
135cb93a386Sopenharmony_ci                    if (!next) {
136cb93a386Sopenharmony_ci                        if (!unsortable && writer->hasMove()
137cb93a386Sopenharmony_ci                                && current->verb() != SkPath::kLine_Verb
138cb93a386Sopenharmony_ci                                && !writer->isClosed()) {
139cb93a386Sopenharmony_ci                            if (!current->addCurveTo(start, end, writer)) {
140cb93a386Sopenharmony_ci                                return false;
141cb93a386Sopenharmony_ci                            }
142cb93a386Sopenharmony_ci                            if (!writer->isClosed()) {
143cb93a386Sopenharmony_ci                                SkPathOpsDebug::ShowActiveSpans(contourList);
144cb93a386Sopenharmony_ci                            }
145cb93a386Sopenharmony_ci                        } else if (lastSimple) {
146cb93a386Sopenharmony_ci                            if (!current->addCurveTo(start, end, writer)) {
147cb93a386Sopenharmony_ci                                return false;
148cb93a386Sopenharmony_ci                            }
149cb93a386Sopenharmony_ci                        }
150cb93a386Sopenharmony_ci                        break;
151cb93a386Sopenharmony_ci                    }
152cb93a386Sopenharmony_ci        #if DEBUG_FLOW
153cb93a386Sopenharmony_ci                    SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
154cb93a386Sopenharmony_ci                            current->debugID(), start->pt().fX, start->pt().fY,
155cb93a386Sopenharmony_ci                            end->pt().fX, end->pt().fY);
156cb93a386Sopenharmony_ci        #endif
157cb93a386Sopenharmony_ci                    if (!current->addCurveTo(start, end, writer)) {
158cb93a386Sopenharmony_ci                        return false;
159cb93a386Sopenharmony_ci                    }
160cb93a386Sopenharmony_ci                    current = next;
161cb93a386Sopenharmony_ci                    start = nextStart;
162cb93a386Sopenharmony_ci                    end = nextEnd;
163cb93a386Sopenharmony_ci                } while (!writer->isClosed() && (!unsortable || !start->starter(end)->done()));
164cb93a386Sopenharmony_ci                if (current->activeWinding(start, end) && !writer->isClosed()) {
165cb93a386Sopenharmony_ci                    SkOpSpan* spanStart = start->starter(end);
166cb93a386Sopenharmony_ci                    if (!spanStart->done()) {
167cb93a386Sopenharmony_ci                        if (!current->addCurveTo(start, end, writer)) {
168cb93a386Sopenharmony_ci                            return false;
169cb93a386Sopenharmony_ci                        }
170cb93a386Sopenharmony_ci                        current->markDone(spanStart);
171cb93a386Sopenharmony_ci                    }
172cb93a386Sopenharmony_ci                }
173cb93a386Sopenharmony_ci                writer->finishContour();
174cb93a386Sopenharmony_ci            } else {
175cb93a386Sopenharmony_ci                SkOpSpanBase* last;
176cb93a386Sopenharmony_ci                if (!current->markAndChaseDone(start, end, &last)) {
177cb93a386Sopenharmony_ci                    return false;
178cb93a386Sopenharmony_ci                }
179cb93a386Sopenharmony_ci                if (last && !last->chased()) {
180cb93a386Sopenharmony_ci                    last->setChased(true);
181cb93a386Sopenharmony_ci                    SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last));
182cb93a386Sopenharmony_ci                    *chase.append() = last;
183cb93a386Sopenharmony_ci#if DEBUG_WINDING
184cb93a386Sopenharmony_ci                    SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segment()->debugID());
185cb93a386Sopenharmony_ci                    if (!last->final()) {
186cb93a386Sopenharmony_ci                         SkDebugf(" windSum=%d", last->upCast()->windSum());
187cb93a386Sopenharmony_ci                    }
188cb93a386Sopenharmony_ci                    SkDebugf("\n");
189cb93a386Sopenharmony_ci#endif
190cb93a386Sopenharmony_ci                }
191cb93a386Sopenharmony_ci            }
192cb93a386Sopenharmony_ci            if (!findChaseOp(chase, &start, &end, &current)) {
193cb93a386Sopenharmony_ci                return false;
194cb93a386Sopenharmony_ci            }
195cb93a386Sopenharmony_ci            SkPathOpsDebug::ShowActiveSpans(contourList);
196cb93a386Sopenharmony_ci            if (!current) {
197cb93a386Sopenharmony_ci                break;
198cb93a386Sopenharmony_ci            }
199cb93a386Sopenharmony_ci        } while (true);
200cb93a386Sopenharmony_ci    } while (true);
201cb93a386Sopenharmony_ci    return true;
202cb93a386Sopenharmony_ci}
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci// diagram of why this simplifcation is possible is here:
205cb93a386Sopenharmony_ci// https://skia.org/dev/present/pathops link at bottom of the page
206cb93a386Sopenharmony_ci// https://drive.google.com/file/d/0BwoLUwz9PYkHLWpsaXd0UDdaN00/view?usp=sharing
207cb93a386Sopenharmony_cistatic const SkPathOp gOpInverse[kReverseDifference_SkPathOp + 1][2][2] = {
208cb93a386Sopenharmony_ci//                  inside minuend                               outside minuend
209cb93a386Sopenharmony_ci//     inside subtrahend     outside subtrahend      inside subtrahend     outside subtrahend
210cb93a386Sopenharmony_ci{{ kDifference_SkPathOp,   kIntersect_SkPathOp }, { kUnion_SkPathOp, kReverseDifference_SkPathOp }},
211cb93a386Sopenharmony_ci{{ kIntersect_SkPathOp,   kDifference_SkPathOp }, { kReverseDifference_SkPathOp, kUnion_SkPathOp }},
212cb93a386Sopenharmony_ci{{ kUnion_SkPathOp, kReverseDifference_SkPathOp }, { kDifference_SkPathOp,   kIntersect_SkPathOp }},
213cb93a386Sopenharmony_ci{{ kXOR_SkPathOp,                 kXOR_SkPathOp }, { kXOR_SkPathOp,                kXOR_SkPathOp }},
214cb93a386Sopenharmony_ci{{ kReverseDifference_SkPathOp, kUnion_SkPathOp }, { kIntersect_SkPathOp,   kDifference_SkPathOp }},
215cb93a386Sopenharmony_ci};
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_cistatic const bool gOutInverse[kReverseDifference_SkPathOp + 1][2][2] = {
218cb93a386Sopenharmony_ci    {{ false, false }, { true, false }},  // diff
219cb93a386Sopenharmony_ci    {{ false, false }, { false, true }},  // sect
220cb93a386Sopenharmony_ci    {{ false, true }, { true, true }},    // union
221cb93a386Sopenharmony_ci    {{ false, true }, { true, false }},   // xor
222cb93a386Sopenharmony_ci    {{ false, true }, { false, false }},  // rev diff
223cb93a386Sopenharmony_ci};
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_ci#if DEBUG_T_SECT_LOOP_COUNT
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci#include "include/private/SkMutex.h"
228cb93a386Sopenharmony_ci
229cb93a386Sopenharmony_ciSkOpGlobalState debugWorstState(nullptr, nullptr  SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr));
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_civoid ReportPathOpsDebugging() {
232cb93a386Sopenharmony_ci    debugWorstState.debugLoopReport();
233cb93a386Sopenharmony_ci}
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_ciextern void (*gVerboseFinalize)();
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci#endif
238cb93a386Sopenharmony_ci
239cb93a386Sopenharmony_cibool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
240cb93a386Sopenharmony_ci        SkDEBUGPARAMS(bool skipAssert) SkDEBUGPARAMS(const char* testName)) {
241cb93a386Sopenharmony_ci#if DEBUG_DUMP_VERIFY
242cb93a386Sopenharmony_ci#ifndef SK_DEBUG
243cb93a386Sopenharmony_ci    const char* testName = "release";
244cb93a386Sopenharmony_ci#endif
245cb93a386Sopenharmony_ci    if (SkPathOpsDebug::gDumpOp) {
246cb93a386Sopenharmony_ci        SkPathOpsDebug::DumpOp(one, two, op, testName);
247cb93a386Sopenharmony_ci    }
248cb93a386Sopenharmony_ci#endif
249cb93a386Sopenharmony_ci    op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()];
250cb93a386Sopenharmony_ci    bool inverseFill = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()];
251cb93a386Sopenharmony_ci    SkPathFillType fillType = inverseFill ? SkPathFillType::kInverseEvenOdd :
252cb93a386Sopenharmony_ci            SkPathFillType::kEvenOdd;
253cb93a386Sopenharmony_ci    SkRect rect1, rect2;
254cb93a386Sopenharmony_ci    if (kIntersect_SkPathOp == op && one.isRect(&rect1) && two.isRect(&rect2)) {
255cb93a386Sopenharmony_ci        result->reset();
256cb93a386Sopenharmony_ci        result->setFillType(fillType);
257cb93a386Sopenharmony_ci        if (rect1.intersect(rect2)) {
258cb93a386Sopenharmony_ci            result->addRect(rect1);
259cb93a386Sopenharmony_ci        }
260cb93a386Sopenharmony_ci        return true;
261cb93a386Sopenharmony_ci    }
262cb93a386Sopenharmony_ci    if (one.isEmpty() || two.isEmpty()) {
263cb93a386Sopenharmony_ci        SkPath work;
264cb93a386Sopenharmony_ci        switch (op) {
265cb93a386Sopenharmony_ci            case kIntersect_SkPathOp:
266cb93a386Sopenharmony_ci                break;
267cb93a386Sopenharmony_ci            case kUnion_SkPathOp:
268cb93a386Sopenharmony_ci            case kXOR_SkPathOp:
269cb93a386Sopenharmony_ci                work = one.isEmpty() ? two : one;
270cb93a386Sopenharmony_ci                break;
271cb93a386Sopenharmony_ci            case kDifference_SkPathOp:
272cb93a386Sopenharmony_ci                if (!one.isEmpty()) {
273cb93a386Sopenharmony_ci                    work = one;
274cb93a386Sopenharmony_ci                }
275cb93a386Sopenharmony_ci                break;
276cb93a386Sopenharmony_ci            case kReverseDifference_SkPathOp:
277cb93a386Sopenharmony_ci                if (!two.isEmpty()) {
278cb93a386Sopenharmony_ci                    work = two;
279cb93a386Sopenharmony_ci                }
280cb93a386Sopenharmony_ci                break;
281cb93a386Sopenharmony_ci            default:
282cb93a386Sopenharmony_ci                SkASSERT(0);  // unhandled case
283cb93a386Sopenharmony_ci        }
284cb93a386Sopenharmony_ci        if (inverseFill != work.isInverseFillType()) {
285cb93a386Sopenharmony_ci            work.toggleInverseFillType();
286cb93a386Sopenharmony_ci        }
287cb93a386Sopenharmony_ci        return Simplify(work, result);
288cb93a386Sopenharmony_ci    }
289cb93a386Sopenharmony_ci    SkSTArenaAlloc<4096> allocator;  // FIXME: add a constant expression here, tune
290cb93a386Sopenharmony_ci    SkOpContour contour;
291cb93a386Sopenharmony_ci    SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
292cb93a386Sopenharmony_ci    SkOpGlobalState globalState(contourList, &allocator
293cb93a386Sopenharmony_ci            SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName));
294cb93a386Sopenharmony_ci    SkOpCoincidence coincidence(&globalState);
295cb93a386Sopenharmony_ci    const SkPath* minuend = &one;
296cb93a386Sopenharmony_ci    const SkPath* subtrahend = &two;
297cb93a386Sopenharmony_ci    if (op == kReverseDifference_SkPathOp) {
298cb93a386Sopenharmony_ci        using std::swap;
299cb93a386Sopenharmony_ci        swap(minuend, subtrahend);
300cb93a386Sopenharmony_ci        op = kDifference_SkPathOp;
301cb93a386Sopenharmony_ci    }
302cb93a386Sopenharmony_ci#if DEBUG_SORT
303cb93a386Sopenharmony_ci    SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
304cb93a386Sopenharmony_ci#endif
305cb93a386Sopenharmony_ci    // turn path into list of segments
306cb93a386Sopenharmony_ci    SkOpEdgeBuilder builder(*minuend, contourList, &globalState);
307cb93a386Sopenharmony_ci    if (builder.unparseable()) {
308cb93a386Sopenharmony_ci        return false;
309cb93a386Sopenharmony_ci    }
310cb93a386Sopenharmony_ci    const int xorMask = builder.xorMask();
311cb93a386Sopenharmony_ci    builder.addOperand(*subtrahend);
312cb93a386Sopenharmony_ci    if (!builder.finish()) {
313cb93a386Sopenharmony_ci        return false;
314cb93a386Sopenharmony_ci    }
315cb93a386Sopenharmony_ci#if DEBUG_DUMP_SEGMENTS
316cb93a386Sopenharmony_ci    contourList->dumpSegments("seg", op);
317cb93a386Sopenharmony_ci#endif
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_ci    const int xorOpMask = builder.xorMask();
320cb93a386Sopenharmony_ci    if (!SortContourList(&contourList, xorMask == kEvenOdd_PathOpsMask,
321cb93a386Sopenharmony_ci            xorOpMask == kEvenOdd_PathOpsMask)) {
322cb93a386Sopenharmony_ci        result->reset();
323cb93a386Sopenharmony_ci        result->setFillType(fillType);
324cb93a386Sopenharmony_ci        return true;
325cb93a386Sopenharmony_ci    }
326cb93a386Sopenharmony_ci    // find all intersections between segments
327cb93a386Sopenharmony_ci    SkOpContour* current = contourList;
328cb93a386Sopenharmony_ci    do {
329cb93a386Sopenharmony_ci        SkOpContour* next = current;
330cb93a386Sopenharmony_ci        while (AddIntersectTs(current, next, &coincidence)
331cb93a386Sopenharmony_ci                && (next = next->next()))
332cb93a386Sopenharmony_ci            ;
333cb93a386Sopenharmony_ci    } while ((current = current->next()));
334cb93a386Sopenharmony_ci#if DEBUG_VALIDATE
335cb93a386Sopenharmony_ci    globalState.setPhase(SkOpPhase::kWalking);
336cb93a386Sopenharmony_ci#endif
337cb93a386Sopenharmony_ci    bool success = HandleCoincidence(contourList, &coincidence);
338cb93a386Sopenharmony_ci#if DEBUG_COIN
339cb93a386Sopenharmony_ci    globalState.debugAddToGlobalCoinDicts();
340cb93a386Sopenharmony_ci#endif
341cb93a386Sopenharmony_ci    if (!success) {
342cb93a386Sopenharmony_ci        return false;
343cb93a386Sopenharmony_ci    }
344cb93a386Sopenharmony_ci#if DEBUG_ALIGNMENT
345cb93a386Sopenharmony_ci    contourList->dumpSegments("aligned");
346cb93a386Sopenharmony_ci#endif
347cb93a386Sopenharmony_ci    // construct closed contours
348cb93a386Sopenharmony_ci    SkPath original = *result;
349cb93a386Sopenharmony_ci    result->reset();
350cb93a386Sopenharmony_ci    result->setFillType(fillType);
351cb93a386Sopenharmony_ci    SkPathWriter wrapper(*result);
352cb93a386Sopenharmony_ci    if (!bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper)) {
353cb93a386Sopenharmony_ci        *result = original;
354cb93a386Sopenharmony_ci        return false;
355cb93a386Sopenharmony_ci    }
356cb93a386Sopenharmony_ci    wrapper.assemble();  // if some edges could not be resolved, assemble remaining
357cb93a386Sopenharmony_ci#if DEBUG_T_SECT_LOOP_COUNT
358cb93a386Sopenharmony_ci    static SkMutex& debugWorstLoop = *(new SkMutex);
359cb93a386Sopenharmony_ci    {
360cb93a386Sopenharmony_ci        SkAutoMutexExclusive autoM(debugWorstLoop);
361cb93a386Sopenharmony_ci        if (!gVerboseFinalize) {
362cb93a386Sopenharmony_ci            gVerboseFinalize = &ReportPathOpsDebugging;
363cb93a386Sopenharmony_ci        }
364cb93a386Sopenharmony_ci        debugWorstState.debugDoYourWorst(&globalState);
365cb93a386Sopenharmony_ci    }
366cb93a386Sopenharmony_ci#endif
367cb93a386Sopenharmony_ci    return true;
368cb93a386Sopenharmony_ci}
369cb93a386Sopenharmony_ci
370cb93a386Sopenharmony_cibool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
371cb93a386Sopenharmony_ci#if DEBUG_DUMP_VERIFY
372cb93a386Sopenharmony_ci    if (SkPathOpsDebug::gVerifyOp) {
373cb93a386Sopenharmony_ci        if (!OpDebug(one, two, op, result  SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) {
374cb93a386Sopenharmony_ci            SkPathOpsDebug::ReportOpFail(one, two, op);
375cb93a386Sopenharmony_ci            return false;
376cb93a386Sopenharmony_ci        }
377cb93a386Sopenharmony_ci        SkPathOpsDebug::VerifyOp(one, two, op, *result);
378cb93a386Sopenharmony_ci        return true;
379cb93a386Sopenharmony_ci    }
380cb93a386Sopenharmony_ci#endif
381cb93a386Sopenharmony_ci    return OpDebug(one, two, op, result  SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
382cb93a386Sopenharmony_ci}
383