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/SkRegion.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/private/SkMacros.h"
11cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
12cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
13cb93a386Sopenharmony_ci#include "src/core/SkRegionPriv.h"
14cb93a386Sopenharmony_ci#include "src/core/SkSafeMath.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#include <utility>
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci/* Region Layout
19cb93a386Sopenharmony_ci *
20cb93a386Sopenharmony_ci *  TOP
21cb93a386Sopenharmony_ci *
22cb93a386Sopenharmony_ci *  [ Bottom, X-Intervals, [Left, Right]..., X-Sentinel ]
23cb93a386Sopenharmony_ci *  ...
24cb93a386Sopenharmony_ci *
25cb93a386Sopenharmony_ci *  Y-Sentinel
26cb93a386Sopenharmony_ci */
27cb93a386Sopenharmony_ci
28cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci#define SkRegion_gEmptyRunHeadPtr   ((SkRegionPriv::RunHead*)-1)
31cb93a386Sopenharmony_ci#define SkRegion_gRectRunHeadPtr    nullptr
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ciconstexpr int kRunArrayStackCount = 256;
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci// This is a simple data structure which is like a SkSTArray<N,T,true>, except that:
36cb93a386Sopenharmony_ci//   - It does not initialize memory.
37cb93a386Sopenharmony_ci//   - It does not distinguish between reserved space and initialized space.
38cb93a386Sopenharmony_ci//   - resizeToAtLeast() instead of resize()
39cb93a386Sopenharmony_ci//   - Uses sk_realloc_throw()
40cb93a386Sopenharmony_ci//   - Can never be made smaller.
41cb93a386Sopenharmony_ci// Measurement:  for the `region_union_16` benchmark, this is 6% faster.
42cb93a386Sopenharmony_ciclass RunArray {
43cb93a386Sopenharmony_cipublic:
44cb93a386Sopenharmony_ci    RunArray() { fPtr = fStack; }
45cb93a386Sopenharmony_ci    #ifdef SK_DEBUG
46cb93a386Sopenharmony_ci    int count() const { return fCount; }
47cb93a386Sopenharmony_ci    #endif
48cb93a386Sopenharmony_ci    SkRegionPriv::RunType& operator[](int i) {
49cb93a386Sopenharmony_ci        SkASSERT((unsigned)i < (unsigned)fCount);
50cb93a386Sopenharmony_ci        return fPtr[i];
51cb93a386Sopenharmony_ci    }
52cb93a386Sopenharmony_ci    /** Resize the array to a size greater-than-or-equal-to count. */
53cb93a386Sopenharmony_ci    void resizeToAtLeast(int count) {
54cb93a386Sopenharmony_ci        if (count > fCount) {
55cb93a386Sopenharmony_ci            // leave at least 50% extra space for future growth.
56cb93a386Sopenharmony_ci            count += count >> 1;
57cb93a386Sopenharmony_ci            fMalloc.realloc(count);
58cb93a386Sopenharmony_ci            if (fPtr == fStack) {
59cb93a386Sopenharmony_ci                memcpy(fMalloc.get(), fStack, fCount * sizeof(SkRegionPriv::RunType));
60cb93a386Sopenharmony_ci            }
61cb93a386Sopenharmony_ci            fPtr = fMalloc.get();
62cb93a386Sopenharmony_ci            fCount = count;
63cb93a386Sopenharmony_ci        }
64cb93a386Sopenharmony_ci    }
65cb93a386Sopenharmony_ciprivate:
66cb93a386Sopenharmony_ci    SkRegionPriv::RunType fStack[kRunArrayStackCount];
67cb93a386Sopenharmony_ci    SkAutoTMalloc<SkRegionPriv::RunType> fMalloc;
68cb93a386Sopenharmony_ci    int fCount = kRunArrayStackCount;
69cb93a386Sopenharmony_ci    SkRegionPriv::RunType* fPtr;  // non-owning pointer
70cb93a386Sopenharmony_ci};
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci/*  Pass in the beginning with the intervals.
73cb93a386Sopenharmony_ci *  We back up 1 to read the interval-count.
74cb93a386Sopenharmony_ci *  Return the beginning of the next scanline (i.e. the next Y-value)
75cb93a386Sopenharmony_ci */
76cb93a386Sopenharmony_cistatic SkRegionPriv::RunType* skip_intervals(const SkRegionPriv::RunType runs[]) {
77cb93a386Sopenharmony_ci    int intervals = runs[-1];
78cb93a386Sopenharmony_ci#ifdef SK_DEBUG
79cb93a386Sopenharmony_ci    if (intervals > 0) {
80cb93a386Sopenharmony_ci        SkASSERT(runs[0] < runs[1]);
81cb93a386Sopenharmony_ci        SkASSERT(runs[1] < SkRegion_kRunTypeSentinel);
82cb93a386Sopenharmony_ci    } else {
83cb93a386Sopenharmony_ci        SkASSERT(0 == intervals);
84cb93a386Sopenharmony_ci        SkASSERT(SkRegion_kRunTypeSentinel == runs[0]);
85cb93a386Sopenharmony_ci    }
86cb93a386Sopenharmony_ci#endif
87cb93a386Sopenharmony_ci    runs += intervals * 2 + 1;
88cb93a386Sopenharmony_ci    return const_cast<SkRegionPriv::RunType*>(runs);
89cb93a386Sopenharmony_ci}
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_cibool SkRegion::RunsAreARect(const SkRegion::RunType runs[], int count,
92cb93a386Sopenharmony_ci                            SkIRect* bounds) {
93cb93a386Sopenharmony_ci    assert_sentinel(runs[0], false);    // top
94cb93a386Sopenharmony_ci    SkASSERT(count >= kRectRegionRuns);
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci    if (count == kRectRegionRuns) {
97cb93a386Sopenharmony_ci        assert_sentinel(runs[1], false);    // bottom
98cb93a386Sopenharmony_ci        SkASSERT(1 == runs[2]);
99cb93a386Sopenharmony_ci        assert_sentinel(runs[3], false);    // left
100cb93a386Sopenharmony_ci        assert_sentinel(runs[4], false);    // right
101cb93a386Sopenharmony_ci        assert_sentinel(runs[5], true);
102cb93a386Sopenharmony_ci        assert_sentinel(runs[6], true);
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci        SkASSERT(runs[0] < runs[1]);    // valid height
105cb93a386Sopenharmony_ci        SkASSERT(runs[3] < runs[4]);    // valid width
106cb93a386Sopenharmony_ci
107cb93a386Sopenharmony_ci        bounds->setLTRB(runs[3], runs[0], runs[4], runs[1]);
108cb93a386Sopenharmony_ci        return true;
109cb93a386Sopenharmony_ci    }
110cb93a386Sopenharmony_ci    return false;
111cb93a386Sopenharmony_ci}
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ciSkRegion::SkRegion() {
116cb93a386Sopenharmony_ci    fBounds.setEmpty();
117cb93a386Sopenharmony_ci    fRunHead = SkRegion_gEmptyRunHeadPtr;
118cb93a386Sopenharmony_ci}
119cb93a386Sopenharmony_ci
120cb93a386Sopenharmony_ciSkRegion::SkRegion(const SkRegion& src) {
121cb93a386Sopenharmony_ci    fRunHead = SkRegion_gEmptyRunHeadPtr;   // just need a value that won't trigger sk_free(fRunHead)
122cb93a386Sopenharmony_ci    this->setRegion(src);
123cb93a386Sopenharmony_ci}
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ciSkRegion::SkRegion(const SkIRect& rect) {
126cb93a386Sopenharmony_ci    fRunHead = SkRegion_gEmptyRunHeadPtr;   // just need a value that won't trigger sk_free(fRunHead)
127cb93a386Sopenharmony_ci    this->setRect(rect);
128cb93a386Sopenharmony_ci}
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ciSkRegion::~SkRegion() {
131cb93a386Sopenharmony_ci    this->freeRuns();
132cb93a386Sopenharmony_ci}
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_civoid SkRegion::freeRuns() {
135cb93a386Sopenharmony_ci    if (this->isComplex()) {
136cb93a386Sopenharmony_ci        SkASSERT(fRunHead->fRefCnt >= 1);
137cb93a386Sopenharmony_ci        if (--fRunHead->fRefCnt == 0) {
138cb93a386Sopenharmony_ci            sk_free(fRunHead);
139cb93a386Sopenharmony_ci        }
140cb93a386Sopenharmony_ci    }
141cb93a386Sopenharmony_ci}
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_civoid SkRegion::allocateRuns(int count, int ySpanCount, int intervalCount) {
144cb93a386Sopenharmony_ci    fRunHead = RunHead::Alloc(count, ySpanCount, intervalCount);
145cb93a386Sopenharmony_ci}
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_civoid SkRegion::allocateRuns(int count) {
148cb93a386Sopenharmony_ci    fRunHead = RunHead::Alloc(count);
149cb93a386Sopenharmony_ci}
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_civoid SkRegion::allocateRuns(const RunHead& head) {
152cb93a386Sopenharmony_ci    fRunHead = RunHead::Alloc(head.fRunCount,
153cb93a386Sopenharmony_ci                              head.getYSpanCount(),
154cb93a386Sopenharmony_ci                              head.getIntervalCount());
155cb93a386Sopenharmony_ci}
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ciSkRegion& SkRegion::operator=(const SkRegion& src) {
158cb93a386Sopenharmony_ci    (void)this->setRegion(src);
159cb93a386Sopenharmony_ci    return *this;
160cb93a386Sopenharmony_ci}
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_civoid SkRegion::swap(SkRegion& other) {
163cb93a386Sopenharmony_ci    using std::swap;
164cb93a386Sopenharmony_ci    swap(fBounds, other.fBounds);
165cb93a386Sopenharmony_ci    swap(fRunHead, other.fRunHead);
166cb93a386Sopenharmony_ci}
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ciint SkRegion::computeRegionComplexity() const {
169cb93a386Sopenharmony_ci  if (this->isEmpty()) {
170cb93a386Sopenharmony_ci    return 0;
171cb93a386Sopenharmony_ci  } else if (this->isRect()) {
172cb93a386Sopenharmony_ci    return 1;
173cb93a386Sopenharmony_ci  }
174cb93a386Sopenharmony_ci  return fRunHead->getIntervalCount();
175cb93a386Sopenharmony_ci}
176cb93a386Sopenharmony_ci
177cb93a386Sopenharmony_cibool SkRegion::setEmpty() {
178cb93a386Sopenharmony_ci    this->freeRuns();
179cb93a386Sopenharmony_ci    fBounds.setEmpty();
180cb93a386Sopenharmony_ci    fRunHead = SkRegion_gEmptyRunHeadPtr;
181cb93a386Sopenharmony_ci    return false;
182cb93a386Sopenharmony_ci}
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_cibool SkRegion::setRect(const SkIRect& r) {
185cb93a386Sopenharmony_ci    if (r.isEmpty() ||
186cb93a386Sopenharmony_ci        SkRegion_kRunTypeSentinel == r.right() ||
187cb93a386Sopenharmony_ci        SkRegion_kRunTypeSentinel == r.bottom()) {
188cb93a386Sopenharmony_ci        return this->setEmpty();
189cb93a386Sopenharmony_ci    }
190cb93a386Sopenharmony_ci    this->freeRuns();
191cb93a386Sopenharmony_ci    fBounds = r;
192cb93a386Sopenharmony_ci    fRunHead = SkRegion_gRectRunHeadPtr;
193cb93a386Sopenharmony_ci    return true;
194cb93a386Sopenharmony_ci}
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_cibool SkRegion::setRegion(const SkRegion& src) {
197cb93a386Sopenharmony_ci    if (this != &src) {
198cb93a386Sopenharmony_ci        this->freeRuns();
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ci        fBounds = src.fBounds;
201cb93a386Sopenharmony_ci        fRunHead = src.fRunHead;
202cb93a386Sopenharmony_ci        if (this->isComplex()) {
203cb93a386Sopenharmony_ci            fRunHead->fRefCnt++;
204cb93a386Sopenharmony_ci        }
205cb93a386Sopenharmony_ci    }
206cb93a386Sopenharmony_ci    return fRunHead != SkRegion_gEmptyRunHeadPtr;
207cb93a386Sopenharmony_ci}
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_cibool SkRegion::op(const SkIRect& rect, const SkRegion& rgn, Op op) {
210cb93a386Sopenharmony_ci    SkRegion tmp(rect);
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci    return this->op(tmp, rgn, op);
213cb93a386Sopenharmony_ci}
214cb93a386Sopenharmony_ci
215cb93a386Sopenharmony_cibool SkRegion::op(const SkRegion& rgn, const SkIRect& rect, Op op) {
216cb93a386Sopenharmony_ci    SkRegion tmp(rect);
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    return this->op(rgn, tmp, op);
219cb93a386Sopenharmony_ci}
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_ci#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
224cb93a386Sopenharmony_ci#include <stdio.h>
225cb93a386Sopenharmony_cichar* SkRegion::toString() {
226cb93a386Sopenharmony_ci    Iterator iter(*this);
227cb93a386Sopenharmony_ci    int count = 0;
228cb93a386Sopenharmony_ci    while (!iter.done()) {
229cb93a386Sopenharmony_ci        count++;
230cb93a386Sopenharmony_ci        iter.next();
231cb93a386Sopenharmony_ci    }
232cb93a386Sopenharmony_ci    // 4 ints, up to 10 digits each plus sign, 3 commas, '(', ')', SkRegion() and '\0'
233cb93a386Sopenharmony_ci    const int max = (count*((11*4)+5))+11+1;
234cb93a386Sopenharmony_ci    char* result = (char*)sk_malloc_throw(max);
235cb93a386Sopenharmony_ci    if (result == nullptr) {
236cb93a386Sopenharmony_ci        return nullptr;
237cb93a386Sopenharmony_ci    }
238cb93a386Sopenharmony_ci    count = snprintf(result, max, "SkRegion(");
239cb93a386Sopenharmony_ci    iter.reset(*this);
240cb93a386Sopenharmony_ci    while (!iter.done()) {
241cb93a386Sopenharmony_ci        const SkIRect& r = iter.rect();
242cb93a386Sopenharmony_ci        count += snprintf(result+count, max - count,
243cb93a386Sopenharmony_ci                "(%d,%d,%d,%d)", r.fLeft, r.fTop, r.fRight, r.fBottom);
244cb93a386Sopenharmony_ci        iter.next();
245cb93a386Sopenharmony_ci    }
246cb93a386Sopenharmony_ci    count += snprintf(result+count, max - count, ")");
247cb93a386Sopenharmony_ci    return result;
248cb93a386Sopenharmony_ci}
249cb93a386Sopenharmony_ci#endif
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ciint SkRegion::count_runtype_values(int* itop, int* ibot) const {
254cb93a386Sopenharmony_ci    int maxT;
255cb93a386Sopenharmony_ci
256cb93a386Sopenharmony_ci    if (this->isRect()) {
257cb93a386Sopenharmony_ci        maxT = 2;
258cb93a386Sopenharmony_ci    } else {
259cb93a386Sopenharmony_ci        SkASSERT(this->isComplex());
260cb93a386Sopenharmony_ci        maxT = fRunHead->getIntervalCount() * 2;
261cb93a386Sopenharmony_ci    }
262cb93a386Sopenharmony_ci    *itop = fBounds.fTop;
263cb93a386Sopenharmony_ci    *ibot = fBounds.fBottom;
264cb93a386Sopenharmony_ci    return maxT;
265cb93a386Sopenharmony_ci}
266cb93a386Sopenharmony_ci
267cb93a386Sopenharmony_cistatic bool isRunCountEmpty(int count) {
268cb93a386Sopenharmony_ci    return count <= 2;
269cb93a386Sopenharmony_ci}
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_cibool SkRegion::setRuns(RunType runs[], int count) {
272cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
273cb93a386Sopenharmony_ci    SkASSERT(count > 0);
274cb93a386Sopenharmony_ci
275cb93a386Sopenharmony_ci    if (isRunCountEmpty(count)) {
276cb93a386Sopenharmony_ci    //  SkDEBUGF("setRuns: empty\n");
277cb93a386Sopenharmony_ci        assert_sentinel(runs[count-1], true);
278cb93a386Sopenharmony_ci        return this->setEmpty();
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci    // trim off any empty spans from the top and bottom
282cb93a386Sopenharmony_ci    // weird I should need this, perhaps op() could be smarter...
283cb93a386Sopenharmony_ci    if (count > kRectRegionRuns) {
284cb93a386Sopenharmony_ci        RunType* stop = runs + count;
285cb93a386Sopenharmony_ci        assert_sentinel(runs[0], false);    // top
286cb93a386Sopenharmony_ci        assert_sentinel(runs[1], false);    // bottom
287cb93a386Sopenharmony_ci        // runs[2] is uncomputed intervalCount
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci        if (runs[3] == SkRegion_kRunTypeSentinel) {  // should be first left...
290cb93a386Sopenharmony_ci            runs += 3;  // skip empty initial span
291cb93a386Sopenharmony_ci            runs[0] = runs[-2]; // set new top to prev bottom
292cb93a386Sopenharmony_ci            assert_sentinel(runs[1], false);    // bot: a sentinal would mean two in a row
293cb93a386Sopenharmony_ci            assert_sentinel(runs[2], false);    // intervalcount
294cb93a386Sopenharmony_ci            assert_sentinel(runs[3], false);    // left
295cb93a386Sopenharmony_ci            assert_sentinel(runs[4], false);    // right
296cb93a386Sopenharmony_ci        }
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_ci        assert_sentinel(stop[-1], true);
299cb93a386Sopenharmony_ci        assert_sentinel(stop[-2], true);
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci        // now check for a trailing empty span
302cb93a386Sopenharmony_ci        if (stop[-5] == SkRegion_kRunTypeSentinel) { // eek, stop[-4] was a bottom with no x-runs
303cb93a386Sopenharmony_ci            stop[-4] = SkRegion_kRunTypeSentinel;    // kill empty last span
304cb93a386Sopenharmony_ci            stop -= 3;
305cb93a386Sopenharmony_ci            assert_sentinel(stop[-1], true);    // last y-sentinel
306cb93a386Sopenharmony_ci            assert_sentinel(stop[-2], true);    // last x-sentinel
307cb93a386Sopenharmony_ci            assert_sentinel(stop[-3], false);   // last right
308cb93a386Sopenharmony_ci            assert_sentinel(stop[-4], false);   // last left
309cb93a386Sopenharmony_ci            assert_sentinel(stop[-5], false);   // last interval-count
310cb93a386Sopenharmony_ci            assert_sentinel(stop[-6], false);   // last bottom
311cb93a386Sopenharmony_ci        }
312cb93a386Sopenharmony_ci        count = (int)(stop - runs);
313cb93a386Sopenharmony_ci    }
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ci    SkASSERT(count >= kRectRegionRuns);
316cb93a386Sopenharmony_ci
317cb93a386Sopenharmony_ci    if (SkRegion::RunsAreARect(runs, count, &fBounds)) {
318cb93a386Sopenharmony_ci        return this->setRect(fBounds);
319cb93a386Sopenharmony_ci    }
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_ci    //  if we get here, we need to become a complex region
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci    if (!this->isComplex() || fRunHead->fRunCount != count) {
324cb93a386Sopenharmony_ci        this->freeRuns();
325cb93a386Sopenharmony_ci        this->allocateRuns(count);
326cb93a386Sopenharmony_ci        SkASSERT(this->isComplex());
327cb93a386Sopenharmony_ci    }
328cb93a386Sopenharmony_ci
329cb93a386Sopenharmony_ci    // must call this before we can write directly into runs()
330cb93a386Sopenharmony_ci    // in case we are sharing the buffer with another region (copy on write)
331cb93a386Sopenharmony_ci    fRunHead = fRunHead->ensureWritable();
332cb93a386Sopenharmony_ci    memcpy(fRunHead->writable_runs(), runs, count * sizeof(RunType));
333cb93a386Sopenharmony_ci    fRunHead->computeRunBounds(&fBounds);
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci    // Our computed bounds might be too large, so we have to check here.
336cb93a386Sopenharmony_ci    if (fBounds.isEmpty()) {
337cb93a386Sopenharmony_ci        return this->setEmpty();
338cb93a386Sopenharmony_ci    }
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
341cb93a386Sopenharmony_ci
342cb93a386Sopenharmony_ci    return true;
343cb93a386Sopenharmony_ci}
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_civoid SkRegion::BuildRectRuns(const SkIRect& bounds,
346cb93a386Sopenharmony_ci                             RunType runs[kRectRegionRuns]) {
347cb93a386Sopenharmony_ci    runs[0] = bounds.fTop;
348cb93a386Sopenharmony_ci    runs[1] = bounds.fBottom;
349cb93a386Sopenharmony_ci    runs[2] = 1;    // 1 interval for this scanline
350cb93a386Sopenharmony_ci    runs[3] = bounds.fLeft;
351cb93a386Sopenharmony_ci    runs[4] = bounds.fRight;
352cb93a386Sopenharmony_ci    runs[5] = SkRegion_kRunTypeSentinel;
353cb93a386Sopenharmony_ci    runs[6] = SkRegion_kRunTypeSentinel;
354cb93a386Sopenharmony_ci}
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_cibool SkRegion::contains(int32_t x, int32_t y) const {
357cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ci    if (!fBounds.contains(x, y)) {
360cb93a386Sopenharmony_ci        return false;
361cb93a386Sopenharmony_ci    }
362cb93a386Sopenharmony_ci    if (this->isRect()) {
363cb93a386Sopenharmony_ci        return true;
364cb93a386Sopenharmony_ci    }
365cb93a386Sopenharmony_ci    SkASSERT(this->isComplex());
366cb93a386Sopenharmony_ci
367cb93a386Sopenharmony_ci    const RunType* runs = fRunHead->findScanline(y);
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_ci    // Skip the Bottom and IntervalCount
370cb93a386Sopenharmony_ci    runs += 2;
371cb93a386Sopenharmony_ci
372cb93a386Sopenharmony_ci    // Just walk this scanline, checking each interval. The X-sentinel will
373cb93a386Sopenharmony_ci    // appear as a left-inteval (runs[0]) and should abort the search.
374cb93a386Sopenharmony_ci    //
375cb93a386Sopenharmony_ci    // We could do a bsearch, using interval-count (runs[1]), but need to time
376cb93a386Sopenharmony_ci    // when that would be worthwhile.
377cb93a386Sopenharmony_ci    //
378cb93a386Sopenharmony_ci    for (;;) {
379cb93a386Sopenharmony_ci        if (x < runs[0]) {
380cb93a386Sopenharmony_ci            break;
381cb93a386Sopenharmony_ci        }
382cb93a386Sopenharmony_ci        if (x < runs[1]) {
383cb93a386Sopenharmony_ci            return true;
384cb93a386Sopenharmony_ci        }
385cb93a386Sopenharmony_ci        runs += 2;
386cb93a386Sopenharmony_ci    }
387cb93a386Sopenharmony_ci    return false;
388cb93a386Sopenharmony_ci}
389cb93a386Sopenharmony_ci
390cb93a386Sopenharmony_cistatic SkRegionPriv::RunType scanline_bottom(const SkRegionPriv::RunType runs[]) {
391cb93a386Sopenharmony_ci    return runs[0];
392cb93a386Sopenharmony_ci}
393cb93a386Sopenharmony_ci
394cb93a386Sopenharmony_cistatic const SkRegionPriv::RunType* scanline_next(const SkRegionPriv::RunType runs[]) {
395cb93a386Sopenharmony_ci    // skip [B N [L R]... S]
396cb93a386Sopenharmony_ci    return runs + 2 + runs[1] * 2 + 1;
397cb93a386Sopenharmony_ci}
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_cistatic bool scanline_contains(const SkRegionPriv::RunType runs[],
400cb93a386Sopenharmony_ci                              SkRegionPriv::RunType L, SkRegionPriv::RunType R) {
401cb93a386Sopenharmony_ci    runs += 2;  // skip Bottom and IntervalCount
402cb93a386Sopenharmony_ci    for (;;) {
403cb93a386Sopenharmony_ci        if (L < runs[0]) {
404cb93a386Sopenharmony_ci            break;
405cb93a386Sopenharmony_ci        }
406cb93a386Sopenharmony_ci        if (R <= runs[1]) {
407cb93a386Sopenharmony_ci            return true;
408cb93a386Sopenharmony_ci        }
409cb93a386Sopenharmony_ci        runs += 2;
410cb93a386Sopenharmony_ci    }
411cb93a386Sopenharmony_ci    return false;
412cb93a386Sopenharmony_ci}
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_cibool SkRegion::contains(const SkIRect& r) const {
415cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci    if (!fBounds.contains(r)) {
418cb93a386Sopenharmony_ci        return false;
419cb93a386Sopenharmony_ci    }
420cb93a386Sopenharmony_ci    if (this->isRect()) {
421cb93a386Sopenharmony_ci        return true;
422cb93a386Sopenharmony_ci    }
423cb93a386Sopenharmony_ci    SkASSERT(this->isComplex());
424cb93a386Sopenharmony_ci
425cb93a386Sopenharmony_ci    const RunType* scanline = fRunHead->findScanline(r.fTop);
426cb93a386Sopenharmony_ci    for (;;) {
427cb93a386Sopenharmony_ci        if (!scanline_contains(scanline, r.fLeft, r.fRight)) {
428cb93a386Sopenharmony_ci            return false;
429cb93a386Sopenharmony_ci        }
430cb93a386Sopenharmony_ci        if (r.fBottom <= scanline_bottom(scanline)) {
431cb93a386Sopenharmony_ci            break;
432cb93a386Sopenharmony_ci        }
433cb93a386Sopenharmony_ci        scanline = scanline_next(scanline);
434cb93a386Sopenharmony_ci    }
435cb93a386Sopenharmony_ci    return true;
436cb93a386Sopenharmony_ci}
437cb93a386Sopenharmony_ci
438cb93a386Sopenharmony_cibool SkRegion::contains(const SkRegion& rgn) const {
439cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
440cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(rgn));
441cb93a386Sopenharmony_ci
442cb93a386Sopenharmony_ci    if (this->isEmpty() || rgn.isEmpty() || !fBounds.contains(rgn.fBounds)) {
443cb93a386Sopenharmony_ci        return false;
444cb93a386Sopenharmony_ci    }
445cb93a386Sopenharmony_ci    if (this->isRect()) {
446cb93a386Sopenharmony_ci        return true;
447cb93a386Sopenharmony_ci    }
448cb93a386Sopenharmony_ci    if (rgn.isRect()) {
449cb93a386Sopenharmony_ci        return this->contains(rgn.getBounds());
450cb93a386Sopenharmony_ci    }
451cb93a386Sopenharmony_ci
452cb93a386Sopenharmony_ci    /*
453cb93a386Sopenharmony_ci     *  A contains B is equivalent to
454cb93a386Sopenharmony_ci     *  B - A == 0
455cb93a386Sopenharmony_ci     */
456cb93a386Sopenharmony_ci    return !Oper(rgn, *this, kDifference_Op, nullptr);
457cb93a386Sopenharmony_ci}
458cb93a386Sopenharmony_ci
459cb93a386Sopenharmony_ciconst SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[],
460cb93a386Sopenharmony_ci                                           int* intervals) const {
461cb93a386Sopenharmony_ci    SkASSERT(tmpStorage && intervals);
462cb93a386Sopenharmony_ci    const RunType* runs = tmpStorage;
463cb93a386Sopenharmony_ci
464cb93a386Sopenharmony_ci    if (this->isEmpty()) {
465cb93a386Sopenharmony_ci        tmpStorage[0] = SkRegion_kRunTypeSentinel;
466cb93a386Sopenharmony_ci        *intervals = 0;
467cb93a386Sopenharmony_ci    } else if (this->isRect()) {
468cb93a386Sopenharmony_ci        BuildRectRuns(fBounds, tmpStorage);
469cb93a386Sopenharmony_ci        *intervals = 1;
470cb93a386Sopenharmony_ci    } else {
471cb93a386Sopenharmony_ci        runs = fRunHead->readonly_runs();
472cb93a386Sopenharmony_ci        *intervals = fRunHead->getIntervalCount();
473cb93a386Sopenharmony_ci    }
474cb93a386Sopenharmony_ci    return runs;
475cb93a386Sopenharmony_ci}
476cb93a386Sopenharmony_ci
477cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
478cb93a386Sopenharmony_ci
479cb93a386Sopenharmony_cistatic bool scanline_intersects(const SkRegionPriv::RunType runs[],
480cb93a386Sopenharmony_ci                                SkRegionPriv::RunType L, SkRegionPriv::RunType R) {
481cb93a386Sopenharmony_ci    runs += 2;  // skip Bottom and IntervalCount
482cb93a386Sopenharmony_ci    for (;;) {
483cb93a386Sopenharmony_ci        if (R <= runs[0]) {
484cb93a386Sopenharmony_ci            break;
485cb93a386Sopenharmony_ci        }
486cb93a386Sopenharmony_ci        if (L < runs[1]) {
487cb93a386Sopenharmony_ci            return true;
488cb93a386Sopenharmony_ci        }
489cb93a386Sopenharmony_ci        runs += 2;
490cb93a386Sopenharmony_ci    }
491cb93a386Sopenharmony_ci    return false;
492cb93a386Sopenharmony_ci}
493cb93a386Sopenharmony_ci
494cb93a386Sopenharmony_cibool SkRegion::intersects(const SkIRect& r) const {
495cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ci    if (this->isEmpty() || r.isEmpty()) {
498cb93a386Sopenharmony_ci        return false;
499cb93a386Sopenharmony_ci    }
500cb93a386Sopenharmony_ci
501cb93a386Sopenharmony_ci    SkIRect sect;
502cb93a386Sopenharmony_ci    if (!sect.intersect(fBounds, r)) {
503cb93a386Sopenharmony_ci        return false;
504cb93a386Sopenharmony_ci    }
505cb93a386Sopenharmony_ci    if (this->isRect()) {
506cb93a386Sopenharmony_ci        return true;
507cb93a386Sopenharmony_ci    }
508cb93a386Sopenharmony_ci    SkASSERT(this->isComplex());
509cb93a386Sopenharmony_ci
510cb93a386Sopenharmony_ci    const RunType* scanline = fRunHead->findScanline(sect.fTop);
511cb93a386Sopenharmony_ci    for (;;) {
512cb93a386Sopenharmony_ci        if (scanline_intersects(scanline, sect.fLeft, sect.fRight)) {
513cb93a386Sopenharmony_ci            return true;
514cb93a386Sopenharmony_ci        }
515cb93a386Sopenharmony_ci        if (sect.fBottom <= scanline_bottom(scanline)) {
516cb93a386Sopenharmony_ci            break;
517cb93a386Sopenharmony_ci        }
518cb93a386Sopenharmony_ci        scanline = scanline_next(scanline);
519cb93a386Sopenharmony_ci    }
520cb93a386Sopenharmony_ci    return false;
521cb93a386Sopenharmony_ci}
522cb93a386Sopenharmony_ci
523cb93a386Sopenharmony_cibool SkRegion::intersects(const SkRegion& rgn) const {
524cb93a386Sopenharmony_ci    if (this->isEmpty() || rgn.isEmpty()) {
525cb93a386Sopenharmony_ci        return false;
526cb93a386Sopenharmony_ci    }
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci    if (!SkIRect::Intersects(fBounds, rgn.fBounds)) {
529cb93a386Sopenharmony_ci        return false;
530cb93a386Sopenharmony_ci    }
531cb93a386Sopenharmony_ci
532cb93a386Sopenharmony_ci    bool weAreARect = this->isRect();
533cb93a386Sopenharmony_ci    bool theyAreARect = rgn.isRect();
534cb93a386Sopenharmony_ci
535cb93a386Sopenharmony_ci    if (weAreARect && theyAreARect) {
536cb93a386Sopenharmony_ci        return true;
537cb93a386Sopenharmony_ci    }
538cb93a386Sopenharmony_ci    if (weAreARect) {
539cb93a386Sopenharmony_ci        return rgn.intersects(this->getBounds());
540cb93a386Sopenharmony_ci    }
541cb93a386Sopenharmony_ci    if (theyAreARect) {
542cb93a386Sopenharmony_ci        return this->intersects(rgn.getBounds());
543cb93a386Sopenharmony_ci    }
544cb93a386Sopenharmony_ci
545cb93a386Sopenharmony_ci    // both of us are complex
546cb93a386Sopenharmony_ci    return Oper(*this, rgn, kIntersect_Op, nullptr);
547cb93a386Sopenharmony_ci}
548cb93a386Sopenharmony_ci
549cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
550cb93a386Sopenharmony_ci
551cb93a386Sopenharmony_cibool SkRegion::operator==(const SkRegion& b) const {
552cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
553cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(b));
554cb93a386Sopenharmony_ci
555cb93a386Sopenharmony_ci    if (this == &b) {
556cb93a386Sopenharmony_ci        return true;
557cb93a386Sopenharmony_ci    }
558cb93a386Sopenharmony_ci    if (fBounds != b.fBounds) {
559cb93a386Sopenharmony_ci        return false;
560cb93a386Sopenharmony_ci    }
561cb93a386Sopenharmony_ci
562cb93a386Sopenharmony_ci    const SkRegion::RunHead* ah = fRunHead;
563cb93a386Sopenharmony_ci    const SkRegion::RunHead* bh = b.fRunHead;
564cb93a386Sopenharmony_ci
565cb93a386Sopenharmony_ci    // this catches empties and rects being equal
566cb93a386Sopenharmony_ci    if (ah == bh) {
567cb93a386Sopenharmony_ci        return true;
568cb93a386Sopenharmony_ci    }
569cb93a386Sopenharmony_ci    // now we insist that both are complex (but different ptrs)
570cb93a386Sopenharmony_ci    if (!this->isComplex() || !b.isComplex()) {
571cb93a386Sopenharmony_ci        return false;
572cb93a386Sopenharmony_ci    }
573cb93a386Sopenharmony_ci    return  ah->fRunCount == bh->fRunCount &&
574cb93a386Sopenharmony_ci            !memcmp(ah->readonly_runs(), bh->readonly_runs(),
575cb93a386Sopenharmony_ci                    ah->fRunCount * sizeof(SkRegion::RunType));
576cb93a386Sopenharmony_ci}
577cb93a386Sopenharmony_ci
578cb93a386Sopenharmony_ci// Return a (new) offset such that when applied (+=) to min and max, we don't overflow/underflow
579cb93a386Sopenharmony_cistatic int32_t pin_offset_s32(int32_t min, int32_t max, int32_t offset) {
580cb93a386Sopenharmony_ci    SkASSERT(min <= max);
581cb93a386Sopenharmony_ci    const int32_t lo = -SK_MaxS32-1,
582cb93a386Sopenharmony_ci                  hi = +SK_MaxS32;
583cb93a386Sopenharmony_ci    if ((int64_t)min + offset < lo) { offset = lo - min; }
584cb93a386Sopenharmony_ci    if ((int64_t)max + offset > hi) { offset = hi - max; }
585cb93a386Sopenharmony_ci    return offset;
586cb93a386Sopenharmony_ci}
587cb93a386Sopenharmony_ci
588cb93a386Sopenharmony_civoid SkRegion::translate(int dx, int dy, SkRegion* dst) const {
589cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
590cb93a386Sopenharmony_ci
591cb93a386Sopenharmony_ci    if (nullptr == dst) {
592cb93a386Sopenharmony_ci        return;
593cb93a386Sopenharmony_ci    }
594cb93a386Sopenharmony_ci    if (this->isEmpty()) {
595cb93a386Sopenharmony_ci        dst->setEmpty();
596cb93a386Sopenharmony_ci        return;
597cb93a386Sopenharmony_ci    }
598cb93a386Sopenharmony_ci    // pin dx and dy so we don't overflow our existing bounds
599cb93a386Sopenharmony_ci    dx = pin_offset_s32(fBounds.fLeft, fBounds.fRight, dx);
600cb93a386Sopenharmony_ci    dy = pin_offset_s32(fBounds.fTop, fBounds.fBottom, dy);
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ci    if (this->isRect()) {
603cb93a386Sopenharmony_ci        dst->setRect(fBounds.makeOffset(dx, dy));
604cb93a386Sopenharmony_ci    } else {
605cb93a386Sopenharmony_ci        if (this == dst) {
606cb93a386Sopenharmony_ci            dst->fRunHead = dst->fRunHead->ensureWritable();
607cb93a386Sopenharmony_ci        } else {
608cb93a386Sopenharmony_ci            SkRegion    tmp;
609cb93a386Sopenharmony_ci            tmp.allocateRuns(*fRunHead);
610cb93a386Sopenharmony_ci            SkASSERT(tmp.isComplex());
611cb93a386Sopenharmony_ci            tmp.fBounds = fBounds;
612cb93a386Sopenharmony_ci            dst->swap(tmp);
613cb93a386Sopenharmony_ci        }
614cb93a386Sopenharmony_ci
615cb93a386Sopenharmony_ci        dst->fBounds.offset(dx, dy);
616cb93a386Sopenharmony_ci
617cb93a386Sopenharmony_ci        const RunType*  sruns = fRunHead->readonly_runs();
618cb93a386Sopenharmony_ci        RunType*        druns = dst->fRunHead->writable_runs();
619cb93a386Sopenharmony_ci
620cb93a386Sopenharmony_ci        *druns++ = (SkRegion::RunType)(*sruns++ + dy);    // top
621cb93a386Sopenharmony_ci        for (;;) {
622cb93a386Sopenharmony_ci            int bottom = *sruns++;
623cb93a386Sopenharmony_ci            if (bottom == SkRegion_kRunTypeSentinel) {
624cb93a386Sopenharmony_ci                break;
625cb93a386Sopenharmony_ci            }
626cb93a386Sopenharmony_ci            *druns++ = (SkRegion::RunType)(bottom + dy);  // bottom;
627cb93a386Sopenharmony_ci            *druns++ = *sruns++;    // copy intervalCount;
628cb93a386Sopenharmony_ci            for (;;) {
629cb93a386Sopenharmony_ci                int x = *sruns++;
630cb93a386Sopenharmony_ci                if (x == SkRegion_kRunTypeSentinel) {
631cb93a386Sopenharmony_ci                    break;
632cb93a386Sopenharmony_ci                }
633cb93a386Sopenharmony_ci                *druns++ = (SkRegion::RunType)(x + dx);
634cb93a386Sopenharmony_ci                *druns++ = (SkRegion::RunType)(*sruns++ + dx);
635cb93a386Sopenharmony_ci            }
636cb93a386Sopenharmony_ci            *druns++ = SkRegion_kRunTypeSentinel;    // x sentinel
637cb93a386Sopenharmony_ci        }
638cb93a386Sopenharmony_ci        *druns++ = SkRegion_kRunTypeSentinel;    // y sentinel
639cb93a386Sopenharmony_ci
640cb93a386Sopenharmony_ci        SkASSERT(sruns - fRunHead->readonly_runs() == fRunHead->fRunCount);
641cb93a386Sopenharmony_ci        SkASSERT(druns - dst->fRunHead->readonly_runs() == dst->fRunHead->fRunCount);
642cb93a386Sopenharmony_ci    }
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
645cb93a386Sopenharmony_ci}
646cb93a386Sopenharmony_ci
647cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
648cb93a386Sopenharmony_ci
649cb93a386Sopenharmony_cibool SkRegion::setRects(const SkIRect rects[], int count) {
650cb93a386Sopenharmony_ci    if (0 == count) {
651cb93a386Sopenharmony_ci        this->setEmpty();
652cb93a386Sopenharmony_ci    } else {
653cb93a386Sopenharmony_ci        this->setRect(rects[0]);
654cb93a386Sopenharmony_ci        for (int i = 1; i < count; i++) {
655cb93a386Sopenharmony_ci            this->op(rects[i], kUnion_Op);
656cb93a386Sopenharmony_ci        }
657cb93a386Sopenharmony_ci    }
658cb93a386Sopenharmony_ci    return !this->isEmpty();
659cb93a386Sopenharmony_ci}
660cb93a386Sopenharmony_ci
661cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
662cb93a386Sopenharmony_ci
663cb93a386Sopenharmony_ci#if defined _WIN32  // disable warning : local variable used without having been initialized
664cb93a386Sopenharmony_ci#pragma warning ( push )
665cb93a386Sopenharmony_ci#pragma warning ( disable : 4701 )
666cb93a386Sopenharmony_ci#endif
667cb93a386Sopenharmony_ci
668cb93a386Sopenharmony_ci#ifdef SK_DEBUG
669cb93a386Sopenharmony_cistatic void assert_valid_pair(int left, int rite)
670cb93a386Sopenharmony_ci{
671cb93a386Sopenharmony_ci    SkASSERT(left == SkRegion_kRunTypeSentinel || left < rite);
672cb93a386Sopenharmony_ci}
673cb93a386Sopenharmony_ci#else
674cb93a386Sopenharmony_ci    #define assert_valid_pair(left, rite)
675cb93a386Sopenharmony_ci#endif
676cb93a386Sopenharmony_ci
677cb93a386Sopenharmony_cistruct spanRec {
678cb93a386Sopenharmony_ci    const SkRegionPriv::RunType*    fA_runs;
679cb93a386Sopenharmony_ci    const SkRegionPriv::RunType*    fB_runs;
680cb93a386Sopenharmony_ci    int                         fA_left, fA_rite, fB_left, fB_rite;
681cb93a386Sopenharmony_ci    int                         fLeft, fRite, fInside;
682cb93a386Sopenharmony_ci
683cb93a386Sopenharmony_ci    void init(const SkRegionPriv::RunType a_runs[],
684cb93a386Sopenharmony_ci              const SkRegionPriv::RunType b_runs[]) {
685cb93a386Sopenharmony_ci        fA_left = *a_runs++;
686cb93a386Sopenharmony_ci        fA_rite = *a_runs++;
687cb93a386Sopenharmony_ci        fB_left = *b_runs++;
688cb93a386Sopenharmony_ci        fB_rite = *b_runs++;
689cb93a386Sopenharmony_ci
690cb93a386Sopenharmony_ci        fA_runs = a_runs;
691cb93a386Sopenharmony_ci        fB_runs = b_runs;
692cb93a386Sopenharmony_ci    }
693cb93a386Sopenharmony_ci
694cb93a386Sopenharmony_ci    bool done() const {
695cb93a386Sopenharmony_ci        SkASSERT(fA_left <= SkRegion_kRunTypeSentinel);
696cb93a386Sopenharmony_ci        SkASSERT(fB_left <= SkRegion_kRunTypeSentinel);
697cb93a386Sopenharmony_ci        return fA_left == SkRegion_kRunTypeSentinel &&
698cb93a386Sopenharmony_ci               fB_left == SkRegion_kRunTypeSentinel;
699cb93a386Sopenharmony_ci    }
700cb93a386Sopenharmony_ci
701cb93a386Sopenharmony_ci    void next() {
702cb93a386Sopenharmony_ci        assert_valid_pair(fA_left, fA_rite);
703cb93a386Sopenharmony_ci        assert_valid_pair(fB_left, fB_rite);
704cb93a386Sopenharmony_ci
705cb93a386Sopenharmony_ci        int     inside, left, rite SK_INIT_TO_AVOID_WARNING;
706cb93a386Sopenharmony_ci        bool    a_flush = false;
707cb93a386Sopenharmony_ci        bool    b_flush = false;
708cb93a386Sopenharmony_ci
709cb93a386Sopenharmony_ci        int a_left = fA_left;
710cb93a386Sopenharmony_ci        int a_rite = fA_rite;
711cb93a386Sopenharmony_ci        int b_left = fB_left;
712cb93a386Sopenharmony_ci        int b_rite = fB_rite;
713cb93a386Sopenharmony_ci
714cb93a386Sopenharmony_ci        if (a_left < b_left) {
715cb93a386Sopenharmony_ci            inside = 1;
716cb93a386Sopenharmony_ci            left = a_left;
717cb93a386Sopenharmony_ci            if (a_rite <= b_left) {   // [...] <...>
718cb93a386Sopenharmony_ci                rite = a_rite;
719cb93a386Sopenharmony_ci                a_flush = true;
720cb93a386Sopenharmony_ci            } else { // [...<..]...> or [...<...>...]
721cb93a386Sopenharmony_ci                rite = a_left = b_left;
722cb93a386Sopenharmony_ci            }
723cb93a386Sopenharmony_ci        } else if (b_left < a_left) {
724cb93a386Sopenharmony_ci            inside = 2;
725cb93a386Sopenharmony_ci            left = b_left;
726cb93a386Sopenharmony_ci            if (b_rite <= a_left) {   // [...] <...>
727cb93a386Sopenharmony_ci                rite = b_rite;
728cb93a386Sopenharmony_ci                b_flush = true;
729cb93a386Sopenharmony_ci            } else {    // [...<..]...> or [...<...>...]
730cb93a386Sopenharmony_ci                rite = b_left = a_left;
731cb93a386Sopenharmony_ci            }
732cb93a386Sopenharmony_ci        } else {    // a_left == b_left
733cb93a386Sopenharmony_ci            inside = 3;
734cb93a386Sopenharmony_ci            left = a_left;  // or b_left
735cb93a386Sopenharmony_ci            if (a_rite <= b_rite) {
736cb93a386Sopenharmony_ci                rite = b_left = a_rite;
737cb93a386Sopenharmony_ci                a_flush = true;
738cb93a386Sopenharmony_ci            }
739cb93a386Sopenharmony_ci            if (b_rite <= a_rite) {
740cb93a386Sopenharmony_ci                rite = a_left = b_rite;
741cb93a386Sopenharmony_ci                b_flush = true;
742cb93a386Sopenharmony_ci            }
743cb93a386Sopenharmony_ci        }
744cb93a386Sopenharmony_ci
745cb93a386Sopenharmony_ci        if (a_flush) {
746cb93a386Sopenharmony_ci            a_left = *fA_runs++;
747cb93a386Sopenharmony_ci            a_rite = *fA_runs++;
748cb93a386Sopenharmony_ci        }
749cb93a386Sopenharmony_ci        if (b_flush) {
750cb93a386Sopenharmony_ci            b_left = *fB_runs++;
751cb93a386Sopenharmony_ci            b_rite = *fB_runs++;
752cb93a386Sopenharmony_ci        }
753cb93a386Sopenharmony_ci
754cb93a386Sopenharmony_ci        SkASSERT(left <= rite);
755cb93a386Sopenharmony_ci
756cb93a386Sopenharmony_ci        // now update our state
757cb93a386Sopenharmony_ci        fA_left = a_left;
758cb93a386Sopenharmony_ci        fA_rite = a_rite;
759cb93a386Sopenharmony_ci        fB_left = b_left;
760cb93a386Sopenharmony_ci        fB_rite = b_rite;
761cb93a386Sopenharmony_ci
762cb93a386Sopenharmony_ci        fLeft = left;
763cb93a386Sopenharmony_ci        fRite = rite;
764cb93a386Sopenharmony_ci        fInside = inside;
765cb93a386Sopenharmony_ci    }
766cb93a386Sopenharmony_ci};
767cb93a386Sopenharmony_ci
768cb93a386Sopenharmony_cistatic int distance_to_sentinel(const SkRegionPriv::RunType* runs) {
769cb93a386Sopenharmony_ci    const SkRegionPriv::RunType* ptr = runs;
770cb93a386Sopenharmony_ci    while (*ptr != SkRegion_kRunTypeSentinel) { ptr += 2; }
771cb93a386Sopenharmony_ci    return ptr - runs;
772cb93a386Sopenharmony_ci}
773cb93a386Sopenharmony_ci
774cb93a386Sopenharmony_cistatic int operate_on_span(const SkRegionPriv::RunType a_runs[],
775cb93a386Sopenharmony_ci                           const SkRegionPriv::RunType b_runs[],
776cb93a386Sopenharmony_ci                           RunArray* array, int dstOffset,
777cb93a386Sopenharmony_ci                           int min, int max) {
778cb93a386Sopenharmony_ci    // This is a worst-case for this span plus two for TWO terminating sentinels.
779cb93a386Sopenharmony_ci    array->resizeToAtLeast(
780cb93a386Sopenharmony_ci            dstOffset + distance_to_sentinel(a_runs) + distance_to_sentinel(b_runs) + 2);
781cb93a386Sopenharmony_ci    SkRegionPriv::RunType* dst = &(*array)[dstOffset]; // get pointer AFTER resizing.
782cb93a386Sopenharmony_ci
783cb93a386Sopenharmony_ci    spanRec rec;
784cb93a386Sopenharmony_ci    bool    firstInterval = true;
785cb93a386Sopenharmony_ci
786cb93a386Sopenharmony_ci    rec.init(a_runs, b_runs);
787cb93a386Sopenharmony_ci
788cb93a386Sopenharmony_ci    while (!rec.done()) {
789cb93a386Sopenharmony_ci        rec.next();
790cb93a386Sopenharmony_ci
791cb93a386Sopenharmony_ci        int left = rec.fLeft;
792cb93a386Sopenharmony_ci        int rite = rec.fRite;
793cb93a386Sopenharmony_ci
794cb93a386Sopenharmony_ci        // add left,rite to our dst buffer (checking for coincidence
795cb93a386Sopenharmony_ci        if ((unsigned)(rec.fInside - min) <= (unsigned)(max - min) &&
796cb93a386Sopenharmony_ci                left < rite) {    // skip if equal
797cb93a386Sopenharmony_ci            if (firstInterval || *(dst - 1) < left) {
798cb93a386Sopenharmony_ci                *dst++ = (SkRegionPriv::RunType)(left);
799cb93a386Sopenharmony_ci                *dst++ = (SkRegionPriv::RunType)(rite);
800cb93a386Sopenharmony_ci                firstInterval = false;
801cb93a386Sopenharmony_ci            } else {
802cb93a386Sopenharmony_ci                // update the right edge
803cb93a386Sopenharmony_ci                *(dst - 1) = (SkRegionPriv::RunType)(rite);
804cb93a386Sopenharmony_ci            }
805cb93a386Sopenharmony_ci        }
806cb93a386Sopenharmony_ci    }
807cb93a386Sopenharmony_ci    SkASSERT(dst < &(*array)[array->count() - 1]);
808cb93a386Sopenharmony_ci    *dst++ = SkRegion_kRunTypeSentinel;
809cb93a386Sopenharmony_ci    return dst - &(*array)[0];
810cb93a386Sopenharmony_ci}
811cb93a386Sopenharmony_ci
812cb93a386Sopenharmony_ci#if defined _WIN32
813cb93a386Sopenharmony_ci#pragma warning ( pop )
814cb93a386Sopenharmony_ci#endif
815cb93a386Sopenharmony_ci
816cb93a386Sopenharmony_cistatic const struct {
817cb93a386Sopenharmony_ci    uint8_t fMin;
818cb93a386Sopenharmony_ci    uint8_t fMax;
819cb93a386Sopenharmony_ci} gOpMinMax[] = {
820cb93a386Sopenharmony_ci    { 1, 1 },   // Difference
821cb93a386Sopenharmony_ci    { 3, 3 },   // Intersection
822cb93a386Sopenharmony_ci    { 1, 3 },   // Union
823cb93a386Sopenharmony_ci    { 1, 2 }    // XOR
824cb93a386Sopenharmony_ci};
825cb93a386Sopenharmony_ci// need to ensure that the op enum lines up with our minmax array
826cb93a386Sopenharmony_cistatic_assert(0 == SkRegion::kDifference_Op, "");
827cb93a386Sopenharmony_cistatic_assert(1 == SkRegion::kIntersect_Op,  "");
828cb93a386Sopenharmony_cistatic_assert(2 == SkRegion::kUnion_Op,      "");
829cb93a386Sopenharmony_cistatic_assert(3 == SkRegion::kXOR_Op,        "");
830cb93a386Sopenharmony_ci
831cb93a386Sopenharmony_ciclass RgnOper {
832cb93a386Sopenharmony_cipublic:
833cb93a386Sopenharmony_ci    RgnOper(int top, RunArray* array, SkRegion::Op op)
834cb93a386Sopenharmony_ci        : fMin(gOpMinMax[op].fMin)
835cb93a386Sopenharmony_ci        , fMax(gOpMinMax[op].fMax)
836cb93a386Sopenharmony_ci        , fArray(array)
837cb93a386Sopenharmony_ci        , fTop((SkRegionPriv::RunType)top)  // just a first guess, we might update this
838cb93a386Sopenharmony_ci        { SkASSERT((unsigned)op <= 3); }
839cb93a386Sopenharmony_ci
840cb93a386Sopenharmony_ci    void addSpan(int bottom, const SkRegionPriv::RunType a_runs[],
841cb93a386Sopenharmony_ci                 const SkRegionPriv::RunType b_runs[]) {
842cb93a386Sopenharmony_ci        // skip X values and slots for the next Y+intervalCount
843cb93a386Sopenharmony_ci        int start = fPrevDst + fPrevLen + 2;
844cb93a386Sopenharmony_ci        // start points to beginning of dst interval
845cb93a386Sopenharmony_ci        int stop = operate_on_span(a_runs, b_runs, fArray, start, fMin, fMax);
846cb93a386Sopenharmony_ci        size_t len = SkToSizeT(stop - start);
847cb93a386Sopenharmony_ci        SkASSERT(len >= 1 && (len & 1) == 1);
848cb93a386Sopenharmony_ci        SkASSERT(SkRegion_kRunTypeSentinel == (*fArray)[stop - 1]);
849cb93a386Sopenharmony_ci
850cb93a386Sopenharmony_ci        // Assert memcmp won't exceed fArray->count().
851cb93a386Sopenharmony_ci        SkASSERT(fArray->count() >= SkToInt(start + len - 1));
852cb93a386Sopenharmony_ci        if (fPrevLen == len &&
853cb93a386Sopenharmony_ci            (1 == len || !memcmp(&(*fArray)[fPrevDst],
854cb93a386Sopenharmony_ci                                 &(*fArray)[start],
855cb93a386Sopenharmony_ci                                 (len - 1) * sizeof(SkRegionPriv::RunType)))) {
856cb93a386Sopenharmony_ci            // update Y value
857cb93a386Sopenharmony_ci            (*fArray)[fPrevDst - 2] = (SkRegionPriv::RunType)bottom;
858cb93a386Sopenharmony_ci        } else {    // accept the new span
859cb93a386Sopenharmony_ci            if (len == 1 && fPrevLen == 0) {
860cb93a386Sopenharmony_ci                fTop = (SkRegionPriv::RunType)bottom; // just update our bottom
861cb93a386Sopenharmony_ci            } else {
862cb93a386Sopenharmony_ci                (*fArray)[start - 2] = (SkRegionPriv::RunType)bottom;
863cb93a386Sopenharmony_ci                (*fArray)[start - 1] = SkToS32(len >> 1);
864cb93a386Sopenharmony_ci                fPrevDst = start;
865cb93a386Sopenharmony_ci                fPrevLen = len;
866cb93a386Sopenharmony_ci            }
867cb93a386Sopenharmony_ci        }
868cb93a386Sopenharmony_ci    }
869cb93a386Sopenharmony_ci
870cb93a386Sopenharmony_ci    int flush() {
871cb93a386Sopenharmony_ci        (*fArray)[fStartDst] = fTop;
872cb93a386Sopenharmony_ci        // Previously reserved enough for TWO sentinals.
873cb93a386Sopenharmony_ci        SkASSERT(fArray->count() > SkToInt(fPrevDst + fPrevLen));
874cb93a386Sopenharmony_ci        (*fArray)[fPrevDst + fPrevLen] = SkRegion_kRunTypeSentinel;
875cb93a386Sopenharmony_ci        return (int)(fPrevDst - fStartDst + fPrevLen + 1);
876cb93a386Sopenharmony_ci    }
877cb93a386Sopenharmony_ci
878cb93a386Sopenharmony_ci    bool isEmpty() const { return 0 == fPrevLen; }
879cb93a386Sopenharmony_ci
880cb93a386Sopenharmony_ci    uint8_t fMin, fMax;
881cb93a386Sopenharmony_ci
882cb93a386Sopenharmony_ciprivate:
883cb93a386Sopenharmony_ci    RunArray* fArray;
884cb93a386Sopenharmony_ci    int fStartDst = 0;
885cb93a386Sopenharmony_ci    int fPrevDst = 1;
886cb93a386Sopenharmony_ci    size_t fPrevLen = 0;  // will never match a length from operate_on_span
887cb93a386Sopenharmony_ci    SkRegionPriv::RunType fTop;
888cb93a386Sopenharmony_ci};
889cb93a386Sopenharmony_ci
890cb93a386Sopenharmony_ci// want a unique value to signal that we exited due to quickExit
891cb93a386Sopenharmony_ci#define QUICK_EXIT_TRUE_COUNT   (-1)
892cb93a386Sopenharmony_ci
893cb93a386Sopenharmony_cistatic int operate(const SkRegionPriv::RunType a_runs[],
894cb93a386Sopenharmony_ci                   const SkRegionPriv::RunType b_runs[],
895cb93a386Sopenharmony_ci                   RunArray* dst,
896cb93a386Sopenharmony_ci                   SkRegion::Op op,
897cb93a386Sopenharmony_ci                   bool quickExit) {
898cb93a386Sopenharmony_ci    const SkRegionPriv::RunType gEmptyScanline[] = {
899cb93a386Sopenharmony_ci        0,  // fake bottom value
900cb93a386Sopenharmony_ci        0,  // zero intervals
901cb93a386Sopenharmony_ci        SkRegion_kRunTypeSentinel,
902cb93a386Sopenharmony_ci        // just need a 2nd value, since spanRec.init() reads 2 values, even
903cb93a386Sopenharmony_ci        // though if the first value is the sentinel, it ignores the 2nd value.
904cb93a386Sopenharmony_ci        // w/o the 2nd value here, we might read uninitialized memory.
905cb93a386Sopenharmony_ci        // This happens when we are using gSentinel, which is pointing at
906cb93a386Sopenharmony_ci        // our sentinel value.
907cb93a386Sopenharmony_ci        0
908cb93a386Sopenharmony_ci    };
909cb93a386Sopenharmony_ci    const SkRegionPriv::RunType* const gSentinel = &gEmptyScanline[2];
910cb93a386Sopenharmony_ci
911cb93a386Sopenharmony_ci    int a_top = *a_runs++;
912cb93a386Sopenharmony_ci    int a_bot = *a_runs++;
913cb93a386Sopenharmony_ci    int b_top = *b_runs++;
914cb93a386Sopenharmony_ci    int b_bot = *b_runs++;
915cb93a386Sopenharmony_ci
916cb93a386Sopenharmony_ci    a_runs += 1;    // skip the intervalCount;
917cb93a386Sopenharmony_ci    b_runs += 1;    // skip the intervalCount;
918cb93a386Sopenharmony_ci
919cb93a386Sopenharmony_ci    // Now a_runs and b_runs to their intervals (or sentinel)
920cb93a386Sopenharmony_ci
921cb93a386Sopenharmony_ci    assert_sentinel(a_top, false);
922cb93a386Sopenharmony_ci    assert_sentinel(a_bot, false);
923cb93a386Sopenharmony_ci    assert_sentinel(b_top, false);
924cb93a386Sopenharmony_ci    assert_sentinel(b_bot, false);
925cb93a386Sopenharmony_ci
926cb93a386Sopenharmony_ci    RgnOper oper(std::min(a_top, b_top), dst, op);
927cb93a386Sopenharmony_ci
928cb93a386Sopenharmony_ci    int prevBot = SkRegion_kRunTypeSentinel; // so we fail the first test
929cb93a386Sopenharmony_ci
930cb93a386Sopenharmony_ci    while (a_bot < SkRegion_kRunTypeSentinel ||
931cb93a386Sopenharmony_ci           b_bot < SkRegion_kRunTypeSentinel) {
932cb93a386Sopenharmony_ci        int                         top, bot SK_INIT_TO_AVOID_WARNING;
933cb93a386Sopenharmony_ci        const SkRegionPriv::RunType*    run0 = gSentinel;
934cb93a386Sopenharmony_ci        const SkRegionPriv::RunType*    run1 = gSentinel;
935cb93a386Sopenharmony_ci        bool                        a_flush = false;
936cb93a386Sopenharmony_ci        bool                        b_flush = false;
937cb93a386Sopenharmony_ci
938cb93a386Sopenharmony_ci        if (a_top < b_top) {
939cb93a386Sopenharmony_ci            top = a_top;
940cb93a386Sopenharmony_ci            run0 = a_runs;
941cb93a386Sopenharmony_ci            if (a_bot <= b_top) {   // [...] <...>
942cb93a386Sopenharmony_ci                bot = a_bot;
943cb93a386Sopenharmony_ci                a_flush = true;
944cb93a386Sopenharmony_ci            } else {  // [...<..]...> or [...<...>...]
945cb93a386Sopenharmony_ci                bot = a_top = b_top;
946cb93a386Sopenharmony_ci            }
947cb93a386Sopenharmony_ci        } else if (b_top < a_top) {
948cb93a386Sopenharmony_ci            top = b_top;
949cb93a386Sopenharmony_ci            run1 = b_runs;
950cb93a386Sopenharmony_ci            if (b_bot <= a_top) {   // [...] <...>
951cb93a386Sopenharmony_ci                bot = b_bot;
952cb93a386Sopenharmony_ci                b_flush = true;
953cb93a386Sopenharmony_ci            } else {    // [...<..]...> or [...<...>...]
954cb93a386Sopenharmony_ci                bot = b_top = a_top;
955cb93a386Sopenharmony_ci            }
956cb93a386Sopenharmony_ci        } else {    // a_top == b_top
957cb93a386Sopenharmony_ci            top = a_top;    // or b_top
958cb93a386Sopenharmony_ci            run0 = a_runs;
959cb93a386Sopenharmony_ci            run1 = b_runs;
960cb93a386Sopenharmony_ci            if (a_bot <= b_bot) {
961cb93a386Sopenharmony_ci                bot = b_top = a_bot;
962cb93a386Sopenharmony_ci                a_flush = true;
963cb93a386Sopenharmony_ci            }
964cb93a386Sopenharmony_ci            if (b_bot <= a_bot) {
965cb93a386Sopenharmony_ci                bot = a_top = b_bot;
966cb93a386Sopenharmony_ci                b_flush = true;
967cb93a386Sopenharmony_ci            }
968cb93a386Sopenharmony_ci        }
969cb93a386Sopenharmony_ci
970cb93a386Sopenharmony_ci        if (top > prevBot) {
971cb93a386Sopenharmony_ci            oper.addSpan(top, gSentinel, gSentinel);
972cb93a386Sopenharmony_ci        }
973cb93a386Sopenharmony_ci        oper.addSpan(bot, run0, run1);
974cb93a386Sopenharmony_ci
975cb93a386Sopenharmony_ci        if (quickExit && !oper.isEmpty()) {
976cb93a386Sopenharmony_ci            return QUICK_EXIT_TRUE_COUNT;
977cb93a386Sopenharmony_ci        }
978cb93a386Sopenharmony_ci
979cb93a386Sopenharmony_ci        if (a_flush) {
980cb93a386Sopenharmony_ci            a_runs = skip_intervals(a_runs);
981cb93a386Sopenharmony_ci            a_top = a_bot;
982cb93a386Sopenharmony_ci            a_bot = *a_runs++;
983cb93a386Sopenharmony_ci            a_runs += 1;    // skip uninitialized intervalCount
984cb93a386Sopenharmony_ci            if (a_bot == SkRegion_kRunTypeSentinel) {
985cb93a386Sopenharmony_ci                a_top = a_bot;
986cb93a386Sopenharmony_ci            }
987cb93a386Sopenharmony_ci        }
988cb93a386Sopenharmony_ci        if (b_flush) {
989cb93a386Sopenharmony_ci            b_runs = skip_intervals(b_runs);
990cb93a386Sopenharmony_ci            b_top = b_bot;
991cb93a386Sopenharmony_ci            b_bot = *b_runs++;
992cb93a386Sopenharmony_ci            b_runs += 1;    // skip uninitialized intervalCount
993cb93a386Sopenharmony_ci            if (b_bot == SkRegion_kRunTypeSentinel) {
994cb93a386Sopenharmony_ci                b_top = b_bot;
995cb93a386Sopenharmony_ci            }
996cb93a386Sopenharmony_ci        }
997cb93a386Sopenharmony_ci
998cb93a386Sopenharmony_ci        prevBot = bot;
999cb93a386Sopenharmony_ci    }
1000cb93a386Sopenharmony_ci    return oper.flush();
1001cb93a386Sopenharmony_ci}
1002cb93a386Sopenharmony_ci
1003cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
1004cb93a386Sopenharmony_ci
1005cb93a386Sopenharmony_ci/*  Given count RunTypes in a complex region, return the worst case number of
1006cb93a386Sopenharmony_ci    logical intervals that represents (i.e. number of rects that would be
1007cb93a386Sopenharmony_ci    returned from the iterator).
1008cb93a386Sopenharmony_ci
1009cb93a386Sopenharmony_ci    We could just return count/2, since there must be at least 2 values per
1010cb93a386Sopenharmony_ci    interval, but we can first trim off the const overhead of the initial TOP
1011cb93a386Sopenharmony_ci    value, plus the final BOTTOM + 2 sentinels.
1012cb93a386Sopenharmony_ci */
1013cb93a386Sopenharmony_ci#if 0 // UNUSED
1014cb93a386Sopenharmony_cistatic int count_to_intervals(int count) {
1015cb93a386Sopenharmony_ci    SkASSERT(count >= 6);   // a single rect is 6 values
1016cb93a386Sopenharmony_ci    return (count - 4) >> 1;
1017cb93a386Sopenharmony_ci}
1018cb93a386Sopenharmony_ci#endif
1019cb93a386Sopenharmony_ci
1020cb93a386Sopenharmony_cistatic bool setEmptyCheck(SkRegion* result) {
1021cb93a386Sopenharmony_ci    return result ? result->setEmpty() : false;
1022cb93a386Sopenharmony_ci}
1023cb93a386Sopenharmony_ci
1024cb93a386Sopenharmony_cistatic bool setRectCheck(SkRegion* result, const SkIRect& rect) {
1025cb93a386Sopenharmony_ci    return result ? result->setRect(rect) : !rect.isEmpty();
1026cb93a386Sopenharmony_ci}
1027cb93a386Sopenharmony_ci
1028cb93a386Sopenharmony_cistatic bool setRegionCheck(SkRegion* result, const SkRegion& rgn) {
1029cb93a386Sopenharmony_ci    return result ? result->setRegion(rgn) : !rgn.isEmpty();
1030cb93a386Sopenharmony_ci}
1031cb93a386Sopenharmony_ci
1032cb93a386Sopenharmony_cibool SkRegion::Oper(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op,
1033cb93a386Sopenharmony_ci                    SkRegion* result) {
1034cb93a386Sopenharmony_ci    SkASSERT((unsigned)op < kOpCount);
1035cb93a386Sopenharmony_ci
1036cb93a386Sopenharmony_ci    if (kReplace_Op == op) {
1037cb93a386Sopenharmony_ci        return setRegionCheck(result, rgnbOrig);
1038cb93a386Sopenharmony_ci    }
1039cb93a386Sopenharmony_ci
1040cb93a386Sopenharmony_ci    // swith to using pointers, so we can swap them as needed
1041cb93a386Sopenharmony_ci    const SkRegion* rgna = &rgnaOrig;
1042cb93a386Sopenharmony_ci    const SkRegion* rgnb = &rgnbOrig;
1043cb93a386Sopenharmony_ci    // after this point, do not refer to rgnaOrig or rgnbOrig!!!
1044cb93a386Sopenharmony_ci
1045cb93a386Sopenharmony_ci    // collaps difference and reverse-difference into just difference
1046cb93a386Sopenharmony_ci    if (kReverseDifference_Op == op) {
1047cb93a386Sopenharmony_ci        using std::swap;
1048cb93a386Sopenharmony_ci        swap(rgna, rgnb);
1049cb93a386Sopenharmony_ci        op = kDifference_Op;
1050cb93a386Sopenharmony_ci    }
1051cb93a386Sopenharmony_ci
1052cb93a386Sopenharmony_ci    SkIRect bounds;
1053cb93a386Sopenharmony_ci    bool    a_empty = rgna->isEmpty();
1054cb93a386Sopenharmony_ci    bool    b_empty = rgnb->isEmpty();
1055cb93a386Sopenharmony_ci    bool    a_rect = rgna->isRect();
1056cb93a386Sopenharmony_ci    bool    b_rect = rgnb->isRect();
1057cb93a386Sopenharmony_ci
1058cb93a386Sopenharmony_ci    switch (op) {
1059cb93a386Sopenharmony_ci    case kDifference_Op:
1060cb93a386Sopenharmony_ci        if (a_empty) {
1061cb93a386Sopenharmony_ci            return setEmptyCheck(result);
1062cb93a386Sopenharmony_ci        }
1063cb93a386Sopenharmony_ci        if (b_empty || !SkIRect::Intersects(rgna->fBounds, rgnb->fBounds)) {
1064cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgna);
1065cb93a386Sopenharmony_ci        }
1066cb93a386Sopenharmony_ci        if (b_rect && rgnb->fBounds.containsNoEmptyCheck(rgna->fBounds)) {
1067cb93a386Sopenharmony_ci            return setEmptyCheck(result);
1068cb93a386Sopenharmony_ci        }
1069cb93a386Sopenharmony_ci        break;
1070cb93a386Sopenharmony_ci
1071cb93a386Sopenharmony_ci    case kIntersect_Op:
1072cb93a386Sopenharmony_ci        if ((a_empty | b_empty)
1073cb93a386Sopenharmony_ci                || !bounds.intersect(rgna->fBounds, rgnb->fBounds)) {
1074cb93a386Sopenharmony_ci            return setEmptyCheck(result);
1075cb93a386Sopenharmony_ci        }
1076cb93a386Sopenharmony_ci        if (a_rect & b_rect) {
1077cb93a386Sopenharmony_ci            return setRectCheck(result, bounds);
1078cb93a386Sopenharmony_ci        }
1079cb93a386Sopenharmony_ci        if (a_rect && rgna->fBounds.contains(rgnb->fBounds)) {
1080cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgnb);
1081cb93a386Sopenharmony_ci        }
1082cb93a386Sopenharmony_ci        if (b_rect && rgnb->fBounds.contains(rgna->fBounds)) {
1083cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgna);
1084cb93a386Sopenharmony_ci        }
1085cb93a386Sopenharmony_ci        break;
1086cb93a386Sopenharmony_ci
1087cb93a386Sopenharmony_ci    case kUnion_Op:
1088cb93a386Sopenharmony_ci        if (a_empty) {
1089cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgnb);
1090cb93a386Sopenharmony_ci        }
1091cb93a386Sopenharmony_ci        if (b_empty) {
1092cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgna);
1093cb93a386Sopenharmony_ci        }
1094cb93a386Sopenharmony_ci        if (a_rect && rgna->fBounds.contains(rgnb->fBounds)) {
1095cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgna);
1096cb93a386Sopenharmony_ci        }
1097cb93a386Sopenharmony_ci        if (b_rect && rgnb->fBounds.contains(rgna->fBounds)) {
1098cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgnb);
1099cb93a386Sopenharmony_ci        }
1100cb93a386Sopenharmony_ci        break;
1101cb93a386Sopenharmony_ci
1102cb93a386Sopenharmony_ci    case kXOR_Op:
1103cb93a386Sopenharmony_ci        if (a_empty) {
1104cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgnb);
1105cb93a386Sopenharmony_ci        }
1106cb93a386Sopenharmony_ci        if (b_empty) {
1107cb93a386Sopenharmony_ci            return setRegionCheck(result, *rgna);
1108cb93a386Sopenharmony_ci        }
1109cb93a386Sopenharmony_ci        break;
1110cb93a386Sopenharmony_ci    default:
1111cb93a386Sopenharmony_ci        SkDEBUGFAIL("unknown region op");
1112cb93a386Sopenharmony_ci        return false;
1113cb93a386Sopenharmony_ci    }
1114cb93a386Sopenharmony_ci
1115cb93a386Sopenharmony_ci    RunType tmpA[kRectRegionRuns];
1116cb93a386Sopenharmony_ci    RunType tmpB[kRectRegionRuns];
1117cb93a386Sopenharmony_ci
1118cb93a386Sopenharmony_ci    int a_intervals, b_intervals;
1119cb93a386Sopenharmony_ci    const RunType* a_runs = rgna->getRuns(tmpA, &a_intervals);
1120cb93a386Sopenharmony_ci    const RunType* b_runs = rgnb->getRuns(tmpB, &b_intervals);
1121cb93a386Sopenharmony_ci
1122cb93a386Sopenharmony_ci    RunArray array;
1123cb93a386Sopenharmony_ci    int count = operate(a_runs, b_runs, &array, op, nullptr == result);
1124cb93a386Sopenharmony_ci    SkASSERT(count <= array.count());
1125cb93a386Sopenharmony_ci
1126cb93a386Sopenharmony_ci    if (result) {
1127cb93a386Sopenharmony_ci        SkASSERT(count >= 0);
1128cb93a386Sopenharmony_ci        return result->setRuns(&array[0], count);
1129cb93a386Sopenharmony_ci    } else {
1130cb93a386Sopenharmony_ci        return (QUICK_EXIT_TRUE_COUNT == count) || !isRunCountEmpty(count);
1131cb93a386Sopenharmony_ci    }
1132cb93a386Sopenharmony_ci}
1133cb93a386Sopenharmony_ci
1134cb93a386Sopenharmony_cibool SkRegion::op(const SkRegion& rgna, const SkRegion& rgnb, Op op) {
1135cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(*this));
1136cb93a386Sopenharmony_ci    return SkRegion::Oper(rgna, rgnb, op, this);
1137cb93a386Sopenharmony_ci}
1138cb93a386Sopenharmony_ci
1139cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
1140cb93a386Sopenharmony_ci
1141cb93a386Sopenharmony_ci#include "src/core/SkBuffer.h"
1142cb93a386Sopenharmony_ci
1143cb93a386Sopenharmony_cisize_t SkRegion::writeToMemory(void* storage) const {
1144cb93a386Sopenharmony_ci    if (nullptr == storage) {
1145cb93a386Sopenharmony_ci        size_t size = sizeof(int32_t); // -1 (empty), 0 (rect), runCount
1146cb93a386Sopenharmony_ci        if (!this->isEmpty()) {
1147cb93a386Sopenharmony_ci            size += sizeof(fBounds);
1148cb93a386Sopenharmony_ci            if (this->isComplex()) {
1149cb93a386Sopenharmony_ci                size += 2 * sizeof(int32_t);    // ySpanCount + intervalCount
1150cb93a386Sopenharmony_ci                size += fRunHead->fRunCount * sizeof(RunType);
1151cb93a386Sopenharmony_ci            }
1152cb93a386Sopenharmony_ci        }
1153cb93a386Sopenharmony_ci        return size;
1154cb93a386Sopenharmony_ci    }
1155cb93a386Sopenharmony_ci
1156cb93a386Sopenharmony_ci    SkWBuffer   buffer(storage);
1157cb93a386Sopenharmony_ci
1158cb93a386Sopenharmony_ci    if (this->isEmpty()) {
1159cb93a386Sopenharmony_ci        buffer.write32(-1);
1160cb93a386Sopenharmony_ci    } else {
1161cb93a386Sopenharmony_ci        bool isRect = this->isRect();
1162cb93a386Sopenharmony_ci
1163cb93a386Sopenharmony_ci        buffer.write32(isRect ? 0 : fRunHead->fRunCount);
1164cb93a386Sopenharmony_ci        buffer.write(&fBounds, sizeof(fBounds));
1165cb93a386Sopenharmony_ci
1166cb93a386Sopenharmony_ci        if (!isRect) {
1167cb93a386Sopenharmony_ci            buffer.write32(fRunHead->getYSpanCount());
1168cb93a386Sopenharmony_ci            buffer.write32(fRunHead->getIntervalCount());
1169cb93a386Sopenharmony_ci            buffer.write(fRunHead->readonly_runs(),
1170cb93a386Sopenharmony_ci                         fRunHead->fRunCount * sizeof(RunType));
1171cb93a386Sopenharmony_ci        }
1172cb93a386Sopenharmony_ci    }
1173cb93a386Sopenharmony_ci    return buffer.pos();
1174cb93a386Sopenharmony_ci}
1175cb93a386Sopenharmony_ci
1176cb93a386Sopenharmony_cistatic bool validate_run_count(int ySpanCount, int intervalCount, int runCount) {
1177cb93a386Sopenharmony_ci    // return 2 + 3 * ySpanCount + 2 * intervalCount;
1178cb93a386Sopenharmony_ci    if (ySpanCount < 1 || intervalCount < 2) {
1179cb93a386Sopenharmony_ci        return false;
1180cb93a386Sopenharmony_ci    }
1181cb93a386Sopenharmony_ci    SkSafeMath safeMath;
1182cb93a386Sopenharmony_ci    int sum = 2;
1183cb93a386Sopenharmony_ci    sum = safeMath.addInt(sum, ySpanCount);
1184cb93a386Sopenharmony_ci    sum = safeMath.addInt(sum, ySpanCount);
1185cb93a386Sopenharmony_ci    sum = safeMath.addInt(sum, ySpanCount);
1186cb93a386Sopenharmony_ci    sum = safeMath.addInt(sum, intervalCount);
1187cb93a386Sopenharmony_ci    sum = safeMath.addInt(sum, intervalCount);
1188cb93a386Sopenharmony_ci    return safeMath && sum == runCount;
1189cb93a386Sopenharmony_ci}
1190cb93a386Sopenharmony_ci
1191cb93a386Sopenharmony_ci// Validate that a memory sequence is a valid region.
1192cb93a386Sopenharmony_ci// Try to check all possible errors.
1193cb93a386Sopenharmony_ci// never read beyond &runs[runCount-1].
1194cb93a386Sopenharmony_cistatic bool validate_run(const int32_t* runs,
1195cb93a386Sopenharmony_ci                         int runCount,
1196cb93a386Sopenharmony_ci                         const SkIRect& givenBounds,
1197cb93a386Sopenharmony_ci                         int32_t ySpanCount,
1198cb93a386Sopenharmony_ci                         int32_t intervalCount) {
1199cb93a386Sopenharmony_ci    // Region Layout:
1200cb93a386Sopenharmony_ci    //    Top ( Bottom Span_Interval_Count ( Left Right )* Sentinel )+ Sentinel
1201cb93a386Sopenharmony_ci    if (!validate_run_count(SkToInt(ySpanCount), SkToInt(intervalCount), runCount)) {
1202cb93a386Sopenharmony_ci        return false;
1203cb93a386Sopenharmony_ci    }
1204cb93a386Sopenharmony_ci    SkASSERT(runCount >= 7);  // 7==SkRegion::kRectRegionRuns
1205cb93a386Sopenharmony_ci    // quick safety check:
1206cb93a386Sopenharmony_ci    if (runs[runCount - 1] != SkRegion_kRunTypeSentinel ||
1207cb93a386Sopenharmony_ci        runs[runCount - 2] != SkRegion_kRunTypeSentinel) {
1208cb93a386Sopenharmony_ci        return false;
1209cb93a386Sopenharmony_ci    }
1210cb93a386Sopenharmony_ci    const int32_t* const end = runs + runCount;
1211cb93a386Sopenharmony_ci    SkIRect bounds = {0, 0, 0 ,0};  // calulated bounds
1212cb93a386Sopenharmony_ci    SkIRect rect = {0, 0, 0, 0};    // current rect
1213cb93a386Sopenharmony_ci    rect.fTop = *runs++;
1214cb93a386Sopenharmony_ci    if (rect.fTop == SkRegion_kRunTypeSentinel) {
1215cb93a386Sopenharmony_ci        return false;  // no rect can contain SkRegion_kRunTypeSentinel
1216cb93a386Sopenharmony_ci    }
1217cb93a386Sopenharmony_ci    if (rect.fTop != givenBounds.fTop) {
1218cb93a386Sopenharmony_ci        return false;  // Must not begin with empty span that does not contribute to bounds.
1219cb93a386Sopenharmony_ci    }
1220cb93a386Sopenharmony_ci    do {
1221cb93a386Sopenharmony_ci        --ySpanCount;
1222cb93a386Sopenharmony_ci        if (ySpanCount < 0) {
1223cb93a386Sopenharmony_ci            return false;  // too many yspans
1224cb93a386Sopenharmony_ci        }
1225cb93a386Sopenharmony_ci        rect.fBottom = *runs++;
1226cb93a386Sopenharmony_ci        if (rect.fBottom == SkRegion_kRunTypeSentinel) {
1227cb93a386Sopenharmony_ci            return false;
1228cb93a386Sopenharmony_ci        }
1229cb93a386Sopenharmony_ci        if (rect.fBottom > givenBounds.fBottom) {
1230cb93a386Sopenharmony_ci            return false;  // Must not end with empty span that does not contribute to bounds.
1231cb93a386Sopenharmony_ci        }
1232cb93a386Sopenharmony_ci        if (rect.fBottom <= rect.fTop) {
1233cb93a386Sopenharmony_ci            return false;  // y-intervals must be ordered; rects must be non-empty.
1234cb93a386Sopenharmony_ci        }
1235cb93a386Sopenharmony_ci
1236cb93a386Sopenharmony_ci        int32_t xIntervals = *runs++;
1237cb93a386Sopenharmony_ci        SkASSERT(runs < end);
1238cb93a386Sopenharmony_ci        if (xIntervals < 0 || xIntervals > intervalCount || runs + 1 + 2 * xIntervals > end) {
1239cb93a386Sopenharmony_ci            return false;
1240cb93a386Sopenharmony_ci        }
1241cb93a386Sopenharmony_ci        intervalCount -= xIntervals;
1242cb93a386Sopenharmony_ci        bool firstInterval = true;
1243cb93a386Sopenharmony_ci        int32_t lastRight = 0;  // check that x-intervals are distinct and ordered.
1244cb93a386Sopenharmony_ci        while (xIntervals-- > 0) {
1245cb93a386Sopenharmony_ci            rect.fLeft = *runs++;
1246cb93a386Sopenharmony_ci            rect.fRight = *runs++;
1247cb93a386Sopenharmony_ci            if (rect.fLeft == SkRegion_kRunTypeSentinel ||
1248cb93a386Sopenharmony_ci                rect.fRight == SkRegion_kRunTypeSentinel ||
1249cb93a386Sopenharmony_ci                rect.fLeft >= rect.fRight ||  // check non-empty rect
1250cb93a386Sopenharmony_ci                (!firstInterval && rect.fLeft <= lastRight)) {
1251cb93a386Sopenharmony_ci                return false;
1252cb93a386Sopenharmony_ci            }
1253cb93a386Sopenharmony_ci            lastRight = rect.fRight;
1254cb93a386Sopenharmony_ci            firstInterval = false;
1255cb93a386Sopenharmony_ci            bounds.join(rect);
1256cb93a386Sopenharmony_ci        }
1257cb93a386Sopenharmony_ci        if (*runs++ != SkRegion_kRunTypeSentinel) {
1258cb93a386Sopenharmony_ci            return false;  // required check sentinal.
1259cb93a386Sopenharmony_ci        }
1260cb93a386Sopenharmony_ci        rect.fTop = rect.fBottom;
1261cb93a386Sopenharmony_ci        SkASSERT(runs < end);
1262cb93a386Sopenharmony_ci    } while (*runs != SkRegion_kRunTypeSentinel);
1263cb93a386Sopenharmony_ci    ++runs;
1264cb93a386Sopenharmony_ci    if (ySpanCount != 0 || intervalCount != 0 || givenBounds != bounds) {
1265cb93a386Sopenharmony_ci        return false;
1266cb93a386Sopenharmony_ci    }
1267cb93a386Sopenharmony_ci    SkASSERT(runs == end);  // if ySpanCount && intervalCount are right, must be correct length.
1268cb93a386Sopenharmony_ci    return true;
1269cb93a386Sopenharmony_ci}
1270cb93a386Sopenharmony_cisize_t SkRegion::readFromMemory(const void* storage, size_t length) {
1271cb93a386Sopenharmony_ci    SkRBuffer   buffer(storage, length);
1272cb93a386Sopenharmony_ci    SkRegion    tmp;
1273cb93a386Sopenharmony_ci    int32_t     count;
1274cb93a386Sopenharmony_ci
1275cb93a386Sopenharmony_ci    // Serialized Region Format:
1276cb93a386Sopenharmony_ci    //    Empty:
1277cb93a386Sopenharmony_ci    //       -1
1278cb93a386Sopenharmony_ci    //    Simple Rect:
1279cb93a386Sopenharmony_ci    //       0  LEFT TOP RIGHT BOTTOM
1280cb93a386Sopenharmony_ci    //    Complex Region:
1281cb93a386Sopenharmony_ci    //       COUNT LEFT TOP RIGHT BOTTOM Y_SPAN_COUNT TOTAL_INTERVAL_COUNT [RUNS....]
1282cb93a386Sopenharmony_ci    if (!buffer.readS32(&count) || count < -1) {
1283cb93a386Sopenharmony_ci        return 0;
1284cb93a386Sopenharmony_ci    }
1285cb93a386Sopenharmony_ci    if (count >= 0) {
1286cb93a386Sopenharmony_ci        if (!buffer.read(&tmp.fBounds, sizeof(tmp.fBounds)) || tmp.fBounds.isEmpty()) {
1287cb93a386Sopenharmony_ci            return 0;  // Short buffer or bad bounds for non-empty region; report failure.
1288cb93a386Sopenharmony_ci        }
1289cb93a386Sopenharmony_ci        if (count == 0) {
1290cb93a386Sopenharmony_ci            tmp.fRunHead = SkRegion_gRectRunHeadPtr;
1291cb93a386Sopenharmony_ci        } else {
1292cb93a386Sopenharmony_ci            int32_t ySpanCount, intervalCount;
1293cb93a386Sopenharmony_ci            if (!buffer.readS32(&ySpanCount) ||
1294cb93a386Sopenharmony_ci                !buffer.readS32(&intervalCount) ||
1295cb93a386Sopenharmony_ci                buffer.available() < count * sizeof(int32_t)) {
1296cb93a386Sopenharmony_ci                return 0;
1297cb93a386Sopenharmony_ci            }
1298cb93a386Sopenharmony_ci            if (!validate_run((const int32_t*)((const char*)storage + buffer.pos()), count,
1299cb93a386Sopenharmony_ci                              tmp.fBounds, ySpanCount, intervalCount)) {
1300cb93a386Sopenharmony_ci                return 0;  // invalid runs, don't even allocate
1301cb93a386Sopenharmony_ci            }
1302cb93a386Sopenharmony_ci            tmp.allocateRuns(count, ySpanCount, intervalCount);
1303cb93a386Sopenharmony_ci            SkASSERT(tmp.isComplex());
1304cb93a386Sopenharmony_ci            SkAssertResult(buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(int32_t)));
1305cb93a386Sopenharmony_ci        }
1306cb93a386Sopenharmony_ci    }
1307cb93a386Sopenharmony_ci    SkASSERT(tmp.isValid());
1308cb93a386Sopenharmony_ci    SkASSERT(buffer.isValid());
1309cb93a386Sopenharmony_ci    this->swap(tmp);
1310cb93a386Sopenharmony_ci    return buffer.pos();
1311cb93a386Sopenharmony_ci}
1312cb93a386Sopenharmony_ci
1313cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
1314cb93a386Sopenharmony_ci
1315cb93a386Sopenharmony_cibool SkRegion::isValid() const {
1316cb93a386Sopenharmony_ci    if (this->isEmpty()) {
1317cb93a386Sopenharmony_ci        return fBounds == SkIRect{0, 0, 0, 0};
1318cb93a386Sopenharmony_ci    }
1319cb93a386Sopenharmony_ci    if (fBounds.isEmpty()) {
1320cb93a386Sopenharmony_ci        return false;
1321cb93a386Sopenharmony_ci    }
1322cb93a386Sopenharmony_ci    if (this->isRect()) {
1323cb93a386Sopenharmony_ci        return true;
1324cb93a386Sopenharmony_ci    }
1325cb93a386Sopenharmony_ci    return fRunHead && fRunHead->fRefCnt > 0 &&
1326cb93a386Sopenharmony_ci           validate_run(fRunHead->readonly_runs(), fRunHead->fRunCount, fBounds,
1327cb93a386Sopenharmony_ci                        fRunHead->getYSpanCount(), fRunHead->getIntervalCount());
1328cb93a386Sopenharmony_ci}
1329cb93a386Sopenharmony_ci
1330cb93a386Sopenharmony_civoid SkRegion::dump(std::string& desc, int depth) const {
1331cb93a386Sopenharmony_ci    std::string split(depth, '\t');
1332cb93a386Sopenharmony_ci    desc += split + "\n SkRegion:{ \n";
1333cb93a386Sopenharmony_ci    if (this->isEmpty()) {
1334cb93a386Sopenharmony_ci        desc += split + "  rgn: empty\n";
1335cb93a386Sopenharmony_ci    } else {
1336cb93a386Sopenharmony_ci        desc += split + "  rgn:\n";
1337cb93a386Sopenharmony_ci        desc += split + "\t fBounds.fLeft:" + std::to_string(fBounds.fLeft) + "\n";
1338cb93a386Sopenharmony_ci        desc += split + "\t fBounds.fTop:" + std::to_string(fBounds.fTop) + "\n";
1339cb93a386Sopenharmony_ci        desc += split + "\t fBounds.fRight:" + std::to_string(fBounds.fRight) + "\n";
1340cb93a386Sopenharmony_ci        desc += split + "\t fBounds.fBottom:" + std::to_string(fBounds.fBottom) + "\n";
1341cb93a386Sopenharmony_ci
1342cb93a386Sopenharmony_ci        if (this->isComplex()) {
1343cb93a386Sopenharmony_ci            desc += split + "\t fRunHead->readonly_runs():";
1344cb93a386Sopenharmony_ci            const RunType* runs = fRunHead->readonly_runs();
1345cb93a386Sopenharmony_ci            for (int i = 0; i < fRunHead->fRunCount; i++) {
1346cb93a386Sopenharmony_ci                desc += " " + std::to_string(runs[i]);
1347cb93a386Sopenharmony_ci            }
1348cb93a386Sopenharmony_ci            desc += "\n";
1349cb93a386Sopenharmony_ci        }
1350cb93a386Sopenharmony_ci    }
1351cb93a386Sopenharmony_ci    desc += split + "}\n";
1352cb93a386Sopenharmony_ci}
1353cb93a386Sopenharmony_ci
1354cb93a386Sopenharmony_ci#ifdef SK_DEBUG
1355cb93a386Sopenharmony_civoid SkRegionPriv::Validate(const SkRegion& rgn) { SkASSERT(rgn.isValid()); }
1356cb93a386Sopenharmony_ci
1357cb93a386Sopenharmony_civoid SkRegion::dump() const {
1358cb93a386Sopenharmony_ci    if (this->isEmpty()) {
1359cb93a386Sopenharmony_ci        SkDebugf("  rgn: empty\n");
1360cb93a386Sopenharmony_ci    } else {
1361cb93a386Sopenharmony_ci        SkDebugf("  rgn: [%d %d %d %d]", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
1362cb93a386Sopenharmony_ci        if (this->isComplex()) {
1363cb93a386Sopenharmony_ci            const RunType* runs = fRunHead->readonly_runs();
1364cb93a386Sopenharmony_ci            for (int i = 0; i < fRunHead->fRunCount; i++)
1365cb93a386Sopenharmony_ci                SkDebugf(" %d", runs[i]);
1366cb93a386Sopenharmony_ci        }
1367cb93a386Sopenharmony_ci        SkDebugf("\n");
1368cb93a386Sopenharmony_ci    }
1369cb93a386Sopenharmony_ci}
1370cb93a386Sopenharmony_ci
1371cb93a386Sopenharmony_ci#endif
1372cb93a386Sopenharmony_ci
1373cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
1374cb93a386Sopenharmony_ci
1375cb93a386Sopenharmony_ciSkRegion::Iterator::Iterator(const SkRegion& rgn) {
1376cb93a386Sopenharmony_ci    this->reset(rgn);
1377cb93a386Sopenharmony_ci}
1378cb93a386Sopenharmony_ci
1379cb93a386Sopenharmony_cibool SkRegion::Iterator::rewind() {
1380cb93a386Sopenharmony_ci    if (fRgn) {
1381cb93a386Sopenharmony_ci        this->reset(*fRgn);
1382cb93a386Sopenharmony_ci        return true;
1383cb93a386Sopenharmony_ci    }
1384cb93a386Sopenharmony_ci    return false;
1385cb93a386Sopenharmony_ci}
1386cb93a386Sopenharmony_ci
1387cb93a386Sopenharmony_civoid SkRegion::Iterator::reset(const SkRegion& rgn) {
1388cb93a386Sopenharmony_ci    fRgn = &rgn;
1389cb93a386Sopenharmony_ci    if (rgn.isEmpty()) {
1390cb93a386Sopenharmony_ci        fDone = true;
1391cb93a386Sopenharmony_ci    } else {
1392cb93a386Sopenharmony_ci        fDone = false;
1393cb93a386Sopenharmony_ci        if (rgn.isRect()) {
1394cb93a386Sopenharmony_ci            fRect = rgn.fBounds;
1395cb93a386Sopenharmony_ci            fRuns = nullptr;
1396cb93a386Sopenharmony_ci        } else {
1397cb93a386Sopenharmony_ci            fRuns = rgn.fRunHead->readonly_runs();
1398cb93a386Sopenharmony_ci            fRect.setLTRB(fRuns[3], fRuns[0], fRuns[4], fRuns[1]);
1399cb93a386Sopenharmony_ci            fRuns += 5;
1400cb93a386Sopenharmony_ci            // Now fRuns points to the 2nd interval (or x-sentinel)
1401cb93a386Sopenharmony_ci        }
1402cb93a386Sopenharmony_ci    }
1403cb93a386Sopenharmony_ci}
1404cb93a386Sopenharmony_ci
1405cb93a386Sopenharmony_civoid SkRegion::Iterator::next() {
1406cb93a386Sopenharmony_ci    if (fDone) {
1407cb93a386Sopenharmony_ci        return;
1408cb93a386Sopenharmony_ci    }
1409cb93a386Sopenharmony_ci
1410cb93a386Sopenharmony_ci    if (fRuns == nullptr) {   // rect case
1411cb93a386Sopenharmony_ci        fDone = true;
1412cb93a386Sopenharmony_ci        return;
1413cb93a386Sopenharmony_ci    }
1414cb93a386Sopenharmony_ci
1415cb93a386Sopenharmony_ci    const RunType* runs = fRuns;
1416cb93a386Sopenharmony_ci
1417cb93a386Sopenharmony_ci    if (runs[0] < SkRegion_kRunTypeSentinel) { // valid X value
1418cb93a386Sopenharmony_ci        fRect.fLeft = runs[0];
1419cb93a386Sopenharmony_ci        fRect.fRight = runs[1];
1420cb93a386Sopenharmony_ci        runs += 2;
1421cb93a386Sopenharmony_ci    } else {    // we're at the end of a line
1422cb93a386Sopenharmony_ci        runs += 1;
1423cb93a386Sopenharmony_ci        if (runs[0] < SkRegion_kRunTypeSentinel) { // valid Y value
1424cb93a386Sopenharmony_ci            int intervals = runs[1];
1425cb93a386Sopenharmony_ci            if (0 == intervals) {    // empty line
1426cb93a386Sopenharmony_ci                fRect.fTop = runs[0];
1427cb93a386Sopenharmony_ci                runs += 3;
1428cb93a386Sopenharmony_ci            } else {
1429cb93a386Sopenharmony_ci                fRect.fTop = fRect.fBottom;
1430cb93a386Sopenharmony_ci            }
1431cb93a386Sopenharmony_ci
1432cb93a386Sopenharmony_ci            fRect.fBottom = runs[0];
1433cb93a386Sopenharmony_ci            assert_sentinel(runs[2], false);
1434cb93a386Sopenharmony_ci            assert_sentinel(runs[3], false);
1435cb93a386Sopenharmony_ci            fRect.fLeft = runs[2];
1436cb93a386Sopenharmony_ci            fRect.fRight = runs[3];
1437cb93a386Sopenharmony_ci            runs += 4;
1438cb93a386Sopenharmony_ci        } else {    // end of rgn
1439cb93a386Sopenharmony_ci            fDone = true;
1440cb93a386Sopenharmony_ci        }
1441cb93a386Sopenharmony_ci    }
1442cb93a386Sopenharmony_ci    fRuns = runs;
1443cb93a386Sopenharmony_ci}
1444cb93a386Sopenharmony_ci
1445cb93a386Sopenharmony_ciSkRegion::Cliperator::Cliperator(const SkRegion& rgn, const SkIRect& clip)
1446cb93a386Sopenharmony_ci        : fIter(rgn), fClip(clip), fDone(true) {
1447cb93a386Sopenharmony_ci    const SkIRect& r = fIter.rect();
1448cb93a386Sopenharmony_ci
1449cb93a386Sopenharmony_ci    while (!fIter.done()) {
1450cb93a386Sopenharmony_ci        if (r.fTop >= clip.fBottom) {
1451cb93a386Sopenharmony_ci            break;
1452cb93a386Sopenharmony_ci        }
1453cb93a386Sopenharmony_ci        if (fRect.intersect(clip, r)) {
1454cb93a386Sopenharmony_ci            fDone = false;
1455cb93a386Sopenharmony_ci            break;
1456cb93a386Sopenharmony_ci        }
1457cb93a386Sopenharmony_ci        fIter.next();
1458cb93a386Sopenharmony_ci    }
1459cb93a386Sopenharmony_ci}
1460cb93a386Sopenharmony_ci
1461cb93a386Sopenharmony_civoid SkRegion::Cliperator::next() {
1462cb93a386Sopenharmony_ci    if (fDone) {
1463cb93a386Sopenharmony_ci        return;
1464cb93a386Sopenharmony_ci    }
1465cb93a386Sopenharmony_ci
1466cb93a386Sopenharmony_ci    const SkIRect& r = fIter.rect();
1467cb93a386Sopenharmony_ci
1468cb93a386Sopenharmony_ci    fDone = true;
1469cb93a386Sopenharmony_ci    fIter.next();
1470cb93a386Sopenharmony_ci    while (!fIter.done()) {
1471cb93a386Sopenharmony_ci        if (r.fTop >= fClip.fBottom) {
1472cb93a386Sopenharmony_ci            break;
1473cb93a386Sopenharmony_ci        }
1474cb93a386Sopenharmony_ci        if (fRect.intersect(fClip, r)) {
1475cb93a386Sopenharmony_ci            fDone = false;
1476cb93a386Sopenharmony_ci            break;
1477cb93a386Sopenharmony_ci        }
1478cb93a386Sopenharmony_ci        fIter.next();
1479cb93a386Sopenharmony_ci    }
1480cb93a386Sopenharmony_ci}
1481cb93a386Sopenharmony_ci
1482cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
1483cb93a386Sopenharmony_ci
1484cb93a386Sopenharmony_ciSkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left,
1485cb93a386Sopenharmony_ci                                 int right) {
1486cb93a386Sopenharmony_ci    SkDEBUGCODE(SkRegionPriv::Validate(rgn));
1487cb93a386Sopenharmony_ci
1488cb93a386Sopenharmony_ci    const SkIRect& r = rgn.getBounds();
1489cb93a386Sopenharmony_ci
1490cb93a386Sopenharmony_ci    fDone = true;
1491cb93a386Sopenharmony_ci    if (!rgn.isEmpty() && y >= r.fTop && y < r.fBottom &&
1492cb93a386Sopenharmony_ci            right > r.fLeft && left < r.fRight) {
1493cb93a386Sopenharmony_ci        if (rgn.isRect()) {
1494cb93a386Sopenharmony_ci            if (left < r.fLeft) {
1495cb93a386Sopenharmony_ci                left = r.fLeft;
1496cb93a386Sopenharmony_ci            }
1497cb93a386Sopenharmony_ci            if (right > r.fRight) {
1498cb93a386Sopenharmony_ci                right = r.fRight;
1499cb93a386Sopenharmony_ci            }
1500cb93a386Sopenharmony_ci            fLeft = left;
1501cb93a386Sopenharmony_ci            fRight = right;
1502cb93a386Sopenharmony_ci            fRuns = nullptr;    // means we're a rect, not a rgn
1503cb93a386Sopenharmony_ci            fDone = false;
1504cb93a386Sopenharmony_ci        } else {
1505cb93a386Sopenharmony_ci            const SkRegion::RunType* runs = rgn.fRunHead->findScanline(y);
1506cb93a386Sopenharmony_ci            runs += 2;  // skip Bottom and IntervalCount
1507cb93a386Sopenharmony_ci            for (;;) {
1508cb93a386Sopenharmony_ci                // runs[0..1] is to the right of the span, so we're done
1509cb93a386Sopenharmony_ci                if (runs[0] >= right) {
1510cb93a386Sopenharmony_ci                    break;
1511cb93a386Sopenharmony_ci                }
1512cb93a386Sopenharmony_ci                // runs[0..1] is to the left of the span, so continue
1513cb93a386Sopenharmony_ci                if (runs[1] <= left) {
1514cb93a386Sopenharmony_ci                    runs += 2;
1515cb93a386Sopenharmony_ci                    continue;
1516cb93a386Sopenharmony_ci                }
1517cb93a386Sopenharmony_ci                // runs[0..1] intersects the span
1518cb93a386Sopenharmony_ci                fRuns = runs;
1519cb93a386Sopenharmony_ci                fLeft = left;
1520cb93a386Sopenharmony_ci                fRight = right;
1521cb93a386Sopenharmony_ci                fDone = false;
1522cb93a386Sopenharmony_ci                break;
1523cb93a386Sopenharmony_ci            }
1524cb93a386Sopenharmony_ci        }
1525cb93a386Sopenharmony_ci    }
1526cb93a386Sopenharmony_ci}
1527cb93a386Sopenharmony_ci
1528cb93a386Sopenharmony_cibool SkRegion::Spanerator::next(int* left, int* right) {
1529cb93a386Sopenharmony_ci    if (fDone) {
1530cb93a386Sopenharmony_ci        return false;
1531cb93a386Sopenharmony_ci    }
1532cb93a386Sopenharmony_ci
1533cb93a386Sopenharmony_ci    if (fRuns == nullptr) {   // we're a rect
1534cb93a386Sopenharmony_ci        fDone = true;   // ok, now we're done
1535cb93a386Sopenharmony_ci        if (left) {
1536cb93a386Sopenharmony_ci            *left = fLeft;
1537cb93a386Sopenharmony_ci        }
1538cb93a386Sopenharmony_ci        if (right) {
1539cb93a386Sopenharmony_ci            *right = fRight;
1540cb93a386Sopenharmony_ci        }
1541cb93a386Sopenharmony_ci        return true;    // this interval is legal
1542cb93a386Sopenharmony_ci    }
1543cb93a386Sopenharmony_ci
1544cb93a386Sopenharmony_ci    const SkRegion::RunType* runs = fRuns;
1545cb93a386Sopenharmony_ci
1546cb93a386Sopenharmony_ci    if (runs[0] >= fRight) {
1547cb93a386Sopenharmony_ci        fDone = true;
1548cb93a386Sopenharmony_ci        return false;
1549cb93a386Sopenharmony_ci    }
1550cb93a386Sopenharmony_ci
1551cb93a386Sopenharmony_ci    SkASSERT(runs[1] > fLeft);
1552cb93a386Sopenharmony_ci
1553cb93a386Sopenharmony_ci    if (left) {
1554cb93a386Sopenharmony_ci        *left = std::max(fLeft, runs[0]);
1555cb93a386Sopenharmony_ci    }
1556cb93a386Sopenharmony_ci    if (right) {
1557cb93a386Sopenharmony_ci        *right = std::min(fRight, runs[1]);
1558cb93a386Sopenharmony_ci    }
1559cb93a386Sopenharmony_ci    fRuns = runs + 2;
1560cb93a386Sopenharmony_ci    return true;
1561cb93a386Sopenharmony_ci}
1562cb93a386Sopenharmony_ci
1563cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
1564cb93a386Sopenharmony_ci
1565cb93a386Sopenharmony_cistatic void visit_pairs(int pairCount, int y, const int32_t pairs[],
1566cb93a386Sopenharmony_ci                        const std::function<void(const SkIRect&)>& visitor) {
1567cb93a386Sopenharmony_ci    for (int i = 0; i < pairCount; ++i) {
1568cb93a386Sopenharmony_ci        visitor({ pairs[0], y, pairs[1], y + 1 });
1569cb93a386Sopenharmony_ci        pairs += 2;
1570cb93a386Sopenharmony_ci    }
1571cb93a386Sopenharmony_ci}
1572cb93a386Sopenharmony_ci
1573cb93a386Sopenharmony_civoid SkRegionPriv::VisitSpans(const SkRegion& rgn,
1574cb93a386Sopenharmony_ci                              const std::function<void(const SkIRect&)>& visitor) {
1575cb93a386Sopenharmony_ci    if (rgn.isEmpty()) {
1576cb93a386Sopenharmony_ci        return;
1577cb93a386Sopenharmony_ci    }
1578cb93a386Sopenharmony_ci    if (rgn.isRect()) {
1579cb93a386Sopenharmony_ci        visitor(rgn.getBounds());
1580cb93a386Sopenharmony_ci    } else {
1581cb93a386Sopenharmony_ci        const int32_t* p = rgn.fRunHead->readonly_runs();
1582cb93a386Sopenharmony_ci        int32_t top = *p++;
1583cb93a386Sopenharmony_ci        int32_t bot = *p++;
1584cb93a386Sopenharmony_ci        do {
1585cb93a386Sopenharmony_ci            int pairCount = *p++;
1586cb93a386Sopenharmony_ci            if (pairCount == 1) {
1587cb93a386Sopenharmony_ci                visitor({ p[0], top, p[1], bot });
1588cb93a386Sopenharmony_ci                p += 2;
1589cb93a386Sopenharmony_ci            } else if (pairCount > 1) {
1590cb93a386Sopenharmony_ci                // we have to loop repeated in Y, sending each interval in Y -> X order
1591cb93a386Sopenharmony_ci                for (int y = top; y < bot; ++y) {
1592cb93a386Sopenharmony_ci                    visit_pairs(pairCount, y, p, visitor);
1593cb93a386Sopenharmony_ci                }
1594cb93a386Sopenharmony_ci                p += pairCount * 2;
1595cb93a386Sopenharmony_ci            }
1596cb93a386Sopenharmony_ci            assert_sentinel(*p, true);
1597cb93a386Sopenharmony_ci            p += 1; // skip sentinel
1598cb93a386Sopenharmony_ci
1599cb93a386Sopenharmony_ci            // read next bottom or sentinel
1600cb93a386Sopenharmony_ci            top = bot;
1601cb93a386Sopenharmony_ci            bot = *p++;
1602cb93a386Sopenharmony_ci        } while (!SkRegionValueIsSentinel(bot));
1603cb93a386Sopenharmony_ci    }
1604cb93a386Sopenharmony_ci}
1605cb93a386Sopenharmony_ci
1606