OLD | NEW |
| (Empty) |
1 /* libs/corecg/SkRegion.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkRegionPriv.h" | |
19 #include "SkTemplates.h" | |
20 #include "SkThread.h" | |
21 | |
22 SkDEBUGCODE(int32_t gRgnAllocCounter;) | |
23 | |
24 ////////////////////////////////////////////////////////////////////////////////
///////////////// | |
25 | |
26 /* Pass in a scanline, beginning with the Left value of the pair (i.e. not the
Y beginning) | |
27 */ | |
28 static SkRegion::RunType* skip_scanline(const SkRegion::RunType runs[]) | |
29 { | |
30 while (runs[0] != SkRegion::kRunTypeSentinel) | |
31 { | |
32 SkASSERT(runs[0] < runs[1]); // valid span | |
33 runs += 2; | |
34 } | |
35 return (SkRegion::RunType*)(runs + 1); // return past the X-sentinel | |
36 } | |
37 | |
38 static SkRegion::RunType* find_y(const SkRegion::RunType runs[], int y) | |
39 { | |
40 int top = *runs++; | |
41 if (top <= y) | |
42 { | |
43 for (;;) | |
44 { | |
45 int bot = *runs++; | |
46 if (bot > y) | |
47 { | |
48 if (bot == SkRegion::kRunTypeSentinel || *runs == SkRegion::kRun
TypeSentinel) | |
49 break; | |
50 return (SkRegion::RunType*)runs; | |
51 } | |
52 top = bot; | |
53 runs = skip_scanline(runs); | |
54 } | |
55 } | |
56 return NULL; | |
57 } | |
58 | |
59 // returns true if runs are just a rect | |
60 bool SkRegion::ComputeRunBounds(const SkRegion::RunType runs[], int count, SkIRe
ct* bounds) | |
61 { | |
62 assert_sentinel(runs[0], false); // top | |
63 | |
64 if (count == kRectRegionRuns) | |
65 { | |
66 assert_sentinel(runs[1], false); // bottom | |
67 assert_sentinel(runs[2], false); // left | |
68 assert_sentinel(runs[3], false); // right | |
69 assert_sentinel(runs[4], true); | |
70 assert_sentinel(runs[5], true); | |
71 | |
72 SkASSERT(runs[0] < runs[1]); // valid height | |
73 SkASSERT(runs[2] < runs[3]); // valid width | |
74 | |
75 bounds->set(runs[2], runs[0], runs[3], runs[1]); | |
76 return true; | |
77 } | |
78 | |
79 int left = SK_MaxS32; | |
80 int rite = SK_MinS32; | |
81 int bot; | |
82 | |
83 bounds->fTop = *runs++; | |
84 do { | |
85 bot = *runs++; | |
86 if (*runs < SkRegion::kRunTypeSentinel) | |
87 { | |
88 if (left > *runs) | |
89 left = *runs; | |
90 runs = skip_scanline(runs); | |
91 if (rite < runs[-2]) | |
92 rite = runs[-2]; | |
93 } | |
94 else | |
95 runs += 1; // skip X-sentinel | |
96 } while (runs[0] < SkRegion::kRunTypeSentinel); | |
97 bounds->fLeft = left; | |
98 bounds->fRight = rite; | |
99 bounds->fBottom = bot; | |
100 return false; | |
101 } | |
102 | |
103 ////////////////////////////////////////////////////////////////////////// | |
104 | |
105 SkRegion::SkRegion() | |
106 { | |
107 fBounds.set(0, 0, 0, 0); | |
108 fRunHead = SkRegion_gEmptyRunHeadPtr; | |
109 } | |
110 | |
111 SkRegion::SkRegion(const SkRegion& src) | |
112 { | |
113 fRunHead = SkRegion_gEmptyRunHeadPtr; // just need a value that won't trig
ger sk_free(fRunHead) | |
114 this->setRegion(src); | |
115 } | |
116 | |
117 SkRegion::SkRegion(const SkIRect& rect) | |
118 { | |
119 fRunHead = SkRegion_gEmptyRunHeadPtr; // just need a value that won't trig
ger sk_free(fRunHead) | |
120 this->setRect(rect); | |
121 } | |
122 | |
123 SkRegion::~SkRegion() | |
124 { | |
125 this->freeRuns(); | |
126 } | |
127 | |
128 void SkRegion::freeRuns() | |
129 { | |
130 if (fRunHead->isComplex()) | |
131 { | |
132 SkASSERT(fRunHead->fRefCnt >= 1); | |
133 if (sk_atomic_dec(&fRunHead->fRefCnt) == 1) | |
134 { | |
135 //SkASSERT(gRgnAllocCounter > 0); | |
136 //SkDEBUGCODE(sk_atomic_dec(&gRgnAllocCounter)); | |
137 //SkDEBUGF(("************** gRgnAllocCounter::free %d\n", gRgnAllocC
ounter)); | |
138 sk_free(fRunHead); | |
139 } | |
140 } | |
141 } | |
142 | |
143 void SkRegion::allocateRuns(int count) | |
144 { | |
145 fRunHead = RunHead::Alloc(count); | |
146 } | |
147 | |
148 SkRegion& SkRegion::operator=(const SkRegion& src) | |
149 { | |
150 (void)this->setRegion(src); | |
151 return *this; | |
152 } | |
153 | |
154 void SkRegion::swap(SkRegion& other) | |
155 { | |
156 SkTSwap<SkIRect>(fBounds, other.fBounds); | |
157 SkTSwap<RunHead*>(fRunHead, other.fRunHead); | |
158 } | |
159 | |
160 bool SkRegion::setEmpty() | |
161 { | |
162 this->freeRuns(); | |
163 fBounds.set(0, 0, 0, 0); | |
164 fRunHead = SkRegion_gEmptyRunHeadPtr; | |
165 return false; | |
166 } | |
167 | |
168 bool SkRegion::setRect(int32_t left, int32_t top, int32_t right, int32_t bottom) | |
169 { | |
170 if (left >= right || top >= bottom) | |
171 return this->setEmpty(); | |
172 | |
173 this->freeRuns(); | |
174 fBounds.set(left, top, right, bottom); | |
175 fRunHead = SkRegion_gRectRunHeadPtr; | |
176 return true; | |
177 } | |
178 | |
179 bool SkRegion::setRect(const SkIRect& r) | |
180 { | |
181 return this->setRect(r.fLeft, r.fTop, r.fRight, r.fBottom); | |
182 } | |
183 | |
184 bool SkRegion::setRegion(const SkRegion& src) | |
185 { | |
186 if (this != &src) | |
187 { | |
188 this->freeRuns(); | |
189 | |
190 fBounds = src.fBounds; | |
191 fRunHead = src.fRunHead; | |
192 if (fRunHead->isComplex()) | |
193 sk_atomic_inc(&fRunHead->fRefCnt); | |
194 } | |
195 return fRunHead != SkRegion_gEmptyRunHeadPtr; | |
196 } | |
197 | |
198 bool SkRegion::op(const SkIRect& rect, const SkRegion& rgn, Op op) | |
199 { | |
200 SkRegion tmp(rect); | |
201 | |
202 return this->op(tmp, rgn, op); | |
203 } | |
204 | |
205 bool SkRegion::op(const SkRegion& rgn, const SkIRect& rect, Op op) | |
206 { | |
207 SkRegion tmp(rect); | |
208 | |
209 return this->op(rgn, tmp, op); | |
210 } | |
211 | |
212 ////////////////////////////////////////////////////////////////////////////////
////// | |
213 | |
214 int SkRegion::count_runtype_values(int* itop, int* ibot) const | |
215 { | |
216 if (this == NULL) | |
217 { | |
218 *itop = SK_MinS32; | |
219 *ibot = SK_MaxS32; | |
220 return 0; | |
221 } | |
222 | |
223 int maxT; | |
224 | |
225 if (this->isRect()) | |
226 maxT = 2; | |
227 else | |
228 { | |
229 SkASSERT(this->isComplex()); | |
230 // skip the top | |
231 const RunType* runs = fRunHead->readonly_runs() + 1; | |
232 maxT = 0; | |
233 | |
234 do { | |
235 const RunType* next = skip_scanline(runs + 1); | |
236 SkASSERT(next > runs); | |
237 int T = (int)(next - runs - 1); | |
238 if (maxT < T) | |
239 maxT = T; | |
240 runs = next; | |
241 } while (runs[0] < SkRegion::kRunTypeSentinel); | |
242 } | |
243 *itop = fBounds.fTop; | |
244 *ibot = fBounds.fBottom; | |
245 return maxT; | |
246 } | |
247 | |
248 bool SkRegion::setRuns(RunType runs[], int count) | |
249 { | |
250 SkDEBUGCODE(this->validate();) | |
251 SkASSERT(count > 0); | |
252 | |
253 if (count <= 2) | |
254 { | |
255 // SkDEBUGF(("setRuns: empty\n")); | |
256 assert_sentinel(runs[count-1], true); | |
257 return this->setEmpty(); | |
258 } | |
259 | |
260 // trim off any empty spans from the top and bottom | |
261 // weird I should need this, perhaps op() could be smarter... | |
262 if (count > kRectRegionRuns) | |
263 { | |
264 RunType* stop = runs + count; | |
265 assert_sentinel(runs[0], false); // top | |
266 assert_sentinel(runs[1], false); // bottom | |
267 if (runs[2] == SkRegion::kRunTypeSentinel) // should be first left... | |
268 { | |
269 runs += 2; // skip empty initial span | |
270 runs[0] = runs[-1]; // set new top to prev bottom | |
271 assert_sentinel(runs[1], false); // bot: a sentinal would mean tw
o in a row | |
272 assert_sentinel(runs[2], false); // left | |
273 assert_sentinel(runs[3], false); // right | |
274 } | |
275 | |
276 // now check for a trailing empty span | |
277 assert_sentinel(stop[-1], true); | |
278 assert_sentinel(stop[-2], true); | |
279 assert_sentinel(stop[-3], false); // should be last right | |
280 if (stop[-4] == SkRegion::kRunTypeSentinel) // eek, stop[-3] was a bot
tom with no x-runs | |
281 { | |
282 stop[-3] = SkRegion::kRunTypeSentinel; // kill empty last span | |
283 stop -= 2; | |
284 assert_sentinel(stop[-1], true); | |
285 assert_sentinel(stop[-2], true); | |
286 assert_sentinel(stop[-3], false); | |
287 assert_sentinel(stop[-4], false); | |
288 assert_sentinel(stop[-5], false); | |
289 } | |
290 count = (int)(stop - runs); | |
291 } | |
292 | |
293 SkASSERT(count >= kRectRegionRuns); | |
294 | |
295 if (ComputeRunBounds(runs, count, &fBounds)) | |
296 { | |
297 // SkDEBUGF(("setRuns: rect[%d %d %d %d]\n", fBounds.fLeft, fBounds.fTop, f
Bounds.fRight, fBounds.fBottom)); | |
298 return this->setRect(fBounds); | |
299 } | |
300 | |
301 // if we get here, we need to become a complex region | |
302 | |
303 if (!fRunHead->isComplex() || fRunHead->fRunCount != count) | |
304 { | |
305 #ifdef SK_DEBUGx | |
306 SkDebugf("setRuns: rgn ["); | |
307 { | |
308 const RunType* r = runs; | |
309 | |
310 SkDebugf(" top: %d\n", *r++); | |
311 while (*r < SkRegion::kRunTypeSentinel) | |
312 { | |
313 SkDebugf(" bottom: %d", *r++); | |
314 while (*r < SkRegion::kRunTypeSentinel) | |
315 { | |
316 SkDebugf(" [%d %d]", r[0], r[1]); | |
317 r += 2; | |
318 } | |
319 SkDebugf("\n"); | |
320 } | |
321 } | |
322 #endif | |
323 this->freeRuns(); | |
324 this->allocateRuns(count); | |
325 } | |
326 | |
327 // must call this before we can write directly into runs() | |
328 // in case we are sharing the buffer with another region (copy on write) | |
329 fRunHead = fRunHead->ensureWritable(); | |
330 memcpy(fRunHead->writable_runs(), runs, count * sizeof(RunType)); | |
331 | |
332 SkDEBUGCODE(this->validate();) | |
333 | |
334 return true; | |
335 } | |
336 | |
337 void SkRegion::BuildRectRuns(const SkIRect& bounds, | |
338 RunType runs[kRectRegionRuns]) | |
339 { | |
340 runs[0] = bounds.fTop; | |
341 runs[1] = bounds.fBottom; | |
342 runs[2] = bounds.fLeft; | |
343 runs[3] = bounds.fRight; | |
344 runs[4] = kRunTypeSentinel; | |
345 runs[5] = kRunTypeSentinel; | |
346 } | |
347 | |
348 static SkRegion::RunType* find_scanline(const SkRegion::RunType runs[], int y) | |
349 { | |
350 SkASSERT(y >= runs[0]); // if this fails, we didn't do a quick check on the
boudns | |
351 | |
352 runs += 1; // skip top-Y | |
353 for (;;) | |
354 { | |
355 if (runs[0] == SkRegion::kRunTypeSentinel) | |
356 break; | |
357 if (y < runs[0]) | |
358 return (SkRegion::RunType*)&runs[1]; | |
359 runs = skip_scanline(runs + 1); // skip the Y value before calling | |
360 } | |
361 return NULL; | |
362 } | |
363 | |
364 bool SkRegion::contains(int x, int y) const | |
365 { | |
366 if (!fBounds.contains(x, y)) | |
367 return false; | |
368 | |
369 if (this->isRect()) | |
370 return true; | |
371 | |
372 SkASSERT(this->isComplex()); | |
373 const RunType* runs = find_scanline(fRunHead->readonly_runs(), y); | |
374 | |
375 if (runs) | |
376 { for (;;) | |
377 { if (x < runs[0]) | |
378 break; | |
379 if (x < runs[1]) | |
380 return true; | |
381 runs += 2; | |
382 } | |
383 } | |
384 return false; | |
385 } | |
386 | |
387 bool SkRegion::contains(const SkIRect& r) const | |
388 { | |
389 SkRegion tmp(r); | |
390 | |
391 return this->contains(tmp); | |
392 } | |
393 | |
394 bool SkRegion::contains(const SkRegion& rgn) const | |
395 { | |
396 if (this->isEmpty() || rgn.isEmpty() || !fBounds.contains(rgn.fBounds)) | |
397 return false; | |
398 | |
399 if (this->isRect()) | |
400 return true; | |
401 | |
402 SkRegion tmp; | |
403 | |
404 tmp.op(*this, rgn, kUnion_Op); | |
405 return tmp == *this; | |
406 } | |
407 | |
408 const SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[], int* count) con
st | |
409 { | |
410 SkASSERT(tmpStorage && count); | |
411 const RunType* runs = tmpStorage; | |
412 | |
413 if (this->isEmpty()) | |
414 { | |
415 tmpStorage[0] = kRunTypeSentinel; | |
416 *count = 1; | |
417 } | |
418 else if (this->isRect()) | |
419 { | |
420 BuildRectRuns(fBounds, tmpStorage); | |
421 *count = kRectRegionRuns; | |
422 } | |
423 else | |
424 { | |
425 *count = fRunHead->fRunCount; | |
426 runs = fRunHead->readonly_runs(); | |
427 } | |
428 return runs; | |
429 } | |
430 | |
431 ////////////////////////////////////////////////////////////////////////////////
///// | |
432 | |
433 bool SkRegion::intersects(const SkIRect& r) const { | |
434 if (this->isEmpty() || r.isEmpty()) { | |
435 return false; | |
436 } | |
437 | |
438 if (!SkIRect::Intersects(fBounds, r)) { | |
439 return false; | |
440 } | |
441 | |
442 if (this->isRect()) { | |
443 return true; | |
444 } | |
445 | |
446 // we are complex | |
447 SkRegion tmp; | |
448 return tmp.op(*this, r, kIntersect_Op); | |
449 } | |
450 | |
451 bool SkRegion::intersects(const SkRegion& rgn) const { | |
452 if (this->isEmpty() || rgn.isEmpty()) { | |
453 return false; | |
454 } | |
455 | |
456 if (!SkIRect::Intersects(fBounds, rgn.fBounds)) { | |
457 return false; | |
458 } | |
459 | |
460 if (this->isRect() && rgn.isRect()) { | |
461 return true; | |
462 } | |
463 | |
464 // one or both of us is complex | |
465 // TODO: write a faster version that aborts as soon as we write the first | |
466 // non-empty span, to avoid build the entire result | |
467 SkRegion tmp; | |
468 return tmp.op(*this, rgn, kIntersect_Op); | |
469 } | |
470 | |
471 ////////////////////////////////////////////////////////////////////////////////
///// | |
472 | |
473 int operator==(const SkRegion& a, const SkRegion& b) | |
474 { | |
475 SkDEBUGCODE(a.validate();) | |
476 SkDEBUGCODE(b.validate();) | |
477 | |
478 if (&a == &b) | |
479 return true; | |
480 if (a.fBounds != b.fBounds) | |
481 return false; | |
482 | |
483 const SkRegion::RunHead* ah = a.fRunHead; | |
484 const SkRegion::RunHead* bh = b.fRunHead; | |
485 | |
486 // this catches empties and rects being equal | |
487 if (ah == bh) | |
488 return true; | |
489 | |
490 // now we insist that both are complex (but different ptrs) | |
491 if (!ah->isComplex() || !bh->isComplex()) | |
492 return false; | |
493 | |
494 return ah->fRunCount == bh->fRunCount && | |
495 !memcmp(ah->readonly_runs(), bh->readonly_runs(), | |
496 ah->fRunCount * sizeof(SkRegion::RunType)); | |
497 } | |
498 | |
499 void SkRegion::translate(int dx, int dy, SkRegion* dst) const | |
500 { | |
501 SkDEBUGCODE(this->validate();) | |
502 | |
503 if (NULL == dst) | |
504 return; | |
505 | |
506 if (this->isEmpty()) | |
507 dst->setEmpty(); | |
508 else if (this->isRect()) | |
509 dst->setRect(fBounds.fLeft + dx, fBounds.fTop + dy, | |
510 fBounds.fRight + dx, fBounds.fBottom + dy); | |
511 else | |
512 { | |
513 if (this == dst) | |
514 { | |
515 dst->fRunHead = dst->fRunHead->ensureWritable(); | |
516 } | |
517 else | |
518 { | |
519 SkRegion tmp; | |
520 tmp.allocateRuns(fRunHead->fRunCount); | |
521 tmp.fBounds = fBounds; | |
522 dst->swap(tmp); | |
523 } | |
524 | |
525 dst->fBounds.offset(dx, dy); | |
526 | |
527 const RunType* sruns = fRunHead->readonly_runs(); | |
528 RunType* druns = dst->fRunHead->writable_runs(); | |
529 | |
530 *druns++ = (SkRegion::RunType)(*sruns++ + dy); // top | |
531 for (;;) | |
532 { | |
533 int bottom = *sruns++; | |
534 if (bottom == kRunTypeSentinel) | |
535 break; | |
536 *druns++ = (SkRegion::RunType)(bottom + dy); // bottom; | |
537 for (;;) | |
538 { | |
539 int x = *sruns++; | |
540 if (x == kRunTypeSentinel) | |
541 break; | |
542 *druns++ = (SkRegion::RunType)(x + dx); | |
543 *druns++ = (SkRegion::RunType)(*sruns++ + dx); | |
544 } | |
545 *druns++ = kRunTypeSentinel; // x sentinel | |
546 } | |
547 *druns++ = kRunTypeSentinel; // y sentinel | |
548 | |
549 SkASSERT(sruns - fRunHead->readonly_runs() == fRunHead->fRunCount); | |
550 SkASSERT(druns - dst->fRunHead->readonly_runs() == dst->fRunHead->fRunCo
unt); | |
551 } | |
552 | |
553 SkDEBUGCODE(this->validate();) | |
554 } | |
555 | |
556 ////////////////////////////////////////////////////////////////////////////////
///// | |
557 | |
558 #if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used
without having been initialized | |
559 #pragma warning ( push ) | |
560 #pragma warning ( disable : 4701 ) | |
561 #endif | |
562 | |
563 #ifdef SK_DEBUG | |
564 static void assert_valid_pair(int left, int rite) | |
565 { | |
566 SkASSERT(left == SkRegion::kRunTypeSentinel || left < rite); | |
567 } | |
568 #else | |
569 #define assert_valid_pair(left, rite) | |
570 #endif | |
571 | |
572 struct spanRec { | |
573 const SkRegion::RunType* fA_runs; | |
574 const SkRegion::RunType* fB_runs; | |
575 int fA_left, fA_rite, fB_left, fB_rite; | |
576 int fLeft, fRite, fInside; | |
577 | |
578 void init(const SkRegion::RunType a_runs[], const SkRegion::RunType b_runs[]
) | |
579 { | |
580 fA_left = *a_runs++; | |
581 fA_rite = *a_runs++; | |
582 fB_left = *b_runs++; | |
583 fB_rite = *b_runs++; | |
584 | |
585 fA_runs = a_runs; | |
586 fB_runs = b_runs; | |
587 } | |
588 | |
589 bool done() const | |
590 { | |
591 SkASSERT(fA_left <= SkRegion::kRunTypeSentinel); | |
592 SkASSERT(fB_left <= SkRegion::kRunTypeSentinel); | |
593 return fA_left == SkRegion::kRunTypeSentinel && fB_left == SkRegion::kRu
nTypeSentinel; | |
594 } | |
595 | |
596 void next() | |
597 { | |
598 assert_valid_pair(fA_left, fA_rite); | |
599 assert_valid_pair(fB_left, fB_rite); | |
600 | |
601 int inside, left, rite SK_INIT_TO_AVOID_WARNING; | |
602 bool a_flush = false; | |
603 bool b_flush = false; | |
604 | |
605 int a_left = fA_left; | |
606 int a_rite = fA_rite; | |
607 int b_left = fB_left; | |
608 int b_rite = fB_rite; | |
609 | |
610 if (a_left < b_left) | |
611 { | |
612 inside = 1; | |
613 left = a_left; | |
614 if (a_rite <= b_left) // [...] <...> | |
615 { | |
616 rite = a_rite; | |
617 a_flush = true; | |
618 } | |
619 else // [...<..]...> or [...<...>...] | |
620 rite = a_left = b_left; | |
621 } | |
622 else if (b_left < a_left) | |
623 { | |
624 inside = 2; | |
625 left = b_left; | |
626 if (b_rite <= a_left) // [...] <...> | |
627 { | |
628 rite = b_rite; | |
629 b_flush = true; | |
630 } | |
631 else // [...<..]...> or [...<...>...] | |
632 rite = b_left = a_left; | |
633 } | |
634 else // a_left == b_left | |
635 { | |
636 inside = 3; | |
637 left = a_left; // or b_left | |
638 if (a_rite <= b_rite) | |
639 { | |
640 rite = b_left = a_rite; | |
641 a_flush = true; | |
642 } | |
643 if (b_rite <= a_rite) | |
644 { | |
645 rite = a_left = b_rite; | |
646 b_flush = true; | |
647 } | |
648 } | |
649 | |
650 if (a_flush) | |
651 { | |
652 a_left = *fA_runs++; | |
653 a_rite = *fA_runs++; | |
654 } | |
655 if (b_flush) | |
656 { | |
657 b_left = *fB_runs++; | |
658 b_rite = *fB_runs++; | |
659 } | |
660 | |
661 SkASSERT(left <= rite); | |
662 | |
663 // now update our state | |
664 fA_left = a_left; | |
665 fA_rite = a_rite; | |
666 fB_left = b_left; | |
667 fB_rite = b_rite; | |
668 | |
669 fLeft = left; | |
670 fRite = rite; | |
671 fInside = inside; | |
672 } | |
673 }; | |
674 | |
675 static SkRegion::RunType* operate_on_span(const SkRegion::RunType a_runs[], | |
676 const SkRegion::RunType b_runs[], | |
677 SkRegion::RunType dst[], | |
678 int min, int max) | |
679 { | |
680 spanRec rec; | |
681 bool firstInterval = true; | |
682 | |
683 rec.init(a_runs, b_runs); | |
684 | |
685 while (!rec.done()) | |
686 { | |
687 rec.next(); | |
688 | |
689 int left = rec.fLeft; | |
690 int rite = rec.fRite; | |
691 | |
692 // add left,rite to our dst buffer (checking for coincidence | |
693 if ((unsigned)(rec.fInside - min) <= (unsigned)(max - min) && | |
694 left < rite) // skip if equal | |
695 { | |
696 if (firstInterval || dst[-1] < left) | |
697 { | |
698 *dst++ = (SkRegion::RunType)(left); | |
699 *dst++ = (SkRegion::RunType)(rite); | |
700 firstInterval = false; | |
701 } | |
702 else // update the right edge | |
703 dst[-1] = (SkRegion::RunType)(rite); | |
704 } | |
705 } | |
706 | |
707 *dst++ = SkRegion::kRunTypeSentinel; | |
708 return dst; | |
709 } | |
710 | |
711 #if defined _WIN32 && _MSC_VER >= 1300 | |
712 #pragma warning ( pop ) | |
713 #endif | |
714 | |
715 static const struct { | |
716 uint8_t fMin; | |
717 uint8_t fMax; | |
718 } gOpMinMax[] = { | |
719 { 1, 1 }, // Difference | |
720 { 3, 3 }, // Intersection | |
721 { 1, 3 }, // Union | |
722 { 1, 2 } // XOR | |
723 }; | |
724 | |
725 class RgnOper { | |
726 public: | |
727 RgnOper(int top, SkRegion::RunType dst[], SkRegion::Op op) | |
728 { | |
729 // need to ensure that the op enum lines up with our minmax array | |
730 SkASSERT(SkRegion::kDifference_Op == 0); | |
731 SkASSERT(SkRegion::kIntersect_Op == 1); | |
732 SkASSERT(SkRegion::kUnion_Op == 2); | |
733 SkASSERT(SkRegion::kXOR_Op == 3); | |
734 SkASSERT((unsigned)op <= 3); | |
735 | |
736 fStartDst = dst; | |
737 fPrevDst = dst + 1; | |
738 fPrevLen = 0; // will never match a length from operate_on_span | |
739 fTop = (SkRegion::RunType)(top); // just a first guess, we might upda
te this | |
740 | |
741 fMin = gOpMinMax[op].fMin; | |
742 fMax = gOpMinMax[op].fMax; | |
743 } | |
744 | |
745 void addSpan(int bottom, const SkRegion::RunType a_runs[], const SkRegion::R
unType b_runs[]) | |
746 { | |
747 SkRegion::RunType* start = fPrevDst + fPrevLen + 1; // skip X values
and slot for the next Y | |
748 SkRegion::RunType* stop = operate_on_span(a_runs, b_runs, start, fMin,
fMax); | |
749 size_t len = stop - start; | |
750 | |
751 if (fPrevLen == len && !memcmp(fPrevDst, start, len * sizeof(SkRegion::R
unType))) // update Y value | |
752 fPrevDst[-1] = (SkRegion::RunType)(bottom); | |
753 else // accept the new span | |
754 { | |
755 if (len == 1 && fPrevLen == 0) { | |
756 fTop = (SkRegion::RunType)(bottom); // just update our bottom | |
757 } else { | |
758 start[-1] = (SkRegion::RunType)(bottom); | |
759 fPrevDst = start; | |
760 fPrevLen = len; | |
761 } | |
762 } | |
763 } | |
764 | |
765 int flush() | |
766 { | |
767 fStartDst[0] = fTop; | |
768 fPrevDst[fPrevLen] = SkRegion::kRunTypeSentinel; | |
769 return (int)(fPrevDst - fStartDst + fPrevLen + 1); | |
770 } | |
771 | |
772 uint8_t fMin, fMax; | |
773 | |
774 private: | |
775 SkRegion::RunType* fStartDst; | |
776 SkRegion::RunType* fPrevDst; | |
777 size_t fPrevLen; | |
778 SkRegion::RunType fTop; | |
779 }; | |
780 | |
781 static int operate( const SkRegion::RunType a_runs[], | |
782 const SkRegion::RunType b_runs[], | |
783 SkRegion::RunType dst[], | |
784 SkRegion::Op op) | |
785 { | |
786 const SkRegion::RunType sentinel = SkRegion::kRunTypeSentinel; | |
787 | |
788 int a_top = *a_runs++; | |
789 int a_bot = *a_runs++; | |
790 int b_top = *b_runs++; | |
791 int b_bot = *b_runs++; | |
792 | |
793 assert_sentinel(a_top, false); | |
794 assert_sentinel(a_bot, false); | |
795 assert_sentinel(b_top, false); | |
796 assert_sentinel(b_bot, false); | |
797 | |
798 RgnOper oper(SkMin32(a_top, b_top), dst, op); | |
799 | |
800 bool firstInterval = true; | |
801 int prevBot = SkRegion::kRunTypeSentinel; // so we fail the first test | |
802 | |
803 while (a_bot < SkRegion::kRunTypeSentinel || b_bot < SkRegion::kRunTypeSenti
nel) | |
804 { | |
805 int top, bot SK_INIT_TO_AVOID_WARNING; | |
806 const SkRegion::RunType* run0 = &sentinel; | |
807 const SkRegion::RunType* run1 = &sentinel; | |
808 bool a_flush = false; | |
809 bool b_flush = false; | |
810 int inside; | |
811 | |
812 if (a_top < b_top) | |
813 { | |
814 inside = 1; | |
815 top = a_top; | |
816 run0 = a_runs; | |
817 if (a_bot <= b_top) // [...] <...> | |
818 { | |
819 bot = a_bot; | |
820 a_flush = true; | |
821 } | |
822 else // [...<..]...> or [...<...>...] | |
823 bot = a_top = b_top; | |
824 } | |
825 else if (b_top < a_top) | |
826 { | |
827 inside = 2; | |
828 top = b_top; | |
829 run1 = b_runs; | |
830 if (b_bot <= a_top) // [...] <...> | |
831 { | |
832 bot = b_bot; | |
833 b_flush = true; | |
834 } | |
835 else // [...<..]...> or [...<...>...] | |
836 bot = b_top = a_top; | |
837 } | |
838 else // a_top == b_top | |
839 { | |
840 inside = 3; | |
841 top = a_top; // or b_top | |
842 run0 = a_runs; | |
843 run1 = b_runs; | |
844 if (a_bot <= b_bot) | |
845 { | |
846 bot = b_top = a_bot; | |
847 a_flush = true; | |
848 } | |
849 if (b_bot <= a_bot) | |
850 { | |
851 bot = a_top = b_bot; | |
852 b_flush = true; | |
853 } | |
854 } | |
855 | |
856 if (top > prevBot) | |
857 oper.addSpan(top, &sentinel, &sentinel); | |
858 | |
859 // if ((unsigned)(inside - oper.fMin) <= (unsigned)(oper.fMax - oper.fMin)) | |
860 { | |
861 oper.addSpan(bot, run0, run1); | |
862 firstInterval = false; | |
863 } | |
864 | |
865 if (a_flush) | |
866 { | |
867 a_runs = skip_scanline(a_runs); | |
868 a_top = a_bot; | |
869 a_bot = *a_runs++; | |
870 if (a_bot == SkRegion::kRunTypeSentinel) | |
871 a_top = a_bot; | |
872 } | |
873 if (b_flush) | |
874 { | |
875 b_runs = skip_scanline(b_runs); | |
876 b_top = b_bot; | |
877 b_bot = *b_runs++; | |
878 if (b_bot == SkRegion::kRunTypeSentinel) | |
879 b_top = b_bot; | |
880 } | |
881 | |
882 prevBot = bot; | |
883 } | |
884 return oper.flush(); | |
885 } | |
886 | |
887 bool SkRegion::op(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op) | |
888 { | |
889 SkDEBUGCODE(this->validate();) | |
890 | |
891 SkASSERT((unsigned)op < kOpCount); | |
892 | |
893 if (kReplace_Op == op) | |
894 return this->set(rgnbOrig); | |
895 | |
896 // swith to using pointers, so we can swap them as needed | |
897 const SkRegion* rgna = &rgnaOrig; | |
898 const SkRegion* rgnb = &rgnbOrig; | |
899 // after this point, do not refer to rgnaOrig or rgnbOrig!!! | |
900 | |
901 // collaps difference and reverse-difference into just difference | |
902 if (kReverseDifference_Op == op) | |
903 { | |
904 SkTSwap<const SkRegion*>(rgna, rgnb); | |
905 op = kDifference_Op; | |
906 } | |
907 | |
908 SkIRect bounds; | |
909 bool a_empty = rgna->isEmpty(); | |
910 bool b_empty = rgnb->isEmpty(); | |
911 bool a_rect = rgna->isRect(); | |
912 bool b_rect = rgnb->isRect(); | |
913 | |
914 switch (op) { | |
915 case kDifference_Op: | |
916 if (a_empty) | |
917 return this->setEmpty(); | |
918 if (b_empty || !SkIRect::Intersects(rgna->fBounds, rgnb->fBounds)) | |
919 return this->setRegion(*rgna); | |
920 break; | |
921 | |
922 case kIntersect_Op: | |
923 if ((a_empty | b_empty) | |
924 || !bounds.intersect(rgna->fBounds, rgnb->fBounds)) | |
925 return this->setEmpty(); | |
926 if (a_rect & b_rect) | |
927 return this->setRect(bounds); | |
928 break; | |
929 | |
930 case kUnion_Op: | |
931 if (a_empty) | |
932 return this->setRegion(*rgnb); | |
933 if (b_empty) | |
934 return this->setRegion(*rgna); | |
935 if (a_rect && rgna->fBounds.contains(rgnb->fBounds)) | |
936 return this->setRegion(*rgna); | |
937 if (b_rect && rgnb->fBounds.contains(rgna->fBounds)) | |
938 return this->setRegion(*rgnb); | |
939 break; | |
940 | |
941 case kXOR_Op: | |
942 if (a_empty) | |
943 return this->setRegion(*rgnb); | |
944 if (b_empty) | |
945 return this->setRegion(*rgna); | |
946 break; | |
947 default: | |
948 SkASSERT(!"unknown region op"); | |
949 return !this->isEmpty(); | |
950 } | |
951 | |
952 RunType tmpA[kRectRegionRuns]; | |
953 RunType tmpB[kRectRegionRuns]; | |
954 | |
955 int a_count, b_count; | |
956 const RunType* a_runs = rgna->getRuns(tmpA, &a_count); | |
957 const RunType* b_runs = rgnb->getRuns(tmpB, &b_count); | |
958 | |
959 int dstCount = 3 * SkMax32(a_count, b_count); | |
960 SkAutoSTMalloc<32, RunType> array(dstCount); | |
961 | |
962 int count = operate(a_runs, b_runs, array.get(), op); | |
963 SkASSERT(count <= dstCount); | |
964 return this->setRuns(array.get(), count); | |
965 } | |
966 | |
967 ////////////////////////////////////////////////////////////////////////////////
////////////////////////// | |
968 | |
969 #include "SkBuffer.h" | |
970 | |
971 uint32_t SkRegion::flatten(void* storage) const { | |
972 if (NULL == storage) { | |
973 uint32_t size = sizeof(int32_t); // -1 (empty), 0 (rect), runCount | |
974 if (!this->isEmpty()) { | |
975 size += sizeof(fBounds); | |
976 if (this->isComplex()) { | |
977 size += fRunHead->fRunCount * sizeof(RunType); | |
978 } | |
979 } | |
980 return size; | |
981 } | |
982 | |
983 SkWBuffer buffer(storage); | |
984 | |
985 if (this->isEmpty()) { | |
986 buffer.write32(-1); | |
987 } else { | |
988 bool isRect = this->isRect(); | |
989 | |
990 buffer.write32(isRect ? 0 : fRunHead->fRunCount); | |
991 buffer.write(&fBounds, sizeof(fBounds)); | |
992 | |
993 if (!isRect) { | |
994 buffer.write(fRunHead->readonly_runs(), | |
995 fRunHead->fRunCount * sizeof(RunType)); | |
996 } | |
997 } | |
998 return buffer.pos(); | |
999 } | |
1000 | |
1001 uint32_t SkRegion::unflatten(const void* storage) { | |
1002 SkRBuffer buffer(storage); | |
1003 SkRegion tmp; | |
1004 int32_t count; | |
1005 | |
1006 count = buffer.readS32(); | |
1007 if (count >= 0) { | |
1008 buffer.read(&tmp.fBounds, sizeof(tmp.fBounds)); | |
1009 if (count == 0) { | |
1010 tmp.fRunHead = SkRegion_gRectRunHeadPtr; | |
1011 } else { | |
1012 tmp.allocateRuns(count); | |
1013 buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(RunType)); | |
1014 } | |
1015 } | |
1016 this->swap(tmp); | |
1017 return buffer.pos(); | |
1018 } | |
1019 | |
1020 ////////////////////////////////////////////////////////////////////////////////
////////////////////////// | |
1021 | |
1022 #ifdef SK_DEBUG | |
1023 | |
1024 static const SkRegion::RunType* validate_line(const SkRegion::RunType run[], con
st SkIRect& bounds) | |
1025 { | |
1026 // *run is the bottom of the current span | |
1027 SkASSERT(*run > bounds.fTop); | |
1028 SkASSERT(*run <= bounds.fBottom); | |
1029 run += 1; | |
1030 | |
1031 // check for empty span | |
1032 if (*run != SkRegion::kRunTypeSentinel) | |
1033 { | |
1034 int prevRite = bounds.fLeft - 1; | |
1035 do { | |
1036 int left = *run++; | |
1037 int rite = *run++; | |
1038 SkASSERT(left < rite); | |
1039 SkASSERT(left > prevRite); | |
1040 SkASSERT(rite <= bounds.fRight); | |
1041 prevRite = rite; | |
1042 } while (*run < SkRegion::kRunTypeSentinel); | |
1043 } | |
1044 return run + 1; // skip sentinel | |
1045 } | |
1046 | |
1047 void SkRegion::validate() const | |
1048 { | |
1049 if (this->isEmpty()) | |
1050 { | |
1051 // check for explicit empty (the zero rect), so we can compare rects to
know when | |
1052 // two regions are equal (i.e. emptyRectA == emptyRectB) | |
1053 // this is stricter than just asserting fBounds.isEmpty() | |
1054 SkASSERT(fBounds.fLeft == 0 && fBounds.fTop == 0 && fBounds.fRight == 0
&& fBounds.fBottom == 0); | |
1055 } | |
1056 else | |
1057 { | |
1058 SkASSERT(!fBounds.isEmpty()); | |
1059 if (!this->isRect()) | |
1060 { | |
1061 SkASSERT(fRunHead->fRefCnt >= 1); | |
1062 SkASSERT(fRunHead->fRunCount >= kRectRegionRuns); | |
1063 | |
1064 const RunType* run = fRunHead->readonly_runs(); | |
1065 const RunType* stop = run + fRunHead->fRunCount; | |
1066 | |
1067 // check that our bounds match our runs | |
1068 { | |
1069 SkIRect bounds; | |
1070 bool isARect = ComputeRunBounds(run, stop - run, &bounds); | |
1071 SkASSERT(!isARect); | |
1072 SkASSERT(bounds == fBounds); | |
1073 } | |
1074 | |
1075 SkASSERT(*run == fBounds.fTop); | |
1076 run++; | |
1077 do { | |
1078 run = validate_line(run, fBounds); | |
1079 } while (*run < kRunTypeSentinel); | |
1080 SkASSERT(run + 1 == stop); | |
1081 } | |
1082 } | |
1083 } | |
1084 | |
1085 void SkRegion::dump() const | |
1086 { | |
1087 if (this->isEmpty()) | |
1088 SkDebugf(" rgn: empty\n"); | |
1089 else | |
1090 { | |
1091 SkDebugf(" rgn: [%d %d %d %d]", fBounds.fLeft, fBounds.fTop, fBounds.fR
ight, fBounds.fBottom); | |
1092 if (this->isComplex()) | |
1093 { | |
1094 const RunType* runs = fRunHead->readonly_runs(); | |
1095 for (int i = 0; i < fRunHead->fRunCount; i++) | |
1096 SkDebugf(" %d", runs[i]); | |
1097 } | |
1098 SkDebugf("\n"); | |
1099 } | |
1100 } | |
1101 | |
1102 #endif | |
1103 | |
1104 ////////////////////////////////////////////////////////////////////////////////
///// | |
1105 | |
1106 SkRegion::Iterator::Iterator(const SkRegion& rgn) { | |
1107 this->reset(rgn); | |
1108 } | |
1109 | |
1110 bool SkRegion::Iterator::rewind() { | |
1111 if (fRgn) { | |
1112 this->reset(*fRgn); | |
1113 return true; | |
1114 } | |
1115 return false; | |
1116 } | |
1117 | |
1118 void SkRegion::Iterator::reset(const SkRegion& rgn) { | |
1119 fRgn = &rgn; | |
1120 if (rgn.isEmpty()) { | |
1121 fDone = true; | |
1122 } else { | |
1123 fDone = false; | |
1124 if (rgn.isRect()) { | |
1125 fRect = rgn.fBounds; | |
1126 fRuns = NULL; | |
1127 } else { | |
1128 fRuns = rgn.fRunHead->readonly_runs(); | |
1129 fRect.set(fRuns[2], fRuns[0], fRuns[3], fRuns[1]); | |
1130 fRuns += 4; | |
1131 } | |
1132 } | |
1133 } | |
1134 | |
1135 void SkRegion::Iterator::next() { | |
1136 if (fDone) { | |
1137 return; | |
1138 } | |
1139 | |
1140 if (fRuns == NULL) { // rect case | |
1141 fDone = true; | |
1142 return; | |
1143 } | |
1144 | |
1145 const RunType* runs = fRuns; | |
1146 | |
1147 if (runs[0] < kRunTypeSentinel) { // valid X value | |
1148 fRect.fLeft = runs[0]; | |
1149 fRect.fRight = runs[1]; | |
1150 runs += 2; | |
1151 } else { // we're at the end of a line | |
1152 runs += 1; | |
1153 if (runs[0] < kRunTypeSentinel) { // valid Y value | |
1154 if (runs[1] == kRunTypeSentinel) { // empty line | |
1155 fRect.fTop = runs[0]; | |
1156 runs += 2; | |
1157 } else { | |
1158 fRect.fTop = fRect.fBottom; | |
1159 } | |
1160 | |
1161 fRect.fBottom = runs[0]; | |
1162 assert_sentinel(runs[1], false); | |
1163 fRect.fLeft = runs[1]; | |
1164 fRect.fRight = runs[2]; | |
1165 runs += 3; | |
1166 } else { // end of rgn | |
1167 fDone = true; | |
1168 } | |
1169 } | |
1170 fRuns = runs; | |
1171 } | |
1172 | |
1173 SkRegion::Cliperator::Cliperator(const SkRegion& rgn, const SkIRect& clip) | |
1174 : fIter(rgn), fClip(clip), fDone(true) { | |
1175 const SkIRect& r = fIter.rect(); | |
1176 | |
1177 while (!fIter.done()) { | |
1178 if (r.fTop >= clip.fBottom) { | |
1179 break; | |
1180 } | |
1181 if (fRect.intersect(clip, r)) { | |
1182 fDone = false; | |
1183 break; | |
1184 } | |
1185 fIter.next(); | |
1186 } | |
1187 } | |
1188 | |
1189 void SkRegion::Cliperator::next() { | |
1190 if (fDone) { | |
1191 return; | |
1192 } | |
1193 | |
1194 const SkIRect& r = fIter.rect(); | |
1195 | |
1196 fDone = true; | |
1197 fIter.next(); | |
1198 while (!fIter.done()) { | |
1199 if (r.fTop >= fClip.fBottom) { | |
1200 break; | |
1201 } | |
1202 if (fRect.intersect(fClip, r)) { | |
1203 fDone = false; | |
1204 break; | |
1205 } | |
1206 fIter.next(); | |
1207 } | |
1208 } | |
1209 | |
1210 ////////////////////////////////////////////////////////////////////// | |
1211 | |
1212 SkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left, int right
) | |
1213 { | |
1214 SkDEBUGCODE(rgn.validate();) | |
1215 | |
1216 const SkIRect& r = rgn.getBounds(); | |
1217 | |
1218 fDone = true; | |
1219 if (!rgn.isEmpty() && y >= r.fTop && y < r.fBottom && right > r.fLeft && lef
t < r.fRight) | |
1220 { | |
1221 if (rgn.isRect()) | |
1222 { | |
1223 if (left < r.fLeft) | |
1224 left = r.fLeft; | |
1225 if (right > r.fRight) | |
1226 right = r.fRight; | |
1227 | |
1228 fLeft = left; | |
1229 fRight = right; | |
1230 fRuns = NULL; // means we're a rect, not a rgn | |
1231 fDone = false; | |
1232 } | |
1233 else | |
1234 { | |
1235 const SkRegion::RunType* runs = find_y(rgn.fRunHead->readonly_runs()
, y); | |
1236 if (runs) | |
1237 { | |
1238 for (;;) | |
1239 { | |
1240 if (runs[0] >= right) // runs[0..1] is to the right of the
span, so we're done | |
1241 break; | |
1242 if (runs[1] <= left) // runs[0..1] is to the left of the
span, so continue | |
1243 { | |
1244 runs += 2; | |
1245 continue; | |
1246 } | |
1247 // runs[0..1] intersects the span | |
1248 fRuns = runs; | |
1249 fLeft = left; | |
1250 fRight = right; | |
1251 fDone = false; | |
1252 break; | |
1253 } | |
1254 } | |
1255 } | |
1256 } | |
1257 } | |
1258 | |
1259 bool SkRegion::Spanerator::next(int* left, int* right) | |
1260 { | |
1261 if (fDone) return false; | |
1262 | |
1263 if (fRuns == NULL) // we're a rect | |
1264 { | |
1265 fDone = true; // ok, now we're done | |
1266 if (left) *left = fLeft; | |
1267 if (right) *right = fRight; | |
1268 return true; // this interval is legal | |
1269 } | |
1270 | |
1271 const SkRegion::RunType* runs = fRuns; | |
1272 | |
1273 if (runs[0] >= fRight) | |
1274 { | |
1275 fDone = true; | |
1276 return false; | |
1277 } | |
1278 | |
1279 SkASSERT(runs[1] > fLeft); | |
1280 | |
1281 if (left) | |
1282 *left = SkMax32(fLeft, runs[0]); | |
1283 if (right) | |
1284 *right = SkMin32(fRight, runs[1]); | |
1285 fRuns = runs + 2; | |
1286 return true; | |
1287 } | |
1288 | |
OLD | NEW |