Coverage Report

Created: 2021-08-22 09:07

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