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