1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
9cb93a386Sopenharmony_ci#include "include/private/SkTDArray.h"
10cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
11cb93a386Sopenharmony_ci#include "src/core/SkBlitter.h"
12cb93a386Sopenharmony_ci#include "src/core/SkRegionPriv.h"
13cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h"
14cb93a386Sopenharmony_ci#include "src/core/SkScan.h"
15cb93a386Sopenharmony_ci#include "src/core/SkTSort.h"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ci// The rgnbuilder caller *seems* to pass short counts, possible often seens early failure, so
18cb93a386Sopenharmony_ci// we may not want to promote this to a "std" routine just yet.
19cb93a386Sopenharmony_cistatic bool sk_memeq32(const int32_t* SK_RESTRICT a, const int32_t* SK_RESTRICT b, int count) {
20cb93a386Sopenharmony_ci    for (int i = 0; i < count; ++i) {
21cb93a386Sopenharmony_ci        if (a[i] != b[i]) {
22cb93a386Sopenharmony_ci            return false;
23cb93a386Sopenharmony_ci        }
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci    return true;
26cb93a386Sopenharmony_ci}
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ciclass SkRgnBuilder : public SkBlitter {
29cb93a386Sopenharmony_cipublic:
30cb93a386Sopenharmony_ci    SkRgnBuilder();
31cb93a386Sopenharmony_ci    ~SkRgnBuilder() override;
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ci    // returns true if it could allocate the working storage needed
34cb93a386Sopenharmony_ci    bool init(int maxHeight, int maxTransitions, bool pathIsInverse);
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    void done() {
37cb93a386Sopenharmony_ci        if (fCurrScanline != nullptr) {
38cb93a386Sopenharmony_ci            fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
39cb93a386Sopenharmony_ci            if (!this->collapsWithPrev()) { // flush the last line
40cb93a386Sopenharmony_ci                fCurrScanline = fCurrScanline->nextScanline();
41cb93a386Sopenharmony_ci            }
42cb93a386Sopenharmony_ci        }
43cb93a386Sopenharmony_ci    }
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci    int     computeRunCount() const;
46cb93a386Sopenharmony_ci    void    copyToRect(SkIRect*) const;
47cb93a386Sopenharmony_ci    void    copyToRgn(SkRegion::RunType runs[]) const;
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci    void blitH(int x, int y, int width) override;
50cb93a386Sopenharmony_ci    void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) override {
51cb93a386Sopenharmony_ci        SkDEBUGFAIL("blitAntiH not implemented");
52cb93a386Sopenharmony_ci    }
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci#ifdef SK_DEBUG
55cb93a386Sopenharmony_ci    void dump() const {
56cb93a386Sopenharmony_ci        SkDebugf("SkRgnBuilder: Top = %d\n", fTop);
57cb93a386Sopenharmony_ci        const Scanline* line = (Scanline*)fStorage;
58cb93a386Sopenharmony_ci        while (line < fCurrScanline) {
59cb93a386Sopenharmony_ci            SkDebugf("SkRgnBuilder::Scanline: LastY=%d, fXCount=%d", line->fLastY, line->fXCount);
60cb93a386Sopenharmony_ci            for (int i = 0; i < line->fXCount; i++) {
61cb93a386Sopenharmony_ci                SkDebugf(" %d", line->firstX()[i]);
62cb93a386Sopenharmony_ci            }
63cb93a386Sopenharmony_ci            SkDebugf("\n");
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci            line = line->nextScanline();
66cb93a386Sopenharmony_ci        }
67cb93a386Sopenharmony_ci    }
68cb93a386Sopenharmony_ci#endif
69cb93a386Sopenharmony_ciprivate:
70cb93a386Sopenharmony_ci    /*
71cb93a386Sopenharmony_ci     *  Scanline mimics a row in the region, nearly. A row in a region is:
72cb93a386Sopenharmony_ci     *      [Bottom IntervalCount [L R]... Sentinel]
73cb93a386Sopenharmony_ci     *  while a Scanline is
74cb93a386Sopenharmony_ci     *      [LastY XCount [L R]... uninitialized]
75cb93a386Sopenharmony_ci     *  The two are the same length (which is good), but we have to transmute
76cb93a386Sopenharmony_ci     *  the scanline a little when we convert it to a region-row.
77cb93a386Sopenharmony_ci     *
78cb93a386Sopenharmony_ci     *  Potentially we could recode this to exactly match the row format, in
79cb93a386Sopenharmony_ci     *  which case copyToRgn() could be a single memcpy. Not sure that is worth
80cb93a386Sopenharmony_ci     *  the effort.
81cb93a386Sopenharmony_ci     */
82cb93a386Sopenharmony_ci    struct Scanline {
83cb93a386Sopenharmony_ci        SkRegion::RunType fLastY;
84cb93a386Sopenharmony_ci        SkRegion::RunType fXCount;
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci        SkRegion::RunType* firstX() const { return (SkRegion::RunType*)(this + 1); }
87cb93a386Sopenharmony_ci        Scanline* nextScanline() const {
88cb93a386Sopenharmony_ci            // add final +1 for the x-sentinel
89cb93a386Sopenharmony_ci            return (Scanline*)((SkRegion::RunType*)(this + 1) + fXCount + 1);
90cb93a386Sopenharmony_ci        }
91cb93a386Sopenharmony_ci    };
92cb93a386Sopenharmony_ci    SkRegion::RunType*  fStorage;
93cb93a386Sopenharmony_ci    Scanline*           fCurrScanline;
94cb93a386Sopenharmony_ci    Scanline*           fPrevScanline;
95cb93a386Sopenharmony_ci    //  points at next avialable x[] in fCurrScanline
96cb93a386Sopenharmony_ci    SkRegion::RunType*  fCurrXPtr;
97cb93a386Sopenharmony_ci    SkRegion::RunType   fTop;           // first Y value
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci    int fStorageCount;
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    bool collapsWithPrev() {
102cb93a386Sopenharmony_ci        if (fPrevScanline != nullptr &&
103cb93a386Sopenharmony_ci            fPrevScanline->fLastY + 1 == fCurrScanline->fLastY &&
104cb93a386Sopenharmony_ci            fPrevScanline->fXCount == fCurrScanline->fXCount &&
105cb93a386Sopenharmony_ci            sk_memeq32(fPrevScanline->firstX(), fCurrScanline->firstX(), fCurrScanline->fXCount))
106cb93a386Sopenharmony_ci        {
107cb93a386Sopenharmony_ci            // update the height of fPrevScanline
108cb93a386Sopenharmony_ci            fPrevScanline->fLastY = fCurrScanline->fLastY;
109cb93a386Sopenharmony_ci            return true;
110cb93a386Sopenharmony_ci        }
111cb93a386Sopenharmony_ci        return false;
112cb93a386Sopenharmony_ci    }
113cb93a386Sopenharmony_ci};
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ciSkRgnBuilder::SkRgnBuilder()
116cb93a386Sopenharmony_ci    : fStorage(nullptr) {
117cb93a386Sopenharmony_ci}
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ciSkRgnBuilder::~SkRgnBuilder() {
120cb93a386Sopenharmony_ci    sk_free(fStorage);
121cb93a386Sopenharmony_ci}
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_cibool SkRgnBuilder::init(int maxHeight, int maxTransitions, bool pathIsInverse) {
124cb93a386Sopenharmony_ci    if ((maxHeight | maxTransitions) < 0) {
125cb93a386Sopenharmony_ci        return false;
126cb93a386Sopenharmony_ci    }
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci    SkSafeMath  safe;
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ci    if (pathIsInverse) {
131cb93a386Sopenharmony_ci        // allow for additional X transitions to "invert" each scanline
132cb93a386Sopenharmony_ci        // [ L' ... normal transitions ... R' ]
133cb93a386Sopenharmony_ci        //
134cb93a386Sopenharmony_ci        maxTransitions = safe.addInt(maxTransitions, 2);
135cb93a386Sopenharmony_ci    }
136cb93a386Sopenharmony_ci
137cb93a386Sopenharmony_ci    // compute the count with +1 and +3 slop for the working buffer
138cb93a386Sopenharmony_ci    size_t count = safe.mul(safe.addInt(maxHeight, 1), safe.addInt(3, maxTransitions));
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci    if (pathIsInverse) {
141cb93a386Sopenharmony_ci        // allow for two "empty" rows for the top and bottom
142cb93a386Sopenharmony_ci        //      [ Y, 1, L, R, S] == 5 (*2 for top and bottom)
143cb93a386Sopenharmony_ci        count = safe.add(count, 10);
144cb93a386Sopenharmony_ci    }
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci    if (!safe || !SkTFitsIn<int32_t>(count)) {
147cb93a386Sopenharmony_ci        return false;
148cb93a386Sopenharmony_ci    }
149cb93a386Sopenharmony_ci    fStorageCount = SkToS32(count);
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    fStorage = (SkRegion::RunType*)sk_malloc_canfail(fStorageCount, sizeof(SkRegion::RunType));
152cb93a386Sopenharmony_ci    if (nullptr == fStorage) {
153cb93a386Sopenharmony_ci        return false;
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    fCurrScanline = nullptr;    // signal empty collection
157cb93a386Sopenharmony_ci    fPrevScanline = nullptr;    // signal first scanline
158cb93a386Sopenharmony_ci    return true;
159cb93a386Sopenharmony_ci}
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_civoid SkRgnBuilder::blitH(int x, int y, int width) {
162cb93a386Sopenharmony_ci    if (fCurrScanline == nullptr) {  // first time
163cb93a386Sopenharmony_ci        fTop = (SkRegion::RunType)(y);
164cb93a386Sopenharmony_ci        fCurrScanline = (Scanline*)fStorage;
165cb93a386Sopenharmony_ci        fCurrScanline->fLastY = (SkRegion::RunType)(y);
166cb93a386Sopenharmony_ci        fCurrXPtr = fCurrScanline->firstX();
167cb93a386Sopenharmony_ci    } else {
168cb93a386Sopenharmony_ci        SkASSERT(y >= fCurrScanline->fLastY);
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci        if (y > fCurrScanline->fLastY) {
171cb93a386Sopenharmony_ci            // if we get here, we're done with fCurrScanline
172cb93a386Sopenharmony_ci            fCurrScanline->fXCount = (SkRegion::RunType)((int)(fCurrXPtr - fCurrScanline->firstX()));
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ci            int prevLastY = fCurrScanline->fLastY;
175cb93a386Sopenharmony_ci            if (!this->collapsWithPrev()) {
176cb93a386Sopenharmony_ci                fPrevScanline = fCurrScanline;
177cb93a386Sopenharmony_ci                fCurrScanline = fCurrScanline->nextScanline();
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci            }
180cb93a386Sopenharmony_ci            if (y - 1 > prevLastY) {  // insert empty run
181cb93a386Sopenharmony_ci                fCurrScanline->fLastY = (SkRegion::RunType)(y - 1);
182cb93a386Sopenharmony_ci                fCurrScanline->fXCount = 0;
183cb93a386Sopenharmony_ci                fCurrScanline = fCurrScanline->nextScanline();
184cb93a386Sopenharmony_ci            }
185cb93a386Sopenharmony_ci            // setup for the new curr line
186cb93a386Sopenharmony_ci            fCurrScanline->fLastY = (SkRegion::RunType)(y);
187cb93a386Sopenharmony_ci            fCurrXPtr = fCurrScanline->firstX();
188cb93a386Sopenharmony_ci        }
189cb93a386Sopenharmony_ci    }
190cb93a386Sopenharmony_ci    //  check if we should extend the current run, or add a new one
191cb93a386Sopenharmony_ci    if (fCurrXPtr > fCurrScanline->firstX() && fCurrXPtr[-1] == x) {
192cb93a386Sopenharmony_ci        fCurrXPtr[-1] = (SkRegion::RunType)(x + width);
193cb93a386Sopenharmony_ci    } else {
194cb93a386Sopenharmony_ci        fCurrXPtr[0] = (SkRegion::RunType)(x);
195cb93a386Sopenharmony_ci        fCurrXPtr[1] = (SkRegion::RunType)(x + width);
196cb93a386Sopenharmony_ci        fCurrXPtr += 2;
197cb93a386Sopenharmony_ci    }
198cb93a386Sopenharmony_ci    SkASSERT(fCurrXPtr - fStorage < fStorageCount);
199cb93a386Sopenharmony_ci}
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ciint SkRgnBuilder::computeRunCount() const {
202cb93a386Sopenharmony_ci    if (fCurrScanline == nullptr) {
203cb93a386Sopenharmony_ci        return 0;
204cb93a386Sopenharmony_ci    }
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_ci    const SkRegion::RunType*  line = fStorage;
207cb93a386Sopenharmony_ci    const SkRegion::RunType*  stop = (const SkRegion::RunType*)fCurrScanline;
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_ci    return 2 + (int)(stop - line);
210cb93a386Sopenharmony_ci}
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_civoid SkRgnBuilder::copyToRect(SkIRect* r) const {
213cb93a386Sopenharmony_ci    SkASSERT(fCurrScanline != nullptr);
214cb93a386Sopenharmony_ci    // A rect's scanline is [bottom intervals left right sentinel] == 5
215cb93a386Sopenharmony_ci    SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage == 5);
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci    const Scanline* line = (const Scanline*)fStorage;
218cb93a386Sopenharmony_ci    SkASSERT(line->fXCount == 2);
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    r->setLTRB(line->firstX()[0], fTop, line->firstX()[1], line->fLastY + 1);
221cb93a386Sopenharmony_ci}
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_civoid SkRgnBuilder::copyToRgn(SkRegion::RunType runs[]) const {
224cb93a386Sopenharmony_ci    SkASSERT(fCurrScanline != nullptr);
225cb93a386Sopenharmony_ci    SkASSERT((const SkRegion::RunType*)fCurrScanline - fStorage > 4);
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    const Scanline* line = (const Scanline*)fStorage;
228cb93a386Sopenharmony_ci    const Scanline* stop = fCurrScanline;
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    *runs++ = fTop;
231cb93a386Sopenharmony_ci    do {
232cb93a386Sopenharmony_ci        *runs++ = (SkRegion::RunType)(line->fLastY + 1);
233cb93a386Sopenharmony_ci        int count = line->fXCount;
234cb93a386Sopenharmony_ci        *runs++ = count >> 1;   // intervalCount
235cb93a386Sopenharmony_ci        if (count) {
236cb93a386Sopenharmony_ci            memcpy(runs, line->firstX(), count * sizeof(SkRegion::RunType));
237cb93a386Sopenharmony_ci            runs += count;
238cb93a386Sopenharmony_ci        }
239cb93a386Sopenharmony_ci        *runs++ = SkRegion_kRunTypeSentinel;
240cb93a386Sopenharmony_ci        line = line->nextScanline();
241cb93a386Sopenharmony_ci    } while (line < stop);
242cb93a386Sopenharmony_ci    SkASSERT(line == stop);
243cb93a386Sopenharmony_ci    *runs = SkRegion_kRunTypeSentinel;
244cb93a386Sopenharmony_ci}
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_cistatic unsigned verb_to_initial_last_index(unsigned verb) {
247cb93a386Sopenharmony_ci    static const uint8_t gPathVerbToInitialLastIndex[] = {
248cb93a386Sopenharmony_ci        0,  //  kMove_Verb
249cb93a386Sopenharmony_ci        1,  //  kLine_Verb
250cb93a386Sopenharmony_ci        2,  //  kQuad_Verb
251cb93a386Sopenharmony_ci        2,  //  kConic_Verb
252cb93a386Sopenharmony_ci        3,  //  kCubic_Verb
253cb93a386Sopenharmony_ci        0,  //  kClose_Verb
254cb93a386Sopenharmony_ci        0   //  kDone_Verb
255cb93a386Sopenharmony_ci    };
256cb93a386Sopenharmony_ci    SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToInitialLastIndex));
257cb93a386Sopenharmony_ci    return gPathVerbToInitialLastIndex[verb];
258cb93a386Sopenharmony_ci}
259cb93a386Sopenharmony_ci
260cb93a386Sopenharmony_cistatic unsigned verb_to_max_edges(unsigned verb) {
261cb93a386Sopenharmony_ci    static const uint8_t gPathVerbToMaxEdges[] = {
262cb93a386Sopenharmony_ci        0,  //  kMove_Verb
263cb93a386Sopenharmony_ci        1,  //  kLine_Verb
264cb93a386Sopenharmony_ci        2,  //  kQuad_VerbB
265cb93a386Sopenharmony_ci        2,  //  kConic_VerbB
266cb93a386Sopenharmony_ci        3,  //  kCubic_Verb
267cb93a386Sopenharmony_ci        0,  //  kClose_Verb
268cb93a386Sopenharmony_ci        0   //  kDone_Verb
269cb93a386Sopenharmony_ci    };
270cb93a386Sopenharmony_ci    SkASSERT((unsigned)verb < SK_ARRAY_COUNT(gPathVerbToMaxEdges));
271cb93a386Sopenharmony_ci    return gPathVerbToMaxEdges[verb];
272cb93a386Sopenharmony_ci}
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_ci// If returns 0, ignore itop and ibot
275cb93a386Sopenharmony_cistatic int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
276cb93a386Sopenharmony_ci    SkPath::Iter    iter(path, true);
277cb93a386Sopenharmony_ci    SkPoint         pts[4];
278cb93a386Sopenharmony_ci    SkPath::Verb    verb;
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci    int maxEdges = 0;
281cb93a386Sopenharmony_ci    SkScalar    top = SkIntToScalar(SK_MaxS16);
282cb93a386Sopenharmony_ci    SkScalar    bot = SkIntToScalar(SK_MinS16);
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
285cb93a386Sopenharmony_ci        maxEdges += verb_to_max_edges(verb);
286cb93a386Sopenharmony_ci
287cb93a386Sopenharmony_ci        int lastIndex = verb_to_initial_last_index(verb);
288cb93a386Sopenharmony_ci        if (lastIndex > 0) {
289cb93a386Sopenharmony_ci            for (int i = 1; i <= lastIndex; i++) {
290cb93a386Sopenharmony_ci                if (top > pts[i].fY) {
291cb93a386Sopenharmony_ci                    top = pts[i].fY;
292cb93a386Sopenharmony_ci                } else if (bot < pts[i].fY) {
293cb93a386Sopenharmony_ci                    bot = pts[i].fY;
294cb93a386Sopenharmony_ci                }
295cb93a386Sopenharmony_ci            }
296cb93a386Sopenharmony_ci        } else if (SkPath::kMove_Verb == verb) {
297cb93a386Sopenharmony_ci            if (top > pts[0].fY) {
298cb93a386Sopenharmony_ci                top = pts[0].fY;
299cb93a386Sopenharmony_ci            } else if (bot < pts[0].fY) {
300cb93a386Sopenharmony_ci                bot = pts[0].fY;
301cb93a386Sopenharmony_ci            }
302cb93a386Sopenharmony_ci        }
303cb93a386Sopenharmony_ci    }
304cb93a386Sopenharmony_ci    if (0 == maxEdges) {
305cb93a386Sopenharmony_ci        return 0;   // we have only moves+closes
306cb93a386Sopenharmony_ci    }
307cb93a386Sopenharmony_ci
308cb93a386Sopenharmony_ci    SkASSERT(top <= bot);
309cb93a386Sopenharmony_ci    *itop = SkScalarRoundToInt(top);
310cb93a386Sopenharmony_ci    *ibot = SkScalarRoundToInt(bot);
311cb93a386Sopenharmony_ci    return maxEdges;
312cb93a386Sopenharmony_ci}
313cb93a386Sopenharmony_ci
314cb93a386Sopenharmony_cistatic bool check_inverse_on_empty_return(SkRegion* dst, const SkPath& path, const SkRegion& clip) {
315cb93a386Sopenharmony_ci    if (path.isInverseFillType()) {
316cb93a386Sopenharmony_ci        return dst->set(clip);
317cb93a386Sopenharmony_ci    } else {
318cb93a386Sopenharmony_ci        return dst->setEmpty();
319cb93a386Sopenharmony_ci    }
320cb93a386Sopenharmony_ci}
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_cibool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
323cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
324cb93a386Sopenharmony_ci
325cb93a386Sopenharmony_ci    if (clip.isEmpty() || !path.isFinite() || path.isEmpty()) {
326cb93a386Sopenharmony_ci        // This treats non-finite paths as empty as well, so this returns empty or 'clip' if
327cb93a386Sopenharmony_ci        // it's inverse-filled. If clip is also empty, path's fill type doesn't really matter
328cb93a386Sopenharmony_ci        // and this region ends up empty.
329cb93a386Sopenharmony_ci        return check_inverse_on_empty_return(this, path, clip);
330cb93a386Sopenharmony_ci    }
331cb93a386Sopenharmony_ci
332cb93a386Sopenharmony_ci    // Our builder is very fragile, and can't be called with spans/rects out of Y->X order.
333cb93a386Sopenharmony_ci    // To ensure this, we only "fill" clipped to a rect (the clip's bounds), and if the
334cb93a386Sopenharmony_ci    // clip is more complex than that, we just post-intersect the result with the clip.
335cb93a386Sopenharmony_ci    if (clip.isComplex()) {
336cb93a386Sopenharmony_ci        if (!this->setPath(path, SkRegion(clip.getBounds()))) {
337cb93a386Sopenharmony_ci            return false;
338cb93a386Sopenharmony_ci        }
339cb93a386Sopenharmony_ci        return this->op(clip, kIntersect_Op);
340cb93a386Sopenharmony_ci    }
341cb93a386Sopenharmony_ci
342cb93a386Sopenharmony_ci    //  compute worst-case rgn-size for the path
343cb93a386Sopenharmony_ci    int pathTop, pathBot;
344cb93a386Sopenharmony_ci    int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
345cb93a386Sopenharmony_ci    if (0 == pathTransitions) {
346cb93a386Sopenharmony_ci        return check_inverse_on_empty_return(this, path, clip);
347cb93a386Sopenharmony_ci    }
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ci    int clipTop, clipBot;
350cb93a386Sopenharmony_ci    int clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
351cb93a386Sopenharmony_ci
352cb93a386Sopenharmony_ci    int top = std::max(pathTop, clipTop);
353cb93a386Sopenharmony_ci    int bot = std::min(pathBot, clipBot);
354cb93a386Sopenharmony_ci    if (top >= bot) {
355cb93a386Sopenharmony_ci        return check_inverse_on_empty_return(this, path, clip);
356cb93a386Sopenharmony_ci    }
357cb93a386Sopenharmony_ci
358cb93a386Sopenharmony_ci    SkRgnBuilder builder;
359cb93a386Sopenharmony_ci
360cb93a386Sopenharmony_ci    if (!builder.init(bot - top,
361cb93a386Sopenharmony_ci                      std::max(pathTransitions, clipTransitions),
362cb93a386Sopenharmony_ci                      path.isInverseFillType())) {
363cb93a386Sopenharmony_ci        // can't allocate working space, so return false
364cb93a386Sopenharmony_ci        return this->setEmpty();
365cb93a386Sopenharmony_ci    }
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ci    SkScan::FillPath(path, clip, &builder);
368cb93a386Sopenharmony_ci    builder.done();
369cb93a386Sopenharmony_ci
370cb93a386Sopenharmony_ci    int count = builder.computeRunCount();
371cb93a386Sopenharmony_ci    if (count == 0) {
372cb93a386Sopenharmony_ci        return this->setEmpty();
373cb93a386Sopenharmony_ci    } else if (count == kRectRegionRuns) {
374cb93a386Sopenharmony_ci        builder.copyToRect(&fBounds);
375cb93a386Sopenharmony_ci        this->setRect(fBounds);
376cb93a386Sopenharmony_ci    } else {
377cb93a386Sopenharmony_ci        SkRegion tmp;
378cb93a386Sopenharmony_ci
379cb93a386Sopenharmony_ci        tmp.fRunHead = RunHead::Alloc(count);
380cb93a386Sopenharmony_ci        builder.copyToRgn(tmp.fRunHead->writable_runs());
381cb93a386Sopenharmony_ci        tmp.fRunHead->computeRunBounds(&tmp.fBounds);
382cb93a386Sopenharmony_ci        this->swap(tmp);
383cb93a386Sopenharmony_ci    }
384cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
385cb93a386Sopenharmony_ci    return true;
386cb93a386Sopenharmony_ci}
387cb93a386Sopenharmony_ci
388cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////
389cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_cistruct Edge {
392cb93a386Sopenharmony_ci    enum {
393cb93a386Sopenharmony_ci        kY0Link = 0x01,
394cb93a386Sopenharmony_ci        kY1Link = 0x02,
395cb93a386Sopenharmony_ci
396cb93a386Sopenharmony_ci        kCompleteLink = (kY0Link | kY1Link)
397cb93a386Sopenharmony_ci    };
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci    SkRegionPriv::RunType fX;
400cb93a386Sopenharmony_ci    SkRegionPriv::RunType fY0, fY1;
401cb93a386Sopenharmony_ci    uint8_t fFlags;
402cb93a386Sopenharmony_ci    Edge*   fNext;
403cb93a386Sopenharmony_ci
404cb93a386Sopenharmony_ci    void set(int x, int y0, int y1) {
405cb93a386Sopenharmony_ci        SkASSERT(y0 != y1);
406cb93a386Sopenharmony_ci
407cb93a386Sopenharmony_ci        fX = (SkRegionPriv::RunType)(x);
408cb93a386Sopenharmony_ci        fY0 = (SkRegionPriv::RunType)(y0);
409cb93a386Sopenharmony_ci        fY1 = (SkRegionPriv::RunType)(y1);
410cb93a386Sopenharmony_ci        fFlags = 0;
411cb93a386Sopenharmony_ci        SkDEBUGCODE(fNext = nullptr;)
412cb93a386Sopenharmony_ci    }
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci    int top() const {
415cb93a386Sopenharmony_ci        return std::min(fY0, fY1);
416cb93a386Sopenharmony_ci    }
417cb93a386Sopenharmony_ci};
418cb93a386Sopenharmony_ci
419cb93a386Sopenharmony_cistatic void find_link(Edge* base, Edge* stop) {
420cb93a386Sopenharmony_ci    SkASSERT(base < stop);
421cb93a386Sopenharmony_ci
422cb93a386Sopenharmony_ci    if (base->fFlags == Edge::kCompleteLink) {
423cb93a386Sopenharmony_ci        SkASSERT(base->fNext);
424cb93a386Sopenharmony_ci        return;
425cb93a386Sopenharmony_ci    }
426cb93a386Sopenharmony_ci
427cb93a386Sopenharmony_ci    SkASSERT(base + 1 < stop);
428cb93a386Sopenharmony_ci
429cb93a386Sopenharmony_ci    int y0 = base->fY0;
430cb93a386Sopenharmony_ci    int y1 = base->fY1;
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ci    Edge* e = base;
433cb93a386Sopenharmony_ci    if ((base->fFlags & Edge::kY0Link) == 0) {
434cb93a386Sopenharmony_ci        for (;;) {
435cb93a386Sopenharmony_ci            e += 1;
436cb93a386Sopenharmony_ci            if ((e->fFlags & Edge::kY1Link) == 0 && y0 == e->fY1) {
437cb93a386Sopenharmony_ci                SkASSERT(nullptr == e->fNext);
438cb93a386Sopenharmony_ci                e->fNext = base;
439cb93a386Sopenharmony_ci                e->fFlags = SkToU8(e->fFlags | Edge::kY1Link);
440cb93a386Sopenharmony_ci                break;
441cb93a386Sopenharmony_ci            }
442cb93a386Sopenharmony_ci        }
443cb93a386Sopenharmony_ci    }
444cb93a386Sopenharmony_ci
445cb93a386Sopenharmony_ci    e = base;
446cb93a386Sopenharmony_ci    if ((base->fFlags & Edge::kY1Link) == 0) {
447cb93a386Sopenharmony_ci        for (;;) {
448cb93a386Sopenharmony_ci            e += 1;
449cb93a386Sopenharmony_ci            if ((e->fFlags & Edge::kY0Link) == 0 && y1 == e->fY0) {
450cb93a386Sopenharmony_ci                SkASSERT(nullptr == base->fNext);
451cb93a386Sopenharmony_ci                base->fNext = e;
452cb93a386Sopenharmony_ci                e->fFlags = SkToU8(e->fFlags | Edge::kY0Link);
453cb93a386Sopenharmony_ci                break;
454cb93a386Sopenharmony_ci            }
455cb93a386Sopenharmony_ci        }
456cb93a386Sopenharmony_ci    }
457cb93a386Sopenharmony_ci
458cb93a386Sopenharmony_ci    base->fFlags = Edge::kCompleteLink;
459cb93a386Sopenharmony_ci}
460cb93a386Sopenharmony_ci
461cb93a386Sopenharmony_cistatic int extract_path(Edge* edge, Edge* stop, SkPath* path) {
462cb93a386Sopenharmony_ci    while (0 == edge->fFlags) {
463cb93a386Sopenharmony_ci        edge++; // skip over "used" edges
464cb93a386Sopenharmony_ci    }
465cb93a386Sopenharmony_ci
466cb93a386Sopenharmony_ci    SkASSERT(edge < stop);
467cb93a386Sopenharmony_ci
468cb93a386Sopenharmony_ci    Edge* base = edge;
469cb93a386Sopenharmony_ci    Edge* prev = edge;
470cb93a386Sopenharmony_ci    edge = edge->fNext;
471cb93a386Sopenharmony_ci    SkASSERT(edge != base);
472cb93a386Sopenharmony_ci
473cb93a386Sopenharmony_ci    int count = 1;
474cb93a386Sopenharmony_ci    path->moveTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY0));
475cb93a386Sopenharmony_ci    prev->fFlags = 0;
476cb93a386Sopenharmony_ci    do {
477cb93a386Sopenharmony_ci        if (prev->fX != edge->fX || prev->fY1 != edge->fY0) { // skip collinear
478cb93a386Sopenharmony_ci            path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
479cb93a386Sopenharmony_ci            path->lineTo(SkIntToScalar(edge->fX), SkIntToScalar(edge->fY0));    // H
480cb93a386Sopenharmony_ci        }
481cb93a386Sopenharmony_ci        prev = edge;
482cb93a386Sopenharmony_ci        edge = edge->fNext;
483cb93a386Sopenharmony_ci        count += 1;
484cb93a386Sopenharmony_ci        prev->fFlags = 0;
485cb93a386Sopenharmony_ci    } while (edge != base);
486cb93a386Sopenharmony_ci    path->lineTo(SkIntToScalar(prev->fX), SkIntToScalar(prev->fY1));    // V
487cb93a386Sopenharmony_ci    path->close();
488cb93a386Sopenharmony_ci    return count;
489cb93a386Sopenharmony_ci}
490cb93a386Sopenharmony_ci
491cb93a386Sopenharmony_cistruct EdgeLT {
492cb93a386Sopenharmony_ci    bool operator()(const Edge& a, const Edge& b) const {
493cb93a386Sopenharmony_ci        return (a.fX == b.fX) ? a.top() < b.top() : a.fX < b.fX;
494cb93a386Sopenharmony_ci    }
495cb93a386Sopenharmony_ci};
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_cibool SkRegion::getBoundaryPath(SkPath* path) const {
498cb93a386Sopenharmony_ci    // path could safely be nullptr if we're empty, but the caller shouldn't
499cb93a386Sopenharmony_ci    // *know* that
500cb93a386Sopenharmony_ci    SkASSERT(path);
501cb93a386Sopenharmony_ci
502cb93a386Sopenharmony_ci    if (this->isEmpty()) {
503cb93a386Sopenharmony_ci        return false;
504cb93a386Sopenharmony_ci    }
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ci    const SkIRect& bounds = this->getBounds();
507cb93a386Sopenharmony_ci
508cb93a386Sopenharmony_ci    if (this->isRect()) {
509cb93a386Sopenharmony_ci        SkRect  r;
510cb93a386Sopenharmony_ci        r.set(bounds);      // this converts the ints to scalars
511cb93a386Sopenharmony_ci        path->addRect(r);
512cb93a386Sopenharmony_ci        return true;
513cb93a386Sopenharmony_ci    }
514cb93a386Sopenharmony_ci
515cb93a386Sopenharmony_ci    SkRegion::Iterator  iter(*this);
516cb93a386Sopenharmony_ci    SkTDArray<Edge>     edges;
517cb93a386Sopenharmony_ci
518cb93a386Sopenharmony_ci    for (const SkIRect& r = iter.rect(); !iter.done(); iter.next()) {
519cb93a386Sopenharmony_ci        Edge* edge = edges.append(2);
520cb93a386Sopenharmony_ci        edge[0].set(r.fLeft, r.fBottom, r.fTop);
521cb93a386Sopenharmony_ci        edge[1].set(r.fRight, r.fTop, r.fBottom);
522cb93a386Sopenharmony_ci    }
523cb93a386Sopenharmony_ci
524cb93a386Sopenharmony_ci    int count = edges.count();
525cb93a386Sopenharmony_ci    Edge* start = edges.begin();
526cb93a386Sopenharmony_ci    Edge* stop = start + count;
527cb93a386Sopenharmony_ci    SkTQSort<Edge>(start, stop, EdgeLT());
528cb93a386Sopenharmony_ci
529cb93a386Sopenharmony_ci    Edge* e;
530cb93a386Sopenharmony_ci    for (e = start; e != stop; e++) {
531cb93a386Sopenharmony_ci        find_link(e, stop);
532cb93a386Sopenharmony_ci    }
533cb93a386Sopenharmony_ci
534cb93a386Sopenharmony_ci#ifdef SK_DEBUG
535cb93a386Sopenharmony_ci    for (e = start; e != stop; e++) {
536cb93a386Sopenharmony_ci        SkASSERT(e->fNext != nullptr);
537cb93a386Sopenharmony_ci        SkASSERT(e->fFlags == Edge::kCompleteLink);
538cb93a386Sopenharmony_ci    }
539cb93a386Sopenharmony_ci#endif
540cb93a386Sopenharmony_ci
541cb93a386Sopenharmony_ci    path->incReserve(count << 1);
542cb93a386Sopenharmony_ci    do {
543cb93a386Sopenharmony_ci        SkASSERT(count > 1);
544cb93a386Sopenharmony_ci        count -= extract_path(start, stop, path);
545cb93a386Sopenharmony_ci    } while (count > 0);
546cb93a386Sopenharmony_ci
547cb93a386Sopenharmony_ci    return true;
548cb93a386Sopenharmony_ci}
549