|
1 |
|
2 /* |
|
3 * Copyright 2006 The Android Open Source Project |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 |
|
10 #ifndef SkRegionPriv_DEFINED |
|
11 #define SkRegionPriv_DEFINED |
|
12 |
|
13 #include "SkRegion.h" |
|
14 #include "SkThread.h" |
|
15 |
|
16 #define assert_sentinel(value, isSentinel) \ |
|
17 SkASSERT(((value) == SkRegion::kRunTypeSentinel) == isSentinel) |
|
18 |
|
19 //SkDEBUGCODE(extern int32_t gRgnAllocCounter;) |
|
20 |
|
21 #ifdef SK_DEBUG |
|
22 // Given the first interval (just past the interval-count), compute the |
|
23 // interval count, by search for the x-sentinel |
|
24 // |
|
25 static int compute_intervalcount(const SkRegion::RunType runs[]) { |
|
26 const SkRegion::RunType* curr = runs; |
|
27 while (*curr < SkRegion::kRunTypeSentinel) { |
|
28 SkASSERT(curr[0] < curr[1]); |
|
29 SkASSERT(curr[1] < SkRegion::kRunTypeSentinel); |
|
30 curr += 2; |
|
31 } |
|
32 return (curr - runs) >> 1; |
|
33 } |
|
34 #endif |
|
35 |
|
36 struct SkRegion::RunHead { |
|
37 private: |
|
38 |
|
39 public: |
|
40 int32_t fRefCnt; |
|
41 int32_t fRunCount; |
|
42 |
|
43 /** |
|
44 * Number of spans with different Y values. This does not count the initial |
|
45 * Top value, nor does it count the final Y-Sentinel value. In the logical |
|
46 * case of a rectangle, this would return 1, and an empty region would |
|
47 * return 0. |
|
48 */ |
|
49 int getYSpanCount() const { |
|
50 return fYSpanCount; |
|
51 } |
|
52 |
|
53 /** |
|
54 * Number of intervals in the entire region. This equals the number of |
|
55 * rects that would be returned by the Iterator. In the logical case of |
|
56 * a rect, this would return 1, and an empty region would return 0. |
|
57 */ |
|
58 int getIntervalCount() const { |
|
59 return fIntervalCount; |
|
60 } |
|
61 |
|
62 static RunHead* Alloc(int count) { |
|
63 //SkDEBUGCODE(sk_atomic_inc(&gRgnAllocCounter);) |
|
64 //SkDEBUGF(("************** gRgnAllocCounter::alloc %d\n", gRgnAllocCounter)); |
|
65 |
|
66 SkASSERT(count >= SkRegion::kRectRegionRuns); |
|
67 |
|
68 RunHead* head = (RunHead*)sk_malloc_throw(sizeof(RunHead) + count * sizeof(RunType)); |
|
69 head->fRefCnt = 1; |
|
70 head->fRunCount = count; |
|
71 // these must be filled in later, otherwise we will be invalid |
|
72 head->fYSpanCount = 0; |
|
73 head->fIntervalCount = 0; |
|
74 return head; |
|
75 } |
|
76 |
|
77 static RunHead* Alloc(int count, int yspancount, int intervalCount) { |
|
78 SkASSERT(yspancount > 0); |
|
79 SkASSERT(intervalCount > 1); |
|
80 |
|
81 RunHead* head = Alloc(count); |
|
82 head->fYSpanCount = yspancount; |
|
83 head->fIntervalCount = intervalCount; |
|
84 return head; |
|
85 } |
|
86 |
|
87 SkRegion::RunType* writable_runs() { |
|
88 SkASSERT(fRefCnt == 1); |
|
89 return (SkRegion::RunType*)(this + 1); |
|
90 } |
|
91 |
|
92 const SkRegion::RunType* readonly_runs() const { |
|
93 return (const SkRegion::RunType*)(this + 1); |
|
94 } |
|
95 |
|
96 RunHead* ensureWritable() { |
|
97 RunHead* writable = this; |
|
98 if (fRefCnt > 1) { |
|
99 // We need to alloc & copy the current region before we call |
|
100 // sk_atomic_dec because it could be freed in the meantime, |
|
101 // otherwise. |
|
102 writable = Alloc(fRunCount, fYSpanCount, fIntervalCount); |
|
103 memcpy(writable->writable_runs(), this->readonly_runs(), |
|
104 fRunCount * sizeof(RunType)); |
|
105 |
|
106 // fRefCount might have changed since we last checked. |
|
107 // If we own the last reference at this point, we need to |
|
108 // free the memory. |
|
109 if (sk_atomic_dec(&fRefCnt) == 1) { |
|
110 sk_free(this); |
|
111 } |
|
112 } |
|
113 return writable; |
|
114 } |
|
115 |
|
116 /** |
|
117 * Given a scanline (including its Bottom value at runs[0]), return the next |
|
118 * scanline. Asserts that there is one (i.e. runs[0] < Sentinel) |
|
119 */ |
|
120 static SkRegion::RunType* SkipEntireScanline(const SkRegion::RunType runs[]) { |
|
121 // we are not the Y Sentinel |
|
122 SkASSERT(runs[0] < SkRegion::kRunTypeSentinel); |
|
123 |
|
124 const int intervals = runs[1]; |
|
125 SkASSERT(runs[2 + intervals * 2] == SkRegion::kRunTypeSentinel); |
|
126 #ifdef SK_DEBUG |
|
127 { |
|
128 int n = compute_intervalcount(&runs[2]); |
|
129 SkASSERT(n == intervals); |
|
130 } |
|
131 #endif |
|
132 |
|
133 // skip the entire line [B N [L R] S] |
|
134 runs += 1 + 1 + intervals * 2 + 1; |
|
135 return const_cast<SkRegion::RunType*>(runs); |
|
136 } |
|
137 |
|
138 |
|
139 /** |
|
140 * Return the scanline that contains the Y value. This requires that the Y |
|
141 * value is already known to be contained within the bounds of the region, |
|
142 * and so this routine never returns NULL. |
|
143 * |
|
144 * It returns the beginning of the scanline, starting with its Bottom value. |
|
145 */ |
|
146 SkRegion::RunType* findScanline(int y) const { |
|
147 const RunType* runs = this->readonly_runs(); |
|
148 |
|
149 // if the top-check fails, we didn't do a quick check on the bounds |
|
150 SkASSERT(y >= runs[0]); |
|
151 |
|
152 runs += 1; // skip top-Y |
|
153 for (;;) { |
|
154 int bottom = runs[0]; |
|
155 // If we hit this, we've walked off the region, and our bounds check |
|
156 // failed. |
|
157 SkASSERT(bottom < SkRegion::kRunTypeSentinel); |
|
158 if (y < bottom) { |
|
159 break; |
|
160 } |
|
161 runs = SkipEntireScanline(runs); |
|
162 } |
|
163 return const_cast<SkRegion::RunType*>(runs); |
|
164 } |
|
165 |
|
166 // Copy src runs into us, computing interval counts and bounds along the way |
|
167 void computeRunBounds(SkIRect* bounds) { |
|
168 RunType* runs = this->writable_runs(); |
|
169 bounds->fTop = *runs++; |
|
170 |
|
171 int bot; |
|
172 int ySpanCount = 0; |
|
173 int intervalCount = 0; |
|
174 int left = SK_MaxS32; |
|
175 int rite = SK_MinS32; |
|
176 |
|
177 do { |
|
178 bot = *runs++; |
|
179 SkASSERT(bot < SkRegion::kRunTypeSentinel); |
|
180 ySpanCount += 1; |
|
181 |
|
182 const int intervals = *runs++; |
|
183 SkASSERT(intervals >= 0); |
|
184 SkASSERT(intervals < SkRegion::kRunTypeSentinel); |
|
185 |
|
186 if (intervals > 0) { |
|
187 #ifdef SK_DEBUG |
|
188 { |
|
189 int n = compute_intervalcount(runs); |
|
190 SkASSERT(n == intervals); |
|
191 } |
|
192 #endif |
|
193 RunType L = runs[0]; |
|
194 SkASSERT(L < SkRegion::kRunTypeSentinel); |
|
195 if (left > L) { |
|
196 left = L; |
|
197 } |
|
198 |
|
199 runs += intervals * 2; |
|
200 RunType R = runs[-1]; |
|
201 SkASSERT(R < SkRegion::kRunTypeSentinel); |
|
202 if (rite < R) { |
|
203 rite = R; |
|
204 } |
|
205 |
|
206 intervalCount += intervals; |
|
207 } |
|
208 SkASSERT(SkRegion::kRunTypeSentinel == *runs); |
|
209 runs += 1; // skip x-sentinel |
|
210 |
|
211 // test Y-sentinel |
|
212 } while (SkRegion::kRunTypeSentinel > *runs); |
|
213 |
|
214 #ifdef SK_DEBUG |
|
215 // +1 to skip the last Y-sentinel |
|
216 int runCount = runs - this->writable_runs() + 1; |
|
217 SkASSERT(runCount == fRunCount); |
|
218 #endif |
|
219 |
|
220 fYSpanCount = ySpanCount; |
|
221 fIntervalCount = intervalCount; |
|
222 |
|
223 bounds->fLeft = left; |
|
224 bounds->fRight = rite; |
|
225 bounds->fBottom = bot; |
|
226 } |
|
227 |
|
228 private: |
|
229 int32_t fYSpanCount; |
|
230 int32_t fIntervalCount; |
|
231 }; |
|
232 |
|
233 #endif |