Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Macros | Functions | Variables
SkRegion.cpp File Reference
#include "include/core/SkRegion.h"
#include "include/private/base/SkMacros.h"
#include "include/private/base/SkMalloc.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkTemplates.h"
#include "include/private/base/SkTo.h"
#include "src/base/SkBuffer.h"
#include "src/base/SkSafeMath.h"
#include "src/core/SkRegionPriv.h"
#include <algorithm>
#include <atomic>
#include <cstring>
#include <functional>

Go to the source code of this file.

Classes

class  RunArray
 
struct  spanRec
 
class  RgnOper
 

Macros

#define SkRegion_gEmptyRunHeadPtr   ((SkRegionPriv::RunHead*)-1)
 
#define SkRegion_gRectRunHeadPtr   nullptr
 
#define assert_valid_pair(left, rite)
 
#define QUICK_EXIT_TRUE_COUNT   (-1)
 

Functions

static SkRegionPriv::RunTypeskip_intervals (const SkRegionPriv::RunType runs[])
 
static bool isRunCountEmpty (int count)
 
static SkRegionPriv::RunType scanline_bottom (const SkRegionPriv::RunType runs[])
 
static const SkRegionPriv::RunTypescanline_next (const SkRegionPriv::RunType runs[])
 
static bool scanline_contains (const SkRegionPriv::RunType runs[], SkRegionPriv::RunType L, SkRegionPriv::RunType R)
 
static bool scanline_intersects (const SkRegionPriv::RunType runs[], SkRegionPriv::RunType L, SkRegionPriv::RunType R)
 
static int32_t pin_offset_s32 (int32_t min, int32_t max, int32_t offset)
 
static int distance_to_sentinel (const SkRegionPriv::RunType *runs)
 
static int operate_on_span (const SkRegionPriv::RunType a_runs[], const SkRegionPriv::RunType b_runs[], RunArray *array, int dstOffset, int min, int max)
 
static int operate (const SkRegionPriv::RunType a_runs[], const SkRegionPriv::RunType b_runs[], RunArray *dst, SkRegion::Op op, bool quickExit)
 
static bool setEmptyCheck (SkRegion *result)
 
static bool setRectCheck (SkRegion *result, const SkIRect &rect)
 
static bool setRegionCheck (SkRegion *result, const SkRegion &rgn)
 
static bool validate_run_count (int ySpanCount, int intervalCount, int runCount)
 
static bool validate_run (const int32_t *runs, int runCount, const SkIRect &givenBounds, int32_t ySpanCount, int32_t intervalCount)
 
static void visit_pairs (int pairCount, int y, const int32_t pairs[], const std::function< void(const SkIRect &)> &visitor)
 

Variables

constexpr int kRunArrayStackCount = 256
 
struct { 
 
   uint8_t   fMin 
 
   uint8_t   fMax 
 
gOpMinMax [] 
 

Macro Definition Documentation

◆ assert_valid_pair

#define assert_valid_pair (   left,
  rite 
)

Definition at line 682 of file SkRegion.cpp.

◆ QUICK_EXIT_TRUE_COUNT

#define QUICK_EXIT_TRUE_COUNT   (-1)

Definition at line 899 of file SkRegion.cpp.

◆ SkRegion_gEmptyRunHeadPtr

#define SkRegion_gEmptyRunHeadPtr   ((SkRegionPriv::RunHead*)-1)

Definition at line 38 of file SkRegion.cpp.

◆ SkRegion_gRectRunHeadPtr

#define SkRegion_gRectRunHeadPtr   nullptr

Definition at line 39 of file SkRegion.cpp.

Function Documentation

◆ distance_to_sentinel()

static int distance_to_sentinel ( const SkRegionPriv::RunType runs)
static

Definition at line 776 of file SkRegion.cpp.

776 {
777 const SkRegionPriv::RunType* ptr = runs;
778 while (*ptr != SkRegion_kRunTypeSentinel) { ptr += 2; }
779 return ptr - runs;
780}
static constexpr int SkRegion_kRunTypeSentinel
SkRegion::RunType RunType

◆ isRunCountEmpty()

static bool isRunCountEmpty ( int  count)
static

Definition at line 275 of file SkRegion.cpp.

275 {
276 return count <= 2;
277}
int count

◆ operate()

static int operate ( const SkRegionPriv::RunType  a_runs[],
const SkRegionPriv::RunType  b_runs[],
RunArray dst,
SkRegion::Op  op,
bool  quickExit 
)
static

Definition at line 901 of file SkRegion.cpp.

905 {
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}
#define SK_INIT_TO_AVOID_WARNING
Definition SkMacros.h:58
#define assert_sentinel(value, isSentinel)
#define QUICK_EXIT_TRUE_COUNT
Definition SkRegion.cpp:899
static SkRegionPriv::RunType * skip_intervals(const SkRegionPriv::RunType runs[])
Definition SkRegion.cpp:84

◆ operate_on_span()

