Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Side by Side Diff: skia/corecg/SkRegion.cpp

Issue 113827: Remove the remainder of the skia source code from the Chromium repo.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « skia/corecg/SkRect.cpp ('k') | skia/corecg/SkRegionPriv.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « skia/corecg/SkRect.cpp ('k') | skia/corecg/SkRegionPriv.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698