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