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
8cb93a386Sopenharmony_ci#include "include/private/SkMacros.h"
9cb93a386Sopenharmony_ci#include "src/core/SkTSort.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkAddIntersections.h"
11cb93a386Sopenharmony_ci#include "src/pathops/SkOpCoincidence.h"
12cb93a386Sopenharmony_ci#include "src/pathops/SkOpEdgeBuilder.h"
13cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCommon.h"
14cb93a386Sopenharmony_ci#include "src/pathops/SkPathWriter.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ciconst SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windingPtr,
17cb93a386Sopenharmony_ci        bool* sortablePtr) {
18cb93a386Sopenharmony_ci    // find first angle, initialize winding to computed fWindSum
19cb93a386Sopenharmony_ci    SkOpSegment* segment = start->segment();
20cb93a386Sopenharmony_ci    const SkOpAngle* angle = segment->spanToAngle(start, end);
21cb93a386Sopenharmony_ci    if (!angle) {
22cb93a386Sopenharmony_ci        *windingPtr = SK_MinS32;
23cb93a386Sopenharmony_ci        return nullptr;
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci    bool computeWinding = false;
26cb93a386Sopenharmony_ci    const SkOpAngle* firstAngle = angle;
27cb93a386Sopenharmony_ci    bool loop = false;
28cb93a386Sopenharmony_ci    bool unorderable = false;
29cb93a386Sopenharmony_ci    int winding = SK_MinS32;
30cb93a386Sopenharmony_ci    do {
31cb93a386Sopenharmony_ci        angle = angle->next();
32cb93a386Sopenharmony_ci        if (!angle) {
33cb93a386Sopenharmony_ci            return nullptr;
34cb93a386Sopenharmony_ci        }
35cb93a386Sopenharmony_ci        unorderable |= angle->unorderable();
36cb93a386Sopenharmony_ci        if ((computeWinding = unorderable || (angle == firstAngle && loop))) {
37cb93a386Sopenharmony_ci            break;    // if we get here, there's no winding, loop is unorderable
38cb93a386Sopenharmony_ci        }
39cb93a386Sopenharmony_ci        loop |= angle == firstAngle;
40cb93a386Sopenharmony_ci        segment = angle->segment();
41cb93a386Sopenharmony_ci        winding = segment->windSum(angle);
42cb93a386Sopenharmony_ci    } while (winding == SK_MinS32);
43cb93a386Sopenharmony_ci    // if the angle loop contains an unorderable span, the angle order may be useless
44cb93a386Sopenharmony_ci    // directly compute the winding in this case for each span
45cb93a386Sopenharmony_ci    if (computeWinding) {
46cb93a386Sopenharmony_ci        firstAngle = angle;
47cb93a386Sopenharmony_ci        winding = SK_MinS32;
48cb93a386Sopenharmony_ci        do {
49cb93a386Sopenharmony_ci            SkOpSpanBase* startSpan = angle->start();
50cb93a386Sopenharmony_ci            SkOpSpanBase* endSpan = angle->end();
51cb93a386Sopenharmony_ci            SkOpSpan* lesser = startSpan->starter(endSpan);
52cb93a386Sopenharmony_ci            int testWinding = lesser->windSum();
53cb93a386Sopenharmony_ci            if (testWinding == SK_MinS32) {
54cb93a386Sopenharmony_ci                testWinding = lesser->computeWindSum();
55cb93a386Sopenharmony_ci            }
56cb93a386Sopenharmony_ci            if (testWinding != SK_MinS32) {
57cb93a386Sopenharmony_ci                segment = angle->segment();
58cb93a386Sopenharmony_ci                winding = testWinding;
59cb93a386Sopenharmony_ci            }
60cb93a386Sopenharmony_ci            angle = angle->next();
61cb93a386Sopenharmony_ci        } while (angle != firstAngle);
62cb93a386Sopenharmony_ci    }
63cb93a386Sopenharmony_ci    *sortablePtr = !unorderable;
64cb93a386Sopenharmony_ci    *windingPtr = winding;
65cb93a386Sopenharmony_ci    return angle;
66cb93a386Sopenharmony_ci}
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ciSkOpSpan* FindUndone(SkOpContourHead* contourHead) {
69cb93a386Sopenharmony_ci    SkOpContour* contour = contourHead;
70cb93a386Sopenharmony_ci    do {
71cb93a386Sopenharmony_ci        if (contour->done()) {
72cb93a386Sopenharmony_ci            continue;
73cb93a386Sopenharmony_ci        }
74cb93a386Sopenharmony_ci        SkOpSpan* result = contour->undoneSpan();
75cb93a386Sopenharmony_ci        if (result) {
76cb93a386Sopenharmony_ci            return result;
77cb93a386Sopenharmony_ci        }
78cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
79cb93a386Sopenharmony_ci    return nullptr;
80cb93a386Sopenharmony_ci}
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ciSkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
83cb93a386Sopenharmony_ci        SkOpSpanBase** endPtr) {
84cb93a386Sopenharmony_ci    while (chase->count()) {
85cb93a386Sopenharmony_ci        SkOpSpanBase* span;
86cb93a386Sopenharmony_ci        chase->pop(&span);
87cb93a386Sopenharmony_ci        SkOpSegment* segment = span->segment();
88cb93a386Sopenharmony_ci        *startPtr = span->ptT()->next()->span();
89cb93a386Sopenharmony_ci        bool done = true;
90cb93a386Sopenharmony_ci        *endPtr = nullptr;
91cb93a386Sopenharmony_ci        if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
92cb93a386Sopenharmony_ci            *startPtr = last->start();
93cb93a386Sopenharmony_ci            *endPtr = last->end();
94cb93a386Sopenharmony_ci    #if TRY_ROTATE
95cb93a386Sopenharmony_ci            *chase->insert(0) = span;
96cb93a386Sopenharmony_ci    #else
97cb93a386Sopenharmony_ci            *chase->append() = span;
98cb93a386Sopenharmony_ci    #endif
99cb93a386Sopenharmony_ci            return last->segment();
100cb93a386Sopenharmony_ci        }
101cb93a386Sopenharmony_ci        if (done) {
102cb93a386Sopenharmony_ci            continue;
103cb93a386Sopenharmony_ci        }
104cb93a386Sopenharmony_ci        // find first angle, initialize winding to computed wind sum
105cb93a386Sopenharmony_ci        int winding;
106cb93a386Sopenharmony_ci        bool sortable;
107cb93a386Sopenharmony_ci        const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
108cb93a386Sopenharmony_ci        if (!angle) {
109cb93a386Sopenharmony_ci            return nullptr;
110cb93a386Sopenharmony_ci        }
111cb93a386Sopenharmony_ci        if (winding == SK_MinS32) {
112cb93a386Sopenharmony_ci            continue;
113cb93a386Sopenharmony_ci        }
114cb93a386Sopenharmony_ci        int sumWinding SK_INIT_TO_AVOID_WARNING;
115cb93a386Sopenharmony_ci        if (sortable) {
116cb93a386Sopenharmony_ci            segment = angle->segment();
117cb93a386Sopenharmony_ci            sumWinding = segment->updateWindingReverse(angle);
118cb93a386Sopenharmony_ci        }
119cb93a386Sopenharmony_ci        SkOpSegment* first = nullptr;
120cb93a386Sopenharmony_ci        const SkOpAngle* firstAngle = angle;
121cb93a386Sopenharmony_ci        while ((angle = angle->next()) != firstAngle) {
122cb93a386Sopenharmony_ci            segment = angle->segment();
123cb93a386Sopenharmony_ci            SkOpSpanBase* start = angle->start();
124cb93a386Sopenharmony_ci            SkOpSpanBase* end = angle->end();
125cb93a386Sopenharmony_ci            int maxWinding SK_INIT_TO_AVOID_WARNING;
126cb93a386Sopenharmony_ci            if (sortable) {
127cb93a386Sopenharmony_ci                segment->setUpWinding(start, end, &maxWinding, &sumWinding);
128cb93a386Sopenharmony_ci            }
129cb93a386Sopenharmony_ci            if (!segment->done(angle)) {
130cb93a386Sopenharmony_ci                if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) {
131cb93a386Sopenharmony_ci                    first = segment;
132cb93a386Sopenharmony_ci                    *startPtr = start;
133cb93a386Sopenharmony_ci                    *endPtr = end;
134cb93a386Sopenharmony_ci                }
135cb93a386Sopenharmony_ci                // OPTIMIZATION: should this also add to the chase?
136cb93a386Sopenharmony_ci                if (sortable) {
137cb93a386Sopenharmony_ci                    // TODO: add error handling
138cb93a386Sopenharmony_ci                    SkAssertResult(segment->markAngle(maxWinding, sumWinding, angle, nullptr));
139cb93a386Sopenharmony_ci                }
140cb93a386Sopenharmony_ci            }
141cb93a386Sopenharmony_ci        }
142cb93a386Sopenharmony_ci        if (first) {
143cb93a386Sopenharmony_ci       #if TRY_ROTATE
144cb93a386Sopenharmony_ci            *chase->insert(0) = span;
145cb93a386Sopenharmony_ci       #else
146cb93a386Sopenharmony_ci            *chase->append() = span;
147cb93a386Sopenharmony_ci       #endif
148cb93a386Sopenharmony_ci            return first;
149cb93a386Sopenharmony_ci        }
150cb93a386Sopenharmony_ci    }
151cb93a386Sopenharmony_ci    return nullptr;
152cb93a386Sopenharmony_ci}
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_cibool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) {
155cb93a386Sopenharmony_ci    SkTDArray<SkOpContour* > list;
156cb93a386Sopenharmony_ci    SkOpContour* contour = *contourList;
157cb93a386Sopenharmony_ci    do {
158cb93a386Sopenharmony_ci        if (contour->count()) {
159cb93a386Sopenharmony_ci            contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
160cb93a386Sopenharmony_ci            *list.append() = contour;
161cb93a386Sopenharmony_ci        }
162cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
163cb93a386Sopenharmony_ci    int count = list.count();
164cb93a386Sopenharmony_ci    if (!count) {
165cb93a386Sopenharmony_ci        return false;
166cb93a386Sopenharmony_ci    }
167cb93a386Sopenharmony_ci    if (count > 1) {
168cb93a386Sopenharmony_ci        SkTQSort<SkOpContour>(list.begin(), list.end());
169cb93a386Sopenharmony_ci    }
170cb93a386Sopenharmony_ci    contour = list[0];
171cb93a386Sopenharmony_ci    SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour);
172cb93a386Sopenharmony_ci    contour->globalState()->setContourHead(contourHead);
173cb93a386Sopenharmony_ci    *contourList = contourHead;
174cb93a386Sopenharmony_ci    for (int index = 1; index < count; ++index) {
175cb93a386Sopenharmony_ci        SkOpContour* next = list[index];
176cb93a386Sopenharmony_ci        contour->setNext(next);
177cb93a386Sopenharmony_ci        contour = next;
178cb93a386Sopenharmony_ci    }
179cb93a386Sopenharmony_ci    contour->setNext(nullptr);
180cb93a386Sopenharmony_ci    return true;
181cb93a386Sopenharmony_ci}
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_cistatic void calc_angles(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
184cb93a386Sopenharmony_ci    DEBUG_STATIC_SET_PHASE(contourList);
185cb93a386Sopenharmony_ci    SkOpContour* contour = contourList;
186cb93a386Sopenharmony_ci    do {
187cb93a386Sopenharmony_ci        contour->calcAngles();
188cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
189cb93a386Sopenharmony_ci}
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_cistatic bool missing_coincidence(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
192cb93a386Sopenharmony_ci    DEBUG_STATIC_SET_PHASE(contourList);
193cb93a386Sopenharmony_ci    SkOpContour* contour = contourList;
194cb93a386Sopenharmony_ci    bool result = false;
195cb93a386Sopenharmony_ci    do {
196cb93a386Sopenharmony_ci        result |= contour->missingCoincidence();
197cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
198cb93a386Sopenharmony_ci    return result;
199cb93a386Sopenharmony_ci}
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_cistatic bool move_multiples(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
202cb93a386Sopenharmony_ci    DEBUG_STATIC_SET_PHASE(contourList);
203cb93a386Sopenharmony_ci    SkOpContour* contour = contourList;
204cb93a386Sopenharmony_ci    do {
205cb93a386Sopenharmony_ci        if (!contour->moveMultiples()) {
206cb93a386Sopenharmony_ci            return false;
207cb93a386Sopenharmony_ci        }
208cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
209cb93a386Sopenharmony_ci    return true;
210cb93a386Sopenharmony_ci}
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_cistatic bool move_nearby(SkOpContourHead* contourList  DEBUG_COIN_DECLARE_PARAMS()) {
213cb93a386Sopenharmony_ci    DEBUG_STATIC_SET_PHASE(contourList);
214cb93a386Sopenharmony_ci    SkOpContour* contour = contourList;
215cb93a386Sopenharmony_ci    do {
216cb93a386Sopenharmony_ci        if (!contour->moveNearby()) {
217cb93a386Sopenharmony_ci            return false;
218cb93a386Sopenharmony_ci        }
219cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
220cb93a386Sopenharmony_ci    return true;
221cb93a386Sopenharmony_ci}
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_cistatic bool sort_angles(SkOpContourHead* contourList) {
224cb93a386Sopenharmony_ci    SkOpContour* contour = contourList;
225cb93a386Sopenharmony_ci    do {
226cb93a386Sopenharmony_ci        if (!contour->sortAngles()) {
227cb93a386Sopenharmony_ci            return false;
228cb93a386Sopenharmony_ci        }
229cb93a386Sopenharmony_ci    } while ((contour = contour->next()));
230cb93a386Sopenharmony_ci    return true;
231cb93a386Sopenharmony_ci}
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_cibool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence) {
234cb93a386Sopenharmony_ci    SkOpGlobalState* globalState = contourList->globalState();
235cb93a386Sopenharmony_ci    // match up points within the coincident runs
236cb93a386Sopenharmony_ci    if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kIntersecting))) {
237cb93a386Sopenharmony_ci        return false;
238cb93a386Sopenharmony_ci    }
239cb93a386Sopenharmony_ci    // combine t values when multiple intersections occur on some segments but not others
240cb93a386Sopenharmony_ci    if (!move_multiples(contourList  DEBUG_PHASE_PARAMS(kWalking))) {
241cb93a386Sopenharmony_ci        return false;
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci    // move t values and points together to eliminate small/tiny gaps
244cb93a386Sopenharmony_ci    if (!move_nearby(contourList  DEBUG_COIN_PARAMS())) {
245cb93a386Sopenharmony_ci        return false;
246cb93a386Sopenharmony_ci    }
247cb93a386Sopenharmony_ci    // add coincidence formed by pairing on curve points and endpoints
248cb93a386Sopenharmony_ci    coincidence->correctEnds(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
249cb93a386Sopenharmony_ci    if (!coincidence->addEndMovedSpans(DEBUG_COIN_ONLY_PARAMS())) {
250cb93a386Sopenharmony_ci        return false;
251cb93a386Sopenharmony_ci    }
252cb93a386Sopenharmony_ci    const int SAFETY_COUNT = 3;
253cb93a386Sopenharmony_ci    int safetyHatch = SAFETY_COUNT;
254cb93a386Sopenharmony_ci    // look for coincidence present in A-B and A-C but missing in B-C
255cb93a386Sopenharmony_ci    do {
256cb93a386Sopenharmony_ci        bool added;
257cb93a386Sopenharmony_ci        if (!coincidence->addMissing(&added  DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
258cb93a386Sopenharmony_ci            return false;
259cb93a386Sopenharmony_ci        }
260cb93a386Sopenharmony_ci        if (!added) {
261cb93a386Sopenharmony_ci            break;
262cb93a386Sopenharmony_ci        }
263cb93a386Sopenharmony_ci        if (!--safetyHatch) {
264cb93a386Sopenharmony_ci            SkASSERT(globalState->debugSkipAssert());
265cb93a386Sopenharmony_ci            return false;
266cb93a386Sopenharmony_ci        }
267cb93a386Sopenharmony_ci        move_nearby(contourList  DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch - 1));
268cb93a386Sopenharmony_ci    } while (true);
269cb93a386Sopenharmony_ci    // check to see if, loosely, coincident ranges may be expanded
270cb93a386Sopenharmony_ci    if (coincidence->expand(DEBUG_COIN_ONLY_PARAMS())) {
271cb93a386Sopenharmony_ci        bool added;
272cb93a386Sopenharmony_ci        if (!coincidence->addMissing(&added  DEBUG_COIN_PARAMS())) {
273cb93a386Sopenharmony_ci            return false;
274cb93a386Sopenharmony_ci        }
275cb93a386Sopenharmony_ci        if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
276cb93a386Sopenharmony_ci            return false;
277cb93a386Sopenharmony_ci        }
278cb93a386Sopenharmony_ci        if (!move_multiples(contourList  DEBUG_COIN_PARAMS())) {
279cb93a386Sopenharmony_ci            return false;
280cb93a386Sopenharmony_ci        }
281cb93a386Sopenharmony_ci        move_nearby(contourList  DEBUG_COIN_PARAMS());
282cb93a386Sopenharmony_ci    }
283cb93a386Sopenharmony_ci    // the expanded ranges may not align -- add the missing spans
284cb93a386Sopenharmony_ci    if (!coincidence->addExpanded(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
285cb93a386Sopenharmony_ci        return false;
286cb93a386Sopenharmony_ci    }
287cb93a386Sopenharmony_ci    // mark spans of coincident segments as coincident
288cb93a386Sopenharmony_ci    coincidence->mark(DEBUG_COIN_ONLY_PARAMS());
289cb93a386Sopenharmony_ci    // look for coincidence lines and curves undetected by intersection
290cb93a386Sopenharmony_ci    if (missing_coincidence(contourList  DEBUG_COIN_PARAMS())) {
291cb93a386Sopenharmony_ci        (void) coincidence->expand(DEBUG_PHASE_ONLY_PARAMS(kIntersecting));
292cb93a386Sopenharmony_ci        if (!coincidence->addExpanded(DEBUG_COIN_ONLY_PARAMS())) {
293cb93a386Sopenharmony_ci            return false;
294cb93a386Sopenharmony_ci        }
295cb93a386Sopenharmony_ci        if (!coincidence->mark(DEBUG_PHASE_ONLY_PARAMS(kWalking))) {
296cb93a386Sopenharmony_ci            return false;
297cb93a386Sopenharmony_ci        }
298cb93a386Sopenharmony_ci    } else {
299cb93a386Sopenharmony_ci        (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
300cb93a386Sopenharmony_ci    }
301cb93a386Sopenharmony_ci    (void) coincidence->expand(DEBUG_COIN_ONLY_PARAMS());
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci    SkOpCoincidence overlaps(globalState);
304cb93a386Sopenharmony_ci    safetyHatch = SAFETY_COUNT;
305cb93a386Sopenharmony_ci    do {
306cb93a386Sopenharmony_ci        SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
307cb93a386Sopenharmony_ci        // adjust the winding value to account for coincident edges
308cb93a386Sopenharmony_ci        if (!pairs->apply(DEBUG_ITER_ONLY_PARAMS(SAFETY_COUNT - safetyHatch))) {
309cb93a386Sopenharmony_ci            return false;
310cb93a386Sopenharmony_ci        }
311cb93a386Sopenharmony_ci        // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
312cb93a386Sopenharmony_ci        // are different, construct a new pair to resolve their mutual span
313cb93a386Sopenharmony_ci        if (!pairs->findOverlaps(&overlaps  DEBUG_ITER_PARAMS(SAFETY_COUNT - safetyHatch))) {
314cb93a386Sopenharmony_ci            return false;
315cb93a386Sopenharmony_ci        }
316cb93a386Sopenharmony_ci        if (!--safetyHatch) {
317cb93a386Sopenharmony_ci            SkASSERT(globalState->debugSkipAssert());
318cb93a386Sopenharmony_ci            return false;
319cb93a386Sopenharmony_ci        }
320cb93a386Sopenharmony_ci    } while (!overlaps.isEmpty());
321cb93a386Sopenharmony_ci    calc_angles(contourList  DEBUG_COIN_PARAMS());
322cb93a386Sopenharmony_ci    if (!sort_angles(contourList)) {
323cb93a386Sopenharmony_ci        return false;
324cb93a386Sopenharmony_ci    }
325cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE
326cb93a386Sopenharmony_ci    coincidence->debugShowCoincidence();
327cb93a386Sopenharmony_ci#endif
328cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE
329cb93a386Sopenharmony_ci    coincidence->debugValidate();
330cb93a386Sopenharmony_ci#endif
331cb93a386Sopenharmony_ci    SkPathOpsDebug::ShowActiveSpans(contourList);
332cb93a386Sopenharmony_ci    return true;
333cb93a386Sopenharmony_ci}
334