static int operate_on_span ( const SkRegionPriv::RunType  a_runs[],
const SkRegionPriv::RunType  b_runs[],
RunArray array,
int  dstOffset,
int  min,
int  max 
)
static

Definition at line 782 of file SkRegion.cpp.

785 {
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}
#define SkASSERT(cond)
Definition SkAssert.h:116
static bool left(const SkPoint &p0, const SkPoint &p1)
static int distance_to_sentinel(const SkRegionPriv::RunType *runs)
Definition SkRegion.cpp:776
void resizeToAtLeast(int count)
Definition SkRegion.cpp:61
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
dst
Definition cp.py:12
int fRite
Definition SkRegion.cpp:689
bool done() const
Definition SkRegion.cpp:702
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 fLeft
Definition SkRegion.cpp:689

◆ pin_offset_s32()

static int32_t pin_offset_s32 ( int32_t  min,
int32_t  max,
int32_t  offset 
)
static

Definition at line 587 of file SkRegion.cpp.

587 {
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}
static constexpr int32_t SK_MaxS32
Definition SkMath.h:21
Point offset

◆ scanline_bottom()

static SkRegionPriv::RunType scanline_bottom ( const SkRegionPriv::RunType  runs[])
static

Definition at line 398 of file SkRegion.cpp.

398 {
399 return runs[0];
400}

◆ scanline_contains()

static bool scanline_contains ( const SkRegionPriv::RunType  runs[],
SkRegionPriv::RunType  L,
SkRegionPriv::RunType  R 
)
static

Definition at line 407 of file SkRegion.cpp.

408 {
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}
#define R(r)

◆ scanline_intersects()

static bool scanline_intersects ( const SkRegionPriv::RunType  runs[],
SkRegionPriv::RunType  L,
SkRegionPriv::RunType  R 
)
static

Definition at line 487 of file SkRegion.cpp.

488 {
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}

◆ scanline_next()

static const SkRegionPriv::RunType * scanline_next ( const SkRegionPriv::RunType  runs[])
static

Definition at line 402 of file SkRegion.cpp.

402 {
403 // skip [B N [L R]... S]
404 return runs + 2 + runs[1] * 2 + 1;
405}

◆ setEmptyCheck()

static bool setEmptyCheck ( SkRegion result)
static

Definition at line 1028 of file SkRegion.cpp.

1028 {
1029 return result ? result->setEmpty() : false;
1030}
GAsyncResult * result

◆ setRectCheck()

static bool setRectCheck ( SkRegion result,
const SkIRect rect 
)
static

Definition at line 1032 of file SkRegion.cpp.

1032 {
1033 return result ? result->setRect(rect) : !rect.isEmpty();
1034}
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350

◆ setRegionCheck()

static bool setRegionCheck ( SkRegion result,
const SkRegion rgn 
)
static

Definition at line 1036 of file SkRegion.cpp.

1036 {
1037 return result ? result->setRegion(rgn) : !rgn.isEmpty();
1038}
bool isEmpty() const
Definition SkRegion.h:146

◆ skip_intervals()

static SkRegionPriv::RunType * skip_intervals ( const SkRegionPriv::RunType  runs[])
static

Definition at line 84 of file SkRegion.cpp.

84 {
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}

◆ validate_run()

static bool validate_run ( const int32_t *  runs,
int  runCount,
const SkIRect givenBounds,
int32_t  ySpanCount,
int32_t  intervalCount 
)
static

Definition at line 1200 of file SkRegion.cpp.

1204 {
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}
static bool validate_run_count(int ySpanCount, int intervalCount, int runCount)
constexpr int SkToInt(S x)
Definition SkTo.h:29
glong glong end
Optional< SkRect > bounds
Definition SkRecords.h:189
int32_t fBottom
larger y-axis bounds
Definition SkRect.h:36
int32_t fTop
smaller y-axis bounds
Definition SkRect.h:34

◆ validate_run_count()

static bool validate_run_count ( int  ySpanCount,
int  intervalCount,
int  runCount 
)
static

Definition at line 1182 of file SkRegion.cpp.

1182 {
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}
int addInt(int a, int b)
Definition SkSafeMath.h:43

◆ visit_pairs()

static void visit_pairs ( int  pairCount,
int  y,
const int32_t  pairs[],
const std::function< void(const SkIRect &)> &  visitor 
)
static

Definition at line 1547 of file SkRegion.cpp.

1548 {
1549 for (int i = 0; i < pairCount; ++i) {
1550 visitor({ pairs[0], y, pairs[1], y + 1 });
1551 pairs += 2;
1552 }
1553}
double y

Variable Documentation

◆ fMax

uint8_t fMax

Definition at line 826 of file SkRegion.cpp.

◆ fMin

uint8_t fMin

Definition at line 825 of file SkRegion.cpp.

◆ [struct]

const struct { ... } gOpMinMax[]
Initial value:
= {
{ 1, 1 },
{ 3, 3 },
{ 1, 3 },
{ 1, 2 }
}

◆ kRunArrayStackCount

constexpr int kRunArrayStackCount = 256
constexpr

Definition at line 41 of file SkRegion.cpp.