Flutter Engine
The Flutter Engine
SkRegionPriv.h
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
8#ifndef SkRegionPriv_DEFINED
9#define SkRegionPriv_DEFINED
10
15
16#include <atomic>
17#include <functional>
18
20public:
21 inline static constexpr int kRunTypeSentinel = 0x7FFFFFFF;
22 typedef SkRegion::RunType RunType;
24
25 // Call the function with each span, in Y -> X ascending order.
26 // We pass a rect, but we will still ensure the span Y->X ordering, so often the height
27 // of the rect may be 1. It should never be empty.
28 static void VisitSpans(const SkRegion& rgn, const std::function<void(const SkIRect&)>&);
29
30#ifdef SK_DEBUG
31 static void Validate(const SkRegion& rgn);
32#endif
33};
34
35static constexpr int SkRegion_kRunTypeSentinel = 0x7FFFFFFF;
36
37inline bool SkRegionValueIsSentinel(int32_t value) {
38 return value == (int32_t)SkRegion_kRunTypeSentinel;
39}
40
41#define assert_sentinel(value, isSentinel) \
42 SkASSERT(SkRegionValueIsSentinel(value) == isSentinel)
43
44#ifdef SK_DEBUG
45// Given the first interval (just past the interval-count), compute the
46// interval count, by search for the x-sentinel
47//
48static int compute_intervalcount(const SkRegionPriv::RunType runs[]) {
49 const SkRegionPriv::RunType* curr = runs;
50 while (*curr < SkRegion_kRunTypeSentinel) {
51 SkASSERT(curr[0] < curr[1]);
53 curr += 2;
54 }
55 return SkToInt((curr - runs) >> 1);
56}
57#endif
58
60private:
61
62public:
63 std::atomic<int32_t> fRefCnt;
64 int32_t fRunCount;
65
66 /**
67 * Number of spans with different Y values. This does not count the initial
68 * Top value, nor does it count the final Y-Sentinel value. In the logical
69 * case of a rectangle, this would return 1, and an empty region would
70 * return 0.
71 */
72 int getYSpanCount() const {
73 return fYSpanCount;
74 }
75
76 /**
77 * Number of intervals in the entire region. This equals the number of
78 * rects that would be returned by the Iterator. In the logical case of
79 * a rect, this would return 1, and an empty region would return 0.
80 */
81 int getIntervalCount() const {
82 return fIntervalCount;
83 }
84
85 static RunHead* Alloc(int count) {
86 if (count < SkRegion::kRectRegionRuns) {
87 return nullptr;
88 }
89
90 const int64_t size = sk_64_mul(count, sizeof(RunType)) + sizeof(RunHead);
91 if (count < 0 || !SkTFitsIn<int32_t>(size)) { SK_ABORT("Invalid Size"); }
92
94 head->fRefCnt = 1;
95 head->fRunCount = count;
96 // these must be filled in later, otherwise we will be invalid
97 head->fYSpanCount = 0;
98 head->fIntervalCount = 0;
99 return head;
100 }
101
102 static RunHead* Alloc(int count, int yspancount, int intervalCount) {
103 if (yspancount <= 0 || intervalCount <= 1) {
104 return nullptr;
105 }
106
108 if (!head) {
109 return nullptr;
110 }
111 head->fYSpanCount = yspancount;
112 head->fIntervalCount = intervalCount;
113 return head;
114 }
115
116 SkRegion::RunType* writable_runs() {
117 SkASSERT(fRefCnt == 1);
118 return (SkRegion::RunType*)(this + 1);
119 }
120
121 const SkRegion::RunType* readonly_runs() const {
122 return (const SkRegion::RunType*)(this + 1);
123 }
124
126 RunHead* writable = this;
127 if (fRefCnt > 1) {
128 // We need to alloc & copy the current region before decrease
129 // the refcount because it could be freed in the meantime.
130 writable = Alloc(fRunCount, fYSpanCount, fIntervalCount);
131 memcpy(writable->writable_runs(), this->readonly_runs(),
132 fRunCount * sizeof(RunType));
133
134 // fRefCount might have changed since we last checked.
135 // If we own the last reference at this point, we need to
136 // free the memory.
137 if (--fRefCnt == 0) {
138 sk_free(this);
139 }
140 }
141 return writable;
142 }
143
144 /**
145 * Given a scanline (including its Bottom value at runs[0]), return the next
146 * scanline. Asserts that there is one (i.e. runs[0] < Sentinel)
147 */
148 static SkRegion::RunType* SkipEntireScanline(const SkRegion::RunType runs[]) {
149 // we are not the Y Sentinel
151
152 const int intervals = runs[1];
153 SkASSERT(runs[2 + intervals * 2] == SkRegion_kRunTypeSentinel);
154#ifdef SK_DEBUG
155 {
156 int n = compute_intervalcount(&runs[2]);
157 SkASSERT(n == intervals);
158 }
159#endif
160
161 // skip the entire line [B N [L R] S]
162 runs += 1 + 1 + intervals * 2 + 1;
163 return const_cast<SkRegion::RunType*>(runs);
164 }
165
166
167 /**
168 * Return the scanline that contains the Y value. This requires that the Y
169 * value is already known to be contained within the bounds of the region,
170 * and so this routine never returns nullptr.
171 *
172 * It returns the beginning of the scanline, starting with its Bottom value.
173 */
174 SkRegion::RunType* findScanline(int y) const {
175 const RunType* runs = this->readonly_runs();
176
177 // if the top-check fails, we didn't do a quick check on the bounds
178 SkASSERT(y >= runs[0]);
179
180 runs += 1; // skip top-Y
181 for (;;) {
182 int bottom = runs[0];
183 // If we hit this, we've walked off the region, and our bounds check
184 // failed.
186 if (y < bottom) {
187 break;
188 }
189 runs = SkipEntireScanline(runs);
190 }
191 return const_cast<SkRegion::RunType*>(runs);
192 }
193
194 // Copy src runs into us, computing interval counts and bounds along the way
196 RunType* runs = this->writable_runs();
197 bounds->fTop = *runs++;
198
199 int bot;
200 int ySpanCount = 0;
201 int intervalCount = 0;
202 int left = SK_MaxS32;
203 int rite = SK_MinS32;
204
205 do {
206 bot = *runs++;
208 ySpanCount += 1;
209
210 const int intervals = *runs++;
211 SkASSERT(intervals >= 0);
213
214 if (intervals > 0) {
215#ifdef SK_DEBUG
216 {
217 int n = compute_intervalcount(runs);
218 SkASSERT(n == intervals);
219 }
220#endif
221 RunType L = runs[0];
223 if (left > L) {
224 left = L;
225 }
226
227 runs += intervals * 2;
228 RunType R = runs[-1];
230 if (rite < R) {
231 rite = R;
232 }
233
234 intervalCount += intervals;
235 }
237 runs += 1; // skip x-sentinel
238
239 // test Y-sentinel
240 } while (SkRegion_kRunTypeSentinel > *runs);
241
242#ifdef SK_DEBUG
243 // +1 to skip the last Y-sentinel
244 int runCount = SkToInt(runs - this->writable_runs() + 1);
245 SkASSERT(runCount == fRunCount);
246#endif
247
248 fYSpanCount = ySpanCount;
249 fIntervalCount = intervalCount;
250
251 bounds->fLeft = left;
252 bounds->fRight = rite;
253 bounds->fBottom = bot;
254 }
255
256private:
257 int32_t fYSpanCount;
258 int32_t fIntervalCount;
259};
260
261#endif
int count
Definition: FontMgrTest.cpp:50
#define SK_ABORT(message,...)
Definition: SkAssert.h:70
#define SkASSERT(cond)
Definition: SkAssert.h:116
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition: SkMalloc.h:67
static int64_t sk_64_mul(int64_t a, int64_t b)
Definition: SkMath.h:33
static constexpr int32_t SK_MinS32
Definition: SkMath.h:22
static constexpr int32_t SK_MaxS32
Definition: SkMath.h:21
static bool left(const SkPoint &p0, const SkPoint &p1)
static constexpr int SkRegion_kRunTypeSentinel
Definition: SkRegionPriv.h:35
bool SkRegionValueIsSentinel(int32_t value)
Definition: SkRegionPriv.h:37
constexpr int SkToInt(S x)
Definition: SkTo.h:29
static constexpr int kRunTypeSentinel
Definition: SkRegionPriv.h:21
static void VisitSpans(const SkRegion &rgn, const std::function< void(const SkIRect &)> &)
Definition: SkRegion.cpp:1555
SkRegion::RunType RunType
Definition: SkRegionPriv.h:22
SkRegion::RunHead RunHead
Definition: SkRegionPriv.h:23
friend struct RunHead
Definition: SkRegion.h:676
uint8_t value
Dart_NativeFunction function
Definition: fuchsia.cc:51
#define R(r)
double y
Optional< SkRect > bounds
Definition: SkRecords.h:189
void Validate(const Table &table)
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
Definition: SkRect.h:32
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
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
static RunHead * Alloc(int count, int yspancount, int intervalCount)
Definition: SkRegionPriv.h:102
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
static SkRegion::RunType * SkipEntireScanline(const SkRegion::RunType runs[])
Definition: SkRegionPriv.h:148
SkRegion::RunType * findScanline(int y) const
Definition: SkRegionPriv.h:174
std::atomic< int32_t > fRefCnt
Definition: SkRegionPriv.h:63