1
2 /*
3 * Copyright 2011 Google Inc.
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 #include "SkAAClip.h"
10 #include "SkBlitter.h"
11 #include "SkColorPriv.h"
12 #include "SkPath.h"
13 #include "SkScan.h"
14 #include "SkThread.h"
15 #include "SkUtils.h"
16
17 class AutoAAClipValidate {
18 public:
AutoAAClipValidate(const SkAAClip & clip)19 AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
20 fClip.validate();
21 }
~AutoAAClipValidate()22 ~AutoAAClipValidate() {
23 fClip.validate();
24 }
25 private:
26 const SkAAClip& fClip;
27 };
28
29 #ifdef SK_DEBUG
30 #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip)
31 #else
32 #define AUTO_AACLIP_VALIDATE(clip)
33 #endif
34
35 ///////////////////////////////////////////////////////////////////////////////
36
37 #define kMaxInt32 0x7FFFFFFF
38
39 #ifdef SK_DEBUG
x_in_rect(int x,const SkIRect & rect)40 static inline bool x_in_rect(int x, const SkIRect& rect) {
41 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
42 }
43 #endif
44
y_in_rect(int y,const SkIRect & rect)45 static inline bool y_in_rect(int y, const SkIRect& rect) {
46 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
47 }
48
49 /*
50 * Data runs are packed [count, alpha]
51 */
52
53 struct SkAAClip::YOffset {
54 int32_t fY;
55 uint32_t fOffset;
56 };
57
58 struct SkAAClip::RunHead {
59 int32_t fRefCnt;
60 int32_t fRowCount;
61 size_t fDataSize;
62
yoffsetsSkAAClip::RunHead63 YOffset* yoffsets() {
64 return (YOffset*)((char*)this + sizeof(RunHead));
65 }
yoffsetsSkAAClip::RunHead66 const YOffset* yoffsets() const {
67 return (const YOffset*)((const char*)this + sizeof(RunHead));
68 }
dataSkAAClip::RunHead69 uint8_t* data() {
70 return (uint8_t*)(this->yoffsets() + fRowCount);
71 }
dataSkAAClip::RunHead72 const uint8_t* data() const {
73 return (const uint8_t*)(this->yoffsets() + fRowCount);
74 }
75
AllocSkAAClip::RunHead76 static RunHead* Alloc(int rowCount, size_t dataSize) {
77 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
78 RunHead* head = (RunHead*)sk_malloc_throw(size);
79 head->fRefCnt = 1;
80 head->fRowCount = rowCount;
81 head->fDataSize = dataSize;
82 return head;
83 }
84
ComputeRowSizeForWidthSkAAClip::RunHead85 static int ComputeRowSizeForWidth(int width) {
86 // 2 bytes per segment, where each segment can store up to 255 for count
87 int segments = 0;
88 while (width > 0) {
89 segments += 1;
90 int n = SkMin32(width, 255);
91 width -= n;
92 }
93 return segments * 2; // each segment is row[0] + row[1] (n + alpha)
94 }
95
AllocRectSkAAClip::RunHead96 static RunHead* AllocRect(const SkIRect& bounds) {
97 SkASSERT(!bounds.isEmpty());
98 int width = bounds.width();
99 size_t rowSize = ComputeRowSizeForWidth(width);
100 RunHead* head = RunHead::Alloc(1, rowSize);
101 YOffset* yoff = head->yoffsets();
102 yoff->fY = bounds.height() - 1;
103 yoff->fOffset = 0;
104 uint8_t* row = head->data();
105 while (width > 0) {
106 int n = SkMin32(width, 255);
107 row[0] = n;
108 row[1] = 0xFF;
109 width -= n;
110 row += 2;
111 }
112 return head;
113 }
114 };
115
116 class SkAAClip::Iter {
117 public:
118 Iter(const SkAAClip&);
119
done() const120 bool done() const { return fDone; }
top() const121 int top() const { return fTop; }
bottom() const122 int bottom() const { return fBottom; }
data() const123 const uint8_t* data() const { return fData; }
124 void next();
125
126 private:
127 const YOffset* fCurrYOff;
128 const YOffset* fStopYOff;
129 const uint8_t* fData;
130
131 int fTop, fBottom;
132 bool fDone;
133 };
134
Iter(const SkAAClip & clip)135 SkAAClip::Iter::Iter(const SkAAClip& clip) {
136 if (clip.isEmpty()) {
137 fDone = true;
138 fTop = fBottom = clip.fBounds.fBottom;
139 fData = NULL;
140 fCurrYOff = NULL;
141 fStopYOff = NULL;
142 return;
143 }
144
145 const RunHead* head = clip.fRunHead;
146 fCurrYOff = head->yoffsets();
147 fStopYOff = fCurrYOff + head->fRowCount;
148 fData = head->data() + fCurrYOff->fOffset;
149
150 // setup first value
151 fTop = clip.fBounds.fTop;
152 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
153 fDone = false;
154 }
155
next()156 void SkAAClip::Iter::next() {
157 if (!fDone) {
158 const YOffset* prev = fCurrYOff;
159 const YOffset* curr = prev + 1;
160 SkASSERT(curr <= fStopYOff);
161
162 fTop = fBottom;
163 if (curr >= fStopYOff) {
164 fDone = true;
165 fBottom = kMaxInt32;
166 fData = NULL;
167 } else {
168 fBottom += curr->fY - prev->fY;
169 fData += curr->fOffset - prev->fOffset;
170 fCurrYOff = curr;
171 }
172 }
173 }
174
175 #ifdef SK_DEBUG
176 // assert we're exactly width-wide, and then return the number of bytes used
compute_row_length(const uint8_t row[],int width)177 static size_t compute_row_length(const uint8_t row[], int width) {
178 const uint8_t* origRow = row;
179 while (width > 0) {
180 int n = row[0];
181 SkASSERT(n > 0);
182 SkASSERT(n <= width);
183 row += 2;
184 width -= n;
185 }
186 SkASSERT(0 == width);
187 return row - origRow;
188 }
189
validate() const190 void SkAAClip::validate() const {
191 if (NULL == fRunHead) {
192 SkASSERT(fBounds.isEmpty());
193 return;
194 }
195
196 const RunHead* head = fRunHead;
197 SkASSERT(head->fRefCnt > 0);
198 SkASSERT(head->fRowCount > 0);
199
200 const YOffset* yoff = head->yoffsets();
201 const YOffset* ystop = yoff + head->fRowCount;
202 const int lastY = fBounds.height() - 1;
203
204 // Y and offset must be monotonic
205 int prevY = -1;
206 int32_t prevOffset = -1;
207 while (yoff < ystop) {
208 SkASSERT(prevY < yoff->fY);
209 SkASSERT(yoff->fY <= lastY);
210 prevY = yoff->fY;
211 SkASSERT(prevOffset < (int32_t)yoff->fOffset);
212 prevOffset = yoff->fOffset;
213 const uint8_t* row = head->data() + yoff->fOffset;
214 size_t rowLength = compute_row_length(row, fBounds.width());
215 SkASSERT(yoff->fOffset + rowLength <= head->fDataSize);
216 yoff += 1;
217 }
218 // check the last entry;
219 --yoff;
220 SkASSERT(yoff->fY == lastY);
221 }
222 #endif
223
224 ///////////////////////////////////////////////////////////////////////////////
225
226 // Count the number of zeros on the left and right edges of the passed in
227 // RLE row. If 'row' is all zeros return 'width' in both variables.
count_left_right_zeros(const uint8_t * row,int width,int * leftZ,int * riteZ)228 static void count_left_right_zeros(const uint8_t* row, int width,
229 int* leftZ, int* riteZ) {
230 int zeros = 0;
231 do {
232 if (row[1]) {
233 break;
234 }
235 int n = row[0];
236 SkASSERT(n > 0);
237 SkASSERT(n <= width);
238 zeros += n;
239 row += 2;
240 width -= n;
241 } while (width > 0);
242 *leftZ = zeros;
243
244 if (0 == width) {
245 // this line is completely empty return 'width' in both variables
246 *riteZ = *leftZ;
247 return;
248 }
249
250 zeros = 0;
251 while (width > 0) {
252 int n = row[0];
253 SkASSERT(n > 0);
254 if (0 == row[1]) {
255 zeros += n;
256 } else {
257 zeros = 0;
258 }
259 row += 2;
260 width -= n;
261 }
262 *riteZ = zeros;
263 }
264
265 #ifdef SK_DEBUG
test_count_left_right_zeros()266 static void test_count_left_right_zeros() {
267 static bool gOnce;
268 if (gOnce) {
269 return;
270 }
271 gOnce = true;
272
273 const uint8_t data0[] = { 0, 0, 10, 0xFF };
274 const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF };
275 const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF };
276 const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 };
277 const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 };
278 const uint8_t data5[] = { 10, 10, 10, 0 };
279 const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
280
281 const uint8_t* array[] = {
282 data0, data1, data2, data3, data4, data5, data6
283 };
284
285 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
286 const uint8_t* data = array[i];
287 const int expectedL = *data++;
288 const int expectedR = *data++;
289 int L = 12345, R = 12345;
290 count_left_right_zeros(data, 10, &L, &R);
291 SkASSERT(expectedL == L);
292 SkASSERT(expectedR == R);
293 }
294 }
295 #endif
296
297 // modify row in place, trimming off (zeros) from the left and right sides.
298 // return the number of bytes that were completely eliminated from the left
trim_row_left_right(uint8_t * row,int width,int leftZ,int riteZ)299 static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
300 int trim = 0;
301 while (leftZ > 0) {
302 SkASSERT(0 == row[1]);
303 int n = row[0];
304 SkASSERT(n > 0);
305 SkASSERT(n <= width);
306 width -= n;
307 row += 2;
308 if (n > leftZ) {
309 row[-2] = n - leftZ;
310 break;
311 }
312 trim += 2;
313 leftZ -= n;
314 SkASSERT(leftZ >= 0);
315 }
316
317 if (riteZ) {
318 // walk row to the end, and then we'll back up to trim riteZ
319 while (width > 0) {
320 int n = row[0];
321 SkASSERT(n <= width);
322 width -= n;
323 row += 2;
324 }
325 // now skip whole runs of zeros
326 do {
327 row -= 2;
328 SkASSERT(0 == row[1]);
329 int n = row[0];
330 SkASSERT(n > 0);
331 if (n > riteZ) {
332 row[0] = n - riteZ;
333 break;
334 }
335 riteZ -= n;
336 SkASSERT(riteZ >= 0);
337 } while (riteZ > 0);
338 }
339
340 return trim;
341 }
342
343 #ifdef SK_DEBUG
344 // assert that this row is exactly this width
assert_row_width(const uint8_t * row,int width)345 static void assert_row_width(const uint8_t* row, int width) {
346 while (width > 0) {
347 int n = row[0];
348 SkASSERT(n > 0);
349 SkASSERT(n <= width);
350 width -= n;
351 row += 2;
352 }
353 SkASSERT(0 == width);
354 }
355
test_trim_row_left_right()356 static void test_trim_row_left_right() {
357 static bool gOnce;
358 if (gOnce) {
359 return;
360 }
361 gOnce = true;
362
363 uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF };
364 uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF };
365 uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
366 uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
367 uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
368 uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
369 uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
370 uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
371 uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
372 uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
373 uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF };
374
375 uint8_t* array[] = {
376 data0, data1, data2, data3, data4,
377 data5, data6, data7, data8, data9,
378 data10
379 };
380
381 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
382 uint8_t* data = array[i];
383 const int trimL = *data++;
384 const int trimR = *data++;
385 const int expectedSkip = *data++;
386 const int origWidth = *data++;
387 assert_row_width(data, origWidth);
388 int skip = trim_row_left_right(data, origWidth, trimL, trimR);
389 SkASSERT(expectedSkip == skip);
390 int expectedWidth = origWidth - trimL - trimR;
391 assert_row_width(data + skip, expectedWidth);
392 }
393 }
394 #endif
395
trimLeftRight()396 bool SkAAClip::trimLeftRight() {
397 SkDEBUGCODE(test_trim_row_left_right();)
398
399 if (this->isEmpty()) {
400 return false;
401 }
402
403 AUTO_AACLIP_VALIDATE(*this);
404
405 const int width = fBounds.width();
406 RunHead* head = fRunHead;
407 YOffset* yoff = head->yoffsets();
408 YOffset* stop = yoff + head->fRowCount;
409 uint8_t* base = head->data();
410
411 // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum
412 // number of zeros on the left and right of the clip. This information
413 // can be used to shrink the bounding box.
414 int leftZeros = width;
415 int riteZeros = width;
416 while (yoff < stop) {
417 int L, R;
418 count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
419 SkASSERT(L + R < width || (L == width && R == width));
420 if (L < leftZeros) {
421 leftZeros = L;
422 }
423 if (R < riteZeros) {
424 riteZeros = R;
425 }
426 if (0 == (leftZeros | riteZeros)) {
427 // no trimming to do
428 return true;
429 }
430 yoff += 1;
431 }
432
433 SkASSERT(leftZeros || riteZeros);
434 if (width == leftZeros) {
435 SkASSERT(width == riteZeros);
436 return this->setEmpty();
437 }
438
439 this->validate();
440
441 fBounds.fLeft += leftZeros;
442 fBounds.fRight -= riteZeros;
443 SkASSERT(!fBounds.isEmpty());
444
445 // For now we don't realloc the storage (for time), we just shrink in place
446 // This means we don't have to do any memmoves either, since we can just
447 // play tricks with the yoff->fOffset for each row
448 yoff = head->yoffsets();
449 while (yoff < stop) {
450 uint8_t* row = base + yoff->fOffset;
451 SkDEBUGCODE((void)compute_row_length(row, width);)
452 yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
453 SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
454 yoff += 1;
455 }
456 return true;
457 }
458
row_is_all_zeros(const uint8_t * row,int width)459 static bool row_is_all_zeros(const uint8_t* row, int width) {
460 SkASSERT(width > 0);
461 do {
462 if (row[1]) {
463 return false;
464 }
465 int n = row[0];
466 SkASSERT(n <= width);
467 width -= n;
468 row += 2;
469 } while (width > 0);
470 SkASSERT(0 == width);
471 return true;
472 }
473
trimTopBottom()474 bool SkAAClip::trimTopBottom() {
475 if (this->isEmpty()) {
476 return false;
477 }
478
479 this->validate();
480
481 const int width = fBounds.width();
482 RunHead* head = fRunHead;
483 YOffset* yoff = head->yoffsets();
484 YOffset* stop = yoff + head->fRowCount;
485 const uint8_t* base = head->data();
486
487 // Look to trim away empty rows from the top.
488 //
489 int skip = 0;
490 while (yoff < stop) {
491 const uint8_t* data = base + yoff->fOffset;
492 if (!row_is_all_zeros(data, width)) {
493 break;
494 }
495 skip += 1;
496 yoff += 1;
497 }
498 SkASSERT(skip <= head->fRowCount);
499 if (skip == head->fRowCount) {
500 return this->setEmpty();
501 }
502 if (skip > 0) {
503 // adjust fRowCount and fBounds.fTop, and slide all the data up
504 // as we remove [skip] number of YOffset entries
505 yoff = head->yoffsets();
506 int dy = yoff[skip - 1].fY + 1;
507 for (int i = skip; i < head->fRowCount; ++i) {
508 SkASSERT(yoff[i].fY >= dy);
509 yoff[i].fY -= dy;
510 }
511 YOffset* dst = head->yoffsets();
512 size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
513 memmove(dst, dst + skip, size - skip * sizeof(YOffset));
514
515 fBounds.fTop += dy;
516 SkASSERT(!fBounds.isEmpty());
517 head->fRowCount -= skip;
518 SkASSERT(head->fRowCount > 0);
519
520 this->validate();
521 // need to reset this after the memmove
522 base = head->data();
523 }
524
525 // Look to trim away empty rows from the bottom.
526 // We know that we have at least one non-zero row, so we can just walk
527 // backwards without checking for running past the start.
528 //
529 stop = yoff = head->yoffsets() + head->fRowCount;
530 do {
531 yoff -= 1;
532 } while (row_is_all_zeros(base + yoff->fOffset, width));
533 skip = SkToInt(stop - yoff - 1);
534 SkASSERT(skip >= 0 && skip < head->fRowCount);
535 if (skip > 0) {
536 // removing from the bottom is easier than from the top, as we don't
537 // have to adjust any of the Y values, we just have to trim the array
538 memmove(stop - skip, stop, head->fDataSize);
539
540 fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
541 SkASSERT(!fBounds.isEmpty());
542 head->fRowCount -= skip;
543 SkASSERT(head->fRowCount > 0);
544 }
545 this->validate();
546
547 return true;
548 }
549
550 // can't validate before we're done, since trimming is part of the process of
551 // making us valid after the Builder. Since we build from top to bottom, its
552 // possible our fBounds.fBottom is bigger than our last scanline of data, so
553 // we trim fBounds.fBottom back up.
554 //
555 // TODO: check for duplicates in X and Y to further compress our data
556 //
trimBounds()557 bool SkAAClip::trimBounds() {
558 if (this->isEmpty()) {
559 return false;
560 }
561
562 const RunHead* head = fRunHead;
563 const YOffset* yoff = head->yoffsets();
564
565 SkASSERT(head->fRowCount > 0);
566 const YOffset& lastY = yoff[head->fRowCount - 1];
567 SkASSERT(lastY.fY + 1 <= fBounds.height());
568 fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
569 SkASSERT(lastY.fY + 1 == fBounds.height());
570 SkASSERT(!fBounds.isEmpty());
571
572 return this->trimTopBottom() && this->trimLeftRight();
573 }
574
575 ///////////////////////////////////////////////////////////////////////////////
576
freeRuns()577 void SkAAClip::freeRuns() {
578 if (fRunHead) {
579 SkASSERT(fRunHead->fRefCnt >= 1);
580 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
581 sk_free(fRunHead);
582 }
583 }
584 }
585
SkAAClip()586 SkAAClip::SkAAClip() {
587 fBounds.setEmpty();
588 fRunHead = NULL;
589 }
590
SkAAClip(const SkAAClip & src)591 SkAAClip::SkAAClip(const SkAAClip& src) {
592 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
593 fRunHead = NULL;
594 *this = src;
595 }
596
~SkAAClip()597 SkAAClip::~SkAAClip() {
598 this->freeRuns();
599 }
600
operator =(const SkAAClip & src)601 SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
602 AUTO_AACLIP_VALIDATE(*this);
603 src.validate();
604
605 if (this != &src) {
606 this->freeRuns();
607 fBounds = src.fBounds;
608 fRunHead = src.fRunHead;
609 if (fRunHead) {
610 sk_atomic_inc(&fRunHead->fRefCnt);
611 }
612 }
613 return *this;
614 }
615
operator ==(const SkAAClip & a,const SkAAClip & b)616 bool operator==(const SkAAClip& a, const SkAAClip& b) {
617 a.validate();
618 b.validate();
619
620 if (&a == &b) {
621 return true;
622 }
623 if (a.fBounds != b.fBounds) {
624 return false;
625 }
626
627 const SkAAClip::RunHead* ah = a.fRunHead;
628 const SkAAClip::RunHead* bh = b.fRunHead;
629
630 // this catches empties and rects being equal
631 if (ah == bh) {
632 return true;
633 }
634
635 // now we insist that both are complex (but different ptrs)
636 if (!a.fRunHead || !b.fRunHead) {
637 return false;
638 }
639
640 return ah->fRowCount == bh->fRowCount &&
641 ah->fDataSize == bh->fDataSize &&
642 !memcmp(ah->data(), bh->data(), ah->fDataSize);
643 }
644
swap(SkAAClip & other)645 void SkAAClip::swap(SkAAClip& other) {
646 AUTO_AACLIP_VALIDATE(*this);
647 other.validate();
648
649 SkTSwap(fBounds, other.fBounds);
650 SkTSwap(fRunHead, other.fRunHead);
651 }
652
set(const SkAAClip & src)653 bool SkAAClip::set(const SkAAClip& src) {
654 *this = src;
655 return !this->isEmpty();
656 }
657
setEmpty()658 bool SkAAClip::setEmpty() {
659 this->freeRuns();
660 fBounds.setEmpty();
661 fRunHead = NULL;
662 return false;
663 }
664
setRect(const SkIRect & bounds)665 bool SkAAClip::setRect(const SkIRect& bounds) {
666 if (bounds.isEmpty()) {
667 return this->setEmpty();
668 }
669
670 AUTO_AACLIP_VALIDATE(*this);
671
672 #if 0
673 SkRect r;
674 r.set(bounds);
675 SkPath path;
676 path.addRect(r);
677 return this->setPath(path);
678 #else
679 this->freeRuns();
680 fBounds = bounds;
681 fRunHead = RunHead::AllocRect(bounds);
682 SkASSERT(!this->isEmpty());
683 return true;
684 #endif
685 }
686
setRect(const SkRect & r,bool doAA)687 bool SkAAClip::setRect(const SkRect& r, bool doAA) {
688 if (r.isEmpty()) {
689 return this->setEmpty();
690 }
691
692 AUTO_AACLIP_VALIDATE(*this);
693
694 // TODO: special case this
695
696 SkPath path;
697 path.addRect(r);
698 return this->setPath(path, NULL, doAA);
699 }
700
append_run(SkTDArray<uint8_t> & array,uint8_t value,int count)701 static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
702 SkASSERT(count >= 0);
703 while (count > 0) {
704 int n = count;
705 if (n > 255) {
706 n = 255;
707 }
708 uint8_t* data = array.append(2);
709 data[0] = n;
710 data[1] = value;
711 count -= n;
712 }
713 }
714
setRegion(const SkRegion & rgn)715 bool SkAAClip::setRegion(const SkRegion& rgn) {
716 if (rgn.isEmpty()) {
717 return this->setEmpty();
718 }
719 if (rgn.isRect()) {
720 return this->setRect(rgn.getBounds());
721 }
722
723 #if 0
724 SkAAClip clip;
725 SkRegion::Iterator iter(rgn);
726 for (; !iter.done(); iter.next()) {
727 clip.op(iter.rect(), SkRegion::kUnion_Op);
728 }
729 this->swap(clip);
730 return !this->isEmpty();
731 #else
732 const SkIRect& bounds = rgn.getBounds();
733 const int offsetX = bounds.fLeft;
734 const int offsetY = bounds.fTop;
735
736 SkTDArray<YOffset> yArray;
737 SkTDArray<uint8_t> xArray;
738
739 yArray.setReserve(SkMin32(bounds.height(), 1024));
740 xArray.setReserve(SkMin32(bounds.width() * 128, 64 * 1024));
741
742 SkRegion::Iterator iter(rgn);
743 int prevRight = 0;
744 int prevBot = 0;
745 YOffset* currY = NULL;
746
747 for (; !iter.done(); iter.next()) {
748 const SkIRect& r = iter.rect();
749 SkASSERT(bounds.contains(r));
750
751 int bot = r.fBottom - offsetY;
752 SkASSERT(bot >= prevBot);
753 if (bot > prevBot) {
754 if (currY) {
755 // flush current row
756 append_run(xArray, 0, bounds.width() - prevRight);
757 }
758 // did we introduce an empty-gap from the prev row?
759 int top = r.fTop - offsetY;
760 if (top > prevBot) {
761 currY = yArray.append();
762 currY->fY = top - 1;
763 currY->fOffset = xArray.count();
764 append_run(xArray, 0, bounds.width());
765 }
766 // create a new record for this Y value
767 currY = yArray.append();
768 currY->fY = bot - 1;
769 currY->fOffset = xArray.count();
770 prevRight = 0;
771 prevBot = bot;
772 }
773
774 int x = r.fLeft - offsetX;
775 append_run(xArray, 0, x - prevRight);
776
777 int w = r.fRight - r.fLeft;
778 append_run(xArray, 0xFF, w);
779 prevRight = x + w;
780 SkASSERT(prevRight <= bounds.width());
781 }
782 // flush last row
783 append_run(xArray, 0, bounds.width() - prevRight);
784
785 // now pack everything into a RunHead
786 RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
787 memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
788 memcpy(head->data(), xArray.begin(), xArray.bytes());
789
790 this->setEmpty();
791 fBounds = bounds;
792 fRunHead = head;
793 this->validate();
794 return true;
795 #endif
796 }
797
798 ///////////////////////////////////////////////////////////////////////////////
799
findRow(int y,int * lastYForRow) const800 const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
801 SkASSERT(fRunHead);
802
803 if (!y_in_rect(y, fBounds)) {
804 return NULL;
805 }
806 y -= fBounds.y(); // our yoffs values are relative to the top
807
808 const YOffset* yoff = fRunHead->yoffsets();
809 while (yoff->fY < y) {
810 yoff += 1;
811 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
812 }
813
814 if (lastYForRow) {
815 *lastYForRow = fBounds.y() + yoff->fY;
816 }
817 return fRunHead->data() + yoff->fOffset;
818 }
819
findX(const uint8_t data[],int x,int * initialCount) const820 const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
821 SkASSERT(x_in_rect(x, fBounds));
822 x -= fBounds.x();
823
824 // first skip up to X
825 for (;;) {
826 int n = data[0];
827 if (x < n) {
828 if (initialCount) {
829 *initialCount = n - x;
830 }
831 break;
832 }
833 data += 2;
834 x -= n;
835 }
836 return data;
837 }
838
quickContains(int left,int top,int right,int bottom) const839 bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
840 if (this->isEmpty()) {
841 return false;
842 }
843 if (!fBounds.contains(left, top, right, bottom)) {
844 return false;
845 }
846 #if 0
847 if (this->isRect()) {
848 return true;
849 }
850 #endif
851
852 int lastY SK_INIT_TO_AVOID_WARNING;
853 const uint8_t* row = this->findRow(top, &lastY);
854 if (lastY < bottom) {
855 return false;
856 }
857 // now just need to check in X
858 int count;
859 row = this->findX(row, left, &count);
860 #if 0
861 return count >= (right - left) && 0xFF == row[1];
862 #else
863 int rectWidth = right - left;
864 while (0xFF == row[1]) {
865 if (count >= rectWidth) {
866 return true;
867 }
868 rectWidth -= count;
869 row += 2;
870 count = row[0];
871 }
872 return false;
873 #endif
874 }
875
876 ///////////////////////////////////////////////////////////////////////////////
877
878 class SkAAClip::Builder {
879 SkIRect fBounds;
880 struct Row {
881 int fY;
882 int fWidth;
883 SkTDArray<uint8_t>* fData;
884 };
885 SkTDArray<Row> fRows;
886 Row* fCurrRow;
887 int fPrevY;
888 int fWidth;
889 int fMinY;
890
891 public:
Builder(const SkIRect & bounds)892 Builder(const SkIRect& bounds) : fBounds(bounds) {
893 fPrevY = -1;
894 fWidth = bounds.width();
895 fCurrRow = NULL;
896 fMinY = bounds.fTop;
897 }
898
~Builder()899 ~Builder() {
900 Row* row = fRows.begin();
901 Row* stop = fRows.end();
902 while (row < stop) {
903 delete row->fData;
904 row += 1;
905 }
906 }
907
getBounds() const908 const SkIRect& getBounds() const { return fBounds; }
909
addRun(int x,int y,U8CPU alpha,int count)910 void addRun(int x, int y, U8CPU alpha, int count) {
911 SkASSERT(count > 0);
912 SkASSERT(fBounds.contains(x, y));
913 SkASSERT(fBounds.contains(x + count - 1, y));
914
915 x -= fBounds.left();
916 y -= fBounds.top();
917
918 Row* row = fCurrRow;
919 if (y != fPrevY) {
920 SkASSERT(y > fPrevY);
921 fPrevY = y;
922 row = this->flushRow(true);
923 row->fY = y;
924 row->fWidth = 0;
925 SkASSERT(row->fData);
926 SkASSERT(0 == row->fData->count());
927 fCurrRow = row;
928 }
929
930 SkASSERT(row->fWidth <= x);
931 SkASSERT(row->fWidth < fBounds.width());
932
933 SkTDArray<uint8_t>& data = *row->fData;
934
935 int gap = x - row->fWidth;
936 if (gap) {
937 AppendRun(data, 0, gap);
938 row->fWidth += gap;
939 SkASSERT(row->fWidth < fBounds.width());
940 }
941
942 AppendRun(data, alpha, count);
943 row->fWidth += count;
944 SkASSERT(row->fWidth <= fBounds.width());
945 }
946
addColumn(int x,int y,U8CPU alpha,int height)947 void addColumn(int x, int y, U8CPU alpha, int height) {
948 SkASSERT(fBounds.contains(x, y + height - 1));
949
950 this->addRun(x, y, alpha, 1);
951 this->flushRowH(fCurrRow);
952 y -= fBounds.fTop;
953 SkASSERT(y == fCurrRow->fY);
954 fCurrRow->fY = y + height - 1;
955 }
956
addRectRun(int x,int y,int width,int height)957 void addRectRun(int x, int y, int width, int height) {
958 SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
959 this->addRun(x, y, 0xFF, width);
960
961 // we assum the rect must be all we'll see for these scanlines
962 // so we ensure our row goes all the way to our right
963 this->flushRowH(fCurrRow);
964
965 y -= fBounds.fTop;
966 SkASSERT(y == fCurrRow->fY);
967 fCurrRow->fY = y + height - 1;
968 }
969
addAntiRectRun(int x,int y,int width,int height,SkAlpha leftAlpha,SkAlpha rightAlpha)970 void addAntiRectRun(int x, int y, int width, int height,
971 SkAlpha leftAlpha, SkAlpha rightAlpha) {
972 SkASSERT(fBounds.contains(x + width - 1 +
973 (leftAlpha > 0 ? 1 : 0) + (rightAlpha > 0 ? 1 : 0),
974 y + height - 1));
975 SkASSERT(width >= 0);
976
977 // Conceptually we're always adding 3 runs, but we should
978 // merge or omit them if possible.
979 if (leftAlpha == 0xFF) {
980 width++;
981 } else if (leftAlpha > 0) {
982 this->addRun(x++, y, leftAlpha, 1);
983 }
984 if (rightAlpha == 0xFF) {
985 width++;
986 }
987 if (width > 0) {
988 this->addRun(x, y, 0xFF, width);
989 }
990 if (rightAlpha > 0 && rightAlpha < 255) {
991 this->addRun(x + width, y, rightAlpha, 1);
992 }
993
994 // we assume the rect must be all we'll see for these scanlines
995 // so we ensure our row goes all the way to our right
996 this->flushRowH(fCurrRow);
997
998 y -= fBounds.fTop;
999 SkASSERT(y == fCurrRow->fY);
1000 fCurrRow->fY = y + height - 1;
1001 }
1002
finish(SkAAClip * target)1003 bool finish(SkAAClip* target) {
1004 this->flushRow(false);
1005
1006 const Row* row = fRows.begin();
1007 const Row* stop = fRows.end();
1008
1009 size_t dataSize = 0;
1010 while (row < stop) {
1011 dataSize += row->fData->count();
1012 row += 1;
1013 }
1014
1015 if (0 == dataSize) {
1016 return target->setEmpty();
1017 }
1018
1019 SkASSERT(fMinY >= fBounds.fTop);
1020 SkASSERT(fMinY < fBounds.fBottom);
1021 int adjustY = fMinY - fBounds.fTop;
1022 fBounds.fTop = fMinY;
1023
1024 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
1025 YOffset* yoffset = head->yoffsets();
1026 uint8_t* data = head->data();
1027 uint8_t* baseData = data;
1028
1029 row = fRows.begin();
1030 SkDEBUGCODE(int prevY = row->fY - 1;)
1031 while (row < stop) {
1032 SkASSERT(prevY < row->fY); // must be monotonic
1033 SkDEBUGCODE(prevY = row->fY);
1034
1035 yoffset->fY = row->fY - adjustY;
1036 yoffset->fOffset = SkToU32(data - baseData);
1037 yoffset += 1;
1038
1039 size_t n = row->fData->count();
1040 memcpy(data, row->fData->begin(), n);
1041 #ifdef SK_DEBUG
1042 size_t bytesNeeded = compute_row_length(data, fBounds.width());
1043 SkASSERT(bytesNeeded == n);
1044 #endif
1045 data += n;
1046
1047 row += 1;
1048 }
1049
1050 target->freeRuns();
1051 target->fBounds = fBounds;
1052 target->fRunHead = head;
1053 return target->trimBounds();
1054 }
1055
dump()1056 void dump() {
1057 this->validate();
1058 int y;
1059 for (y = 0; y < fRows.count(); ++y) {
1060 const Row& row = fRows[y];
1061 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
1062 const SkTDArray<uint8_t>& data = *row.fData;
1063 int count = data.count();
1064 SkASSERT(!(count & 1));
1065 const uint8_t* ptr = data.begin();
1066 for (int x = 0; x < count; x += 2) {
1067 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
1068 ptr += 2;
1069 }
1070 SkDebugf("\n");
1071 }
1072 }
1073
validate()1074 void validate() {
1075 #ifdef SK_DEBUG
1076 if (false) { // avoid bit rot, suppress warning
1077 test_count_left_right_zeros();
1078 }
1079 int prevY = -1;
1080 for (int i = 0; i < fRows.count(); ++i) {
1081 const Row& row = fRows[i];
1082 SkASSERT(prevY < row.fY);
1083 SkASSERT(fWidth == row.fWidth);
1084 int count = row.fData->count();
1085 const uint8_t* ptr = row.fData->begin();
1086 SkASSERT(!(count & 1));
1087 int w = 0;
1088 for (int x = 0; x < count; x += 2) {
1089 int n = ptr[0];
1090 SkASSERT(n > 0);
1091 w += n;
1092 SkASSERT(w <= fWidth);
1093 ptr += 2;
1094 }
1095 SkASSERT(w == fWidth);
1096 prevY = row.fY;
1097 }
1098 #endif
1099 }
1100
1101 // only called by BuilderBlitter
setMinY(int y)1102 void setMinY(int y) {
1103 fMinY = y;
1104 }
1105
1106 private:
flushRowH(Row * row)1107 void flushRowH(Row* row) {
1108 // flush current row if needed
1109 if (row->fWidth < fWidth) {
1110 AppendRun(*row->fData, 0, fWidth - row->fWidth);
1111 row->fWidth = fWidth;
1112 }
1113 }
1114
flushRow(bool readyForAnother)1115 Row* flushRow(bool readyForAnother) {
1116 Row* next = NULL;
1117 int count = fRows.count();
1118 if (count > 0) {
1119 this->flushRowH(&fRows[count - 1]);
1120 }
1121 if (count > 1) {
1122 // are our last two runs the same?
1123 Row* prev = &fRows[count - 2];
1124 Row* curr = &fRows[count - 1];
1125 SkASSERT(prev->fWidth == fWidth);
1126 SkASSERT(curr->fWidth == fWidth);
1127 if (*prev->fData == *curr->fData) {
1128 prev->fY = curr->fY;
1129 if (readyForAnother) {
1130 curr->fData->rewind();
1131 next = curr;
1132 } else {
1133 delete curr->fData;
1134 fRows.removeShuffle(count - 1);
1135 }
1136 } else {
1137 if (readyForAnother) {
1138 next = fRows.append();
1139 next->fData = new SkTDArray<uint8_t>;
1140 }
1141 }
1142 } else {
1143 if (readyForAnother) {
1144 next = fRows.append();
1145 next->fData = new SkTDArray<uint8_t>;
1146 }
1147 }
1148 return next;
1149 }
1150
AppendRun(SkTDArray<uint8_t> & data,U8CPU alpha,int count)1151 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
1152 do {
1153 int n = count;
1154 if (n > 255) {
1155 n = 255;
1156 }
1157 uint8_t* ptr = data.append(2);
1158 ptr[0] = n;
1159 ptr[1] = alpha;
1160 count -= n;
1161 } while (count > 0);
1162 }
1163 };
1164
1165 class SkAAClip::BuilderBlitter : public SkBlitter {
1166 int fLastY;
1167
1168 /*
1169 If we see a gap of 1 or more empty scanlines while building in Y-order,
1170 we inject an explicit empty scanline (alpha==0)
1171
1172 See AAClipTest.cpp : test_path_with_hole()
1173 */
checkForYGap(int y)1174 void checkForYGap(int y) {
1175 SkASSERT(y >= fLastY);
1176 if (fLastY > -SK_MaxS32) {
1177 int gap = y - fLastY;
1178 if (gap > 1) {
1179 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
1180 }
1181 }
1182 fLastY = y;
1183 }
1184
1185 public:
1186
BuilderBlitter(Builder * builder)1187 BuilderBlitter(Builder* builder) {
1188 fBuilder = builder;
1189 fLeft = builder->getBounds().fLeft;
1190 fRight = builder->getBounds().fRight;
1191 fMinY = SK_MaxS32;
1192 fLastY = -SK_MaxS32; // sentinel
1193 }
1194
finish()1195 void finish() {
1196 if (fMinY < SK_MaxS32) {
1197 fBuilder->setMinY(fMinY);
1198 }
1199 }
1200
1201 /**
1202 Must evaluate clips in scan-line order, so don't want to allow blitV(),
1203 but an AAClip can be clipped down to a single pixel wide, so we
1204 must support it (given AntiRect semantics: minimum width is 2).
1205 Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
1206 any failure cases that misses may have minor artifacts.
1207 */
blitV(int x,int y,int height,SkAlpha alpha)1208 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
1209 this->recordMinY(y);
1210 fBuilder->addColumn(x, y, alpha, height);
1211 fLastY = y + height - 1;
1212 }
1213
blitRect(int x,int y,int width,int height)1214 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
1215 this->recordMinY(y);
1216 this->checkForYGap(y);
1217 fBuilder->addRectRun(x, y, width, height);
1218 fLastY = y + height - 1;
1219 }
1220
blitAntiRect(int x,int y,int width,int height,SkAlpha leftAlpha,SkAlpha rightAlpha)1221 virtual void blitAntiRect(int x, int y, int width, int height,
1222 SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE {
1223 this->recordMinY(y);
1224 this->checkForYGap(y);
1225 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
1226 fLastY = y + height - 1;
1227 }
1228
blitMask(const SkMask &,const SkIRect & clip)1229 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
1230 { unexpected(); }
1231
justAnOpaqueColor(uint32_t *)1232 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
1233 return NULL;
1234 }
1235
blitH(int x,int y,int width)1236 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
1237 this->recordMinY(y);
1238 this->checkForYGap(y);
1239 fBuilder->addRun(x, y, 0xFF, width);
1240 }
1241
blitAntiH(int x,int y,const SkAlpha alpha[],const int16_t runs[])1242 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
1243 const int16_t runs[]) SK_OVERRIDE {
1244 this->recordMinY(y);
1245 this->checkForYGap(y);
1246 for (;;) {
1247 int count = *runs;
1248 if (count <= 0) {
1249 return;
1250 }
1251
1252 // The supersampler's buffer can be the width of the device, so
1253 // we may have to trim the run to our bounds. If so, we assert that
1254 // the extra spans are always alpha==0
1255 int localX = x;
1256 int localCount = count;
1257 if (x < fLeft) {
1258 SkASSERT(0 == *alpha);
1259 int gap = fLeft - x;
1260 SkASSERT(gap <= count);
1261 localX += gap;
1262 localCount -= gap;
1263 }
1264 int right = x + count;
1265 if (right > fRight) {
1266 SkASSERT(0 == *alpha);
1267 localCount -= right - fRight;
1268 SkASSERT(localCount >= 0);
1269 }
1270
1271 if (localCount) {
1272 fBuilder->addRun(localX, y, *alpha, localCount);
1273 }
1274 // Next run
1275 runs += count;
1276 alpha += count;
1277 x += count;
1278 }
1279 }
1280
1281 private:
1282 Builder* fBuilder;
1283 int fLeft; // cache of builder's bounds' left edge
1284 int fRight;
1285 int fMinY;
1286
1287 /*
1288 * We track this, in case the scan converter skipped some number of
1289 * scanlines at the (relative to the bounds it was given). This allows
1290 * the builder, during its finish, to trip its bounds down to the "real"
1291 * top.
1292 */
recordMinY(int y)1293 void recordMinY(int y) {
1294 if (y < fMinY) {
1295 fMinY = y;
1296 }
1297 }
1298
unexpected()1299 void unexpected() {
1300 SkDebugf("---- did not expect to get called here");
1301 sk_throw();
1302 }
1303 };
1304
setPath(const SkPath & path,const SkRegion * clip,bool doAA)1305 bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
1306 AUTO_AACLIP_VALIDATE(*this);
1307
1308 if (clip && clip->isEmpty()) {
1309 return this->setEmpty();
1310 }
1311
1312 SkIRect ibounds;
1313 path.getBounds().roundOut(&ibounds);
1314
1315 SkRegion tmpClip;
1316 if (NULL == clip) {
1317 tmpClip.setRect(ibounds);
1318 clip = &tmpClip;
1319 }
1320
1321 if (path.isInverseFillType()) {
1322 ibounds = clip->getBounds();
1323 } else {
1324 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
1325 return this->setEmpty();
1326 }
1327 }
1328
1329 Builder builder(ibounds);
1330 BuilderBlitter blitter(&builder);
1331
1332 if (doAA) {
1333 SkScan::AntiFillPath(path, *clip, &blitter, true);
1334 } else {
1335 SkScan::FillPath(path, *clip, &blitter);
1336 }
1337
1338 blitter.finish();
1339 return builder.finish(this);
1340 }
1341
1342 ///////////////////////////////////////////////////////////////////////////////
1343
1344 typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1345 const uint8_t* rowA, const SkIRect& rectA,
1346 const uint8_t* rowB, const SkIRect& rectB);
1347
1348 typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1349
sectAlphaProc(U8CPU alphaA,U8CPU alphaB)1350 static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1351 // Multiply
1352 return SkMulDiv255Round(alphaA, alphaB);
1353 }
1354
unionAlphaProc(U8CPU alphaA,U8CPU alphaB)1355 static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1356 // SrcOver
1357 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1358 }
1359
diffAlphaProc(U8CPU alphaA,U8CPU alphaB)1360 static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1361 // SrcOut
1362 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1363 }
1364
xorAlphaProc(U8CPU alphaA,U8CPU alphaB)1365 static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1366 // XOR
1367 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1368 }
1369
find_alpha_proc(SkRegion::Op op)1370 static AlphaProc find_alpha_proc(SkRegion::Op op) {
1371 switch (op) {
1372 case SkRegion::kIntersect_Op:
1373 return sectAlphaProc;
1374 case SkRegion::kDifference_Op:
1375 return diffAlphaProc;
1376 case SkRegion::kUnion_Op:
1377 return unionAlphaProc;
1378 case SkRegion::kXOR_Op:
1379 return xorAlphaProc;
1380 default:
1381 SkDEBUGFAIL("unexpected region op");
1382 return sectAlphaProc;
1383 }
1384 }
1385
1386 class RowIter {
1387 public:
RowIter(const uint8_t * row,const SkIRect & bounds)1388 RowIter(const uint8_t* row, const SkIRect& bounds) {
1389 fRow = row;
1390 fLeft = bounds.fLeft;
1391 fBoundsRight = bounds.fRight;
1392 if (row) {
1393 fRight = bounds.fLeft + row[0];
1394 SkASSERT(fRight <= fBoundsRight);
1395 fAlpha = row[1];
1396 fDone = false;
1397 } else {
1398 fDone = true;
1399 fRight = kMaxInt32;
1400 fAlpha = 0;
1401 }
1402 }
1403
done() const1404 bool done() const { return fDone; }
left() const1405 int left() const { return fLeft; }
right() const1406 int right() const { return fRight; }
alpha() const1407 U8CPU alpha() const { return fAlpha; }
next()1408 void next() {
1409 if (!fDone) {
1410 fLeft = fRight;
1411 if (fRight == fBoundsRight) {
1412 fDone = true;
1413 fRight = kMaxInt32;
1414 fAlpha = 0;
1415 } else {
1416 fRow += 2;
1417 fRight += fRow[0];
1418 fAlpha = fRow[1];
1419 SkASSERT(fRight <= fBoundsRight);
1420 }
1421 }
1422 }
1423
1424 private:
1425 const uint8_t* fRow;
1426 int fLeft;
1427 int fRight;
1428 int fBoundsRight;
1429 bool fDone;
1430 uint8_t fAlpha;
1431 };
1432
adjust_row(RowIter & iter,int & leftA,int & riteA,int rite)1433 static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1434 if (rite == riteA) {
1435 iter.next();
1436 leftA = iter.left();
1437 riteA = iter.right();
1438 }
1439 }
1440
1441 #if 0 // UNUSED
1442 static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1443 SkASSERT(min < max);
1444 SkASSERT(boundsMin < boundsMax);
1445 if (min >= boundsMax || max <= boundsMin) {
1446 return false;
1447 }
1448 if (min < boundsMin) {
1449 min = boundsMin;
1450 }
1451 if (max > boundsMax) {
1452 max = boundsMax;
1453 }
1454 return true;
1455 }
1456 #endif
1457
operatorX(SkAAClip::Builder & builder,int lastY,RowIter & iterA,RowIter & iterB,AlphaProc proc,const SkIRect & bounds)1458 static void operatorX(SkAAClip::Builder& builder, int lastY,
1459 RowIter& iterA, RowIter& iterB,
1460 AlphaProc proc, const SkIRect& bounds) {
1461 int leftA = iterA.left();
1462 int riteA = iterA.right();
1463 int leftB = iterB.left();
1464 int riteB = iterB.right();
1465
1466 int prevRite = bounds.fLeft;
1467
1468 do {
1469 U8CPU alphaA = 0;
1470 U8CPU alphaB = 0;
1471 int left, rite;
1472
1473 if (leftA < leftB) {
1474 left = leftA;
1475 alphaA = iterA.alpha();
1476 if (riteA <= leftB) {
1477 rite = riteA;
1478 } else {
1479 rite = leftA = leftB;
1480 }
1481 } else if (leftB < leftA) {
1482 left = leftB;
1483 alphaB = iterB.alpha();
1484 if (riteB <= leftA) {
1485 rite = riteB;
1486 } else {
1487 rite = leftB = leftA;
1488 }
1489 } else {
1490 left = leftA; // or leftB, since leftA == leftB
1491 rite = leftA = leftB = SkMin32(riteA, riteB);
1492 alphaA = iterA.alpha();
1493 alphaB = iterB.alpha();
1494 }
1495
1496 if (left >= bounds.fRight) {
1497 break;
1498 }
1499 if (rite > bounds.fRight) {
1500 rite = bounds.fRight;
1501 }
1502
1503 if (left >= bounds.fLeft) {
1504 SkASSERT(rite > left);
1505 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
1506 prevRite = rite;
1507 }
1508
1509 adjust_row(iterA, leftA, riteA, rite);
1510 adjust_row(iterB, leftB, riteB, rite);
1511 } while (!iterA.done() || !iterB.done());
1512
1513 if (prevRite < bounds.fRight) {
1514 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
1515 }
1516 }
1517
adjust_iter(SkAAClip::Iter & iter,int & topA,int & botA,int bot)1518 static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1519 if (bot == botA) {
1520 iter.next();
1521 topA = botA;
1522 SkASSERT(botA == iter.top());
1523 botA = iter.bottom();
1524 }
1525 }
1526
operateY(SkAAClip::Builder & builder,const SkAAClip & A,const SkAAClip & B,SkRegion::Op op)1527 static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1528 const SkAAClip& B, SkRegion::Op op) {
1529 AlphaProc proc = find_alpha_proc(op);
1530 const SkIRect& bounds = builder.getBounds();
1531
1532 SkAAClip::Iter iterA(A);
1533 SkAAClip::Iter iterB(B);
1534
1535 SkASSERT(!iterA.done());
1536 int topA = iterA.top();
1537 int botA = iterA.bottom();
1538 SkASSERT(!iterB.done());
1539 int topB = iterB.top();
1540 int botB = iterB.bottom();
1541
1542 do {
1543 const uint8_t* rowA = NULL;
1544 const uint8_t* rowB = NULL;
1545 int top, bot;
1546
1547 if (topA < topB) {
1548 top = topA;
1549 rowA = iterA.data();
1550 if (botA <= topB) {
1551 bot = botA;
1552 } else {
1553 bot = topA = topB;
1554 }
1555
1556 } else if (topB < topA) {
1557 top = topB;
1558 rowB = iterB.data();
1559 if (botB <= topA) {
1560 bot = botB;
1561 } else {
1562 bot = topB = topA;
1563 }
1564 } else {
1565 top = topA; // or topB, since topA == topB
1566 bot = topA = topB = SkMin32(botA, botB);
1567 rowA = iterA.data();
1568 rowB = iterB.data();
1569 }
1570
1571 if (top >= bounds.fBottom) {
1572 break;
1573 }
1574
1575 if (bot > bounds.fBottom) {
1576 bot = bounds.fBottom;
1577 }
1578 SkASSERT(top < bot);
1579
1580 if (!rowA && !rowB) {
1581 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1582 } else if (top >= bounds.fTop) {
1583 SkASSERT(bot <= bounds.fBottom);
1584 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1585 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
1586 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
1587 }
1588
1589 adjust_iter(iterA, topA, botA, bot);
1590 adjust_iter(iterB, topB, botB, bot);
1591 } while (!iterA.done() || !iterB.done());
1592 }
1593
op(const SkAAClip & clipAOrig,const SkAAClip & clipBOrig,SkRegion::Op op)1594 bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1595 SkRegion::Op op) {
1596 AUTO_AACLIP_VALIDATE(*this);
1597
1598 if (SkRegion::kReplace_Op == op) {
1599 return this->set(clipBOrig);
1600 }
1601
1602 const SkAAClip* clipA = &clipAOrig;
1603 const SkAAClip* clipB = &clipBOrig;
1604
1605 if (SkRegion::kReverseDifference_Op == op) {
1606 SkTSwap(clipA, clipB);
1607 op = SkRegion::kDifference_Op;
1608 }
1609
1610 bool a_empty = clipA->isEmpty();
1611 bool b_empty = clipB->isEmpty();
1612
1613 SkIRect bounds;
1614 switch (op) {
1615 case SkRegion::kDifference_Op:
1616 if (a_empty) {
1617 return this->setEmpty();
1618 }
1619 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1620 return this->set(*clipA);
1621 }
1622 bounds = clipA->fBounds;
1623 break;
1624
1625 case SkRegion::kIntersect_Op:
1626 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1627 clipB->fBounds)) {
1628 return this->setEmpty();
1629 }
1630 break;
1631
1632 case SkRegion::kUnion_Op:
1633 case SkRegion::kXOR_Op:
1634 if (a_empty) {
1635 return this->set(*clipB);
1636 }
1637 if (b_empty) {
1638 return this->set(*clipA);
1639 }
1640 bounds = clipA->fBounds;
1641 bounds.join(clipB->fBounds);
1642 break;
1643
1644 default:
1645 SkDEBUGFAIL("unknown region op");
1646 return !this->isEmpty();
1647 }
1648
1649 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1650 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1651
1652 Builder builder(bounds);
1653 operateY(builder, *clipA, *clipB, op);
1654
1655 return builder.finish(this);
1656 }
1657
1658 /*
1659 * It can be expensive to build a local aaclip before applying the op, so
1660 * we first see if we can restrict the bounds of new rect to our current
1661 * bounds, or note that the new rect subsumes our current clip.
1662 */
1663
op(const SkIRect & rOrig,SkRegion::Op op)1664 bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1665 SkIRect rStorage;
1666 const SkIRect* r = &rOrig;
1667
1668 switch (op) {
1669 case SkRegion::kIntersect_Op:
1670 if (!rStorage.intersect(rOrig, fBounds)) {
1671 // no overlap, so we're empty
1672 return this->setEmpty();
1673 }
1674 if (rStorage == fBounds) {
1675 // we were wholly inside the rect, no change
1676 return !this->isEmpty();
1677 }
1678 if (this->quickContains(rStorage)) {
1679 // the intersection is wholly inside us, we're a rect
1680 return this->setRect(rStorage);
1681 }
1682 r = &rStorage; // use the intersected bounds
1683 break;
1684 case SkRegion::kDifference_Op:
1685 break;
1686 case SkRegion::kUnion_Op:
1687 if (rOrig.contains(fBounds)) {
1688 return this->setRect(rOrig);
1689 }
1690 break;
1691 default:
1692 break;
1693 }
1694
1695 SkAAClip clip;
1696 clip.setRect(*r);
1697 return this->op(*this, clip, op);
1698 }
1699
op(const SkRect & rOrig,SkRegion::Op op,bool doAA)1700 bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1701 SkRect rStorage, boundsStorage;
1702 const SkRect* r = &rOrig;
1703
1704 boundsStorage.set(fBounds);
1705 switch (op) {
1706 case SkRegion::kIntersect_Op:
1707 case SkRegion::kDifference_Op:
1708 if (!rStorage.intersect(rOrig, boundsStorage)) {
1709 if (SkRegion::kIntersect_Op == op) {
1710 return this->setEmpty();
1711 } else { // kDifference
1712 return !this->isEmpty();
1713 }
1714 }
1715 r = &rStorage; // use the intersected bounds
1716 break;
1717 case SkRegion::kUnion_Op:
1718 if (rOrig.contains(boundsStorage)) {
1719 return this->setRect(rOrig);
1720 }
1721 break;
1722 default:
1723 break;
1724 }
1725
1726 SkAAClip clip;
1727 clip.setRect(*r, doAA);
1728 return this->op(*this, clip, op);
1729 }
1730
op(const SkAAClip & clip,SkRegion::Op op)1731 bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1732 return this->op(*this, clip, op);
1733 }
1734
1735 ///////////////////////////////////////////////////////////////////////////////
1736
translate(int dx,int dy,SkAAClip * dst) const1737 bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1738 if (NULL == dst) {
1739 return !this->isEmpty();
1740 }
1741
1742 if (this->isEmpty()) {
1743 return dst->setEmpty();
1744 }
1745
1746 if (this != dst) {
1747 sk_atomic_inc(&fRunHead->fRefCnt);
1748 dst->freeRuns();
1749 dst->fRunHead = fRunHead;
1750 dst->fBounds = fBounds;
1751 }
1752 dst->fBounds.offset(dx, dy);
1753 return true;
1754 }
1755
expand_row_to_mask(uint8_t * SK_RESTRICT mask,const uint8_t * SK_RESTRICT row,int width)1756 static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1757 const uint8_t* SK_RESTRICT row,
1758 int width) {
1759 while (width > 0) {
1760 int n = row[0];
1761 SkASSERT(width >= n);
1762 memset(mask, row[1], n);
1763 mask += n;
1764 row += 2;
1765 width -= n;
1766 }
1767 SkASSERT(0 == width);
1768 }
1769
copyToMask(SkMask * mask) const1770 void SkAAClip::copyToMask(SkMask* mask) const {
1771 mask->fFormat = SkMask::kA8_Format;
1772 if (this->isEmpty()) {
1773 mask->fBounds.setEmpty();
1774 mask->fImage = NULL;
1775 mask->fRowBytes = 0;
1776 return;
1777 }
1778
1779 mask->fBounds = fBounds;
1780 mask->fRowBytes = fBounds.width();
1781 size_t size = mask->computeImageSize();
1782 mask->fImage = SkMask::AllocImage(size);
1783
1784 Iter iter(*this);
1785 uint8_t* dst = mask->fImage;
1786 const int width = fBounds.width();
1787
1788 int y = fBounds.fTop;
1789 while (!iter.done()) {
1790 do {
1791 expand_row_to_mask(dst, iter.data(), width);
1792 dst += mask->fRowBytes;
1793 } while (++y < iter.bottom());
1794 iter.next();
1795 }
1796 }
1797
1798 ///////////////////////////////////////////////////////////////////////////////
1799 ///////////////////////////////////////////////////////////////////////////////
1800
expandToRuns(const uint8_t * SK_RESTRICT data,int initialCount,int width,int16_t * SK_RESTRICT runs,SkAlpha * SK_RESTRICT aa)1801 static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1802 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1803 // we don't read our initial n from data, since the caller may have had to
1804 // clip it, hence the initialCount parameter.
1805 int n = initialCount;
1806 for (;;) {
1807 if (n > width) {
1808 n = width;
1809 }
1810 SkASSERT(n > 0);
1811 runs[0] = n;
1812 runs += n;
1813
1814 aa[0] = data[1];
1815 aa += n;
1816
1817 data += 2;
1818 width -= n;
1819 if (0 == width) {
1820 break;
1821 }
1822 // load the next count
1823 n = data[0];
1824 }
1825 runs[0] = 0; // sentinel
1826 }
1827
~SkAAClipBlitter()1828 SkAAClipBlitter::~SkAAClipBlitter() {
1829 sk_free(fScanlineScratch);
1830 }
1831
ensureRunsAndAA()1832 void SkAAClipBlitter::ensureRunsAndAA() {
1833 if (NULL == fScanlineScratch) {
1834 // add 1 so we can store the terminating run count of 0
1835 int count = fAAClipBounds.width() + 1;
1836 // we use this either for fRuns + fAA, or a scaline of a mask
1837 // which may be as deep as 32bits
1838 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1839 fRuns = (int16_t*)fScanlineScratch;
1840 fAA = (SkAlpha*)(fRuns + count);
1841 }
1842 }
1843
blitH(int x,int y,int width)1844 void SkAAClipBlitter::blitH(int x, int y, int width) {
1845 SkASSERT(width > 0);
1846 SkASSERT(fAAClipBounds.contains(x, y));
1847 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1848
1849 const uint8_t* row = fAAClip->findRow(y);
1850 int initialCount;
1851 row = fAAClip->findX(row, x, &initialCount);
1852
1853 if (initialCount >= width) {
1854 SkAlpha alpha = row[1];
1855 if (0 == alpha) {
1856 return;
1857 }
1858 if (0xFF == alpha) {
1859 fBlitter->blitH(x, y, width);
1860 return;
1861 }
1862 }
1863
1864 this->ensureRunsAndAA();
1865 expandToRuns(row, initialCount, width, fRuns, fAA);
1866
1867 fBlitter->blitAntiH(x, y, fAA, fRuns);
1868 }
1869
merge(const uint8_t * SK_RESTRICT row,int rowN,const SkAlpha * SK_RESTRICT srcAA,const int16_t * SK_RESTRICT srcRuns,SkAlpha * SK_RESTRICT dstAA,int16_t * SK_RESTRICT dstRuns,int width)1870 static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1871 const SkAlpha* SK_RESTRICT srcAA,
1872 const int16_t* SK_RESTRICT srcRuns,
1873 SkAlpha* SK_RESTRICT dstAA,
1874 int16_t* SK_RESTRICT dstRuns,
1875 int width) {
1876 SkDEBUGCODE(int accumulated = 0;)
1877 int srcN = srcRuns[0];
1878 // do we need this check?
1879 if (0 == srcN) {
1880 return;
1881 }
1882
1883 for (;;) {
1884 SkASSERT(rowN > 0);
1885 SkASSERT(srcN > 0);
1886
1887 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1888 int minN = SkMin32(srcN, rowN);
1889 dstRuns[0] = minN;
1890 dstRuns += minN;
1891 dstAA[0] = newAlpha;
1892 dstAA += minN;
1893
1894 if (0 == (srcN -= minN)) {
1895 srcN = srcRuns[0]; // refresh
1896 srcRuns += srcN;
1897 srcAA += srcN;
1898 srcN = srcRuns[0]; // reload
1899 if (0 == srcN) {
1900 break;
1901 }
1902 }
1903 if (0 == (rowN -= minN)) {
1904 row += 2;
1905 rowN = row[0]; // reload
1906 }
1907
1908 SkDEBUGCODE(accumulated += minN;)
1909 SkASSERT(accumulated <= width);
1910 }
1911 dstRuns[0] = 0;
1912 }
1913
blitAntiH(int x,int y,const SkAlpha aa[],const int16_t runs[])1914 void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1915 const int16_t runs[]) {
1916
1917 const uint8_t* row = fAAClip->findRow(y);
1918 int initialCount;
1919 row = fAAClip->findX(row, x, &initialCount);
1920
1921 this->ensureRunsAndAA();
1922
1923 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1924 fBlitter->blitAntiH(x, y, fAA, fRuns);
1925 }
1926
blitV(int x,int y,int height,SkAlpha alpha)1927 void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1928 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1929 fBlitter->blitV(x, y, height, alpha);
1930 return;
1931 }
1932
1933 for (;;) {
1934 int lastY SK_INIT_TO_AVOID_WARNING;
1935 const uint8_t* row = fAAClip->findRow(y, &lastY);
1936 int dy = lastY - y + 1;
1937 if (dy > height) {
1938 dy = height;
1939 }
1940 height -= dy;
1941
1942 row = fAAClip->findX(row, x);
1943 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1944 if (newAlpha) {
1945 fBlitter->blitV(x, y, dy, newAlpha);
1946 }
1947 SkASSERT(height >= 0);
1948 if (height <= 0) {
1949 break;
1950 }
1951 y = lastY + 1;
1952 }
1953 }
1954
blitRect(int x,int y,int width,int height)1955 void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1956 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1957 fBlitter->blitRect(x, y, width, height);
1958 return;
1959 }
1960
1961 while (--height >= 0) {
1962 this->blitH(x, y, width);
1963 y += 1;
1964 }
1965 }
1966
1967 typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1968 int initialRowCount, void* dst);
1969
small_memcpy(void * dst,const void * src,size_t n)1970 static void small_memcpy(void* dst, const void* src, size_t n) {
1971 memcpy(dst, src, n);
1972 }
1973
small_bzero(void * dst,size_t n)1974 static void small_bzero(void* dst, size_t n) {
1975 sk_bzero(dst, n);
1976 }
1977
mergeOne(uint8_t value,unsigned alpha)1978 static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1979 return SkMulDiv255Round(value, alpha);
1980 }
mergeOne(uint16_t value,unsigned alpha)1981 static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1982 unsigned r = SkGetPackedR16(value);
1983 unsigned g = SkGetPackedG16(value);
1984 unsigned b = SkGetPackedB16(value);
1985 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1986 SkMulDiv255Round(g, alpha),
1987 SkMulDiv255Round(b, alpha));
1988 }
mergeOne(SkPMColor value,unsigned alpha)1989 static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1990 unsigned a = SkGetPackedA32(value);
1991 unsigned r = SkGetPackedR32(value);
1992 unsigned g = SkGetPackedG32(value);
1993 unsigned b = SkGetPackedB32(value);
1994 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1995 SkMulDiv255Round(r, alpha),
1996 SkMulDiv255Round(g, alpha),
1997 SkMulDiv255Round(b, alpha));
1998 }
1999
mergeT(const T * SK_RESTRICT src,int srcN,const uint8_t * SK_RESTRICT row,int rowN,T * SK_RESTRICT dst)2000 template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
2001 const uint8_t* SK_RESTRICT row, int rowN,
2002 T* SK_RESTRICT dst) {
2003 for (;;) {
2004 SkASSERT(rowN > 0);
2005 SkASSERT(srcN > 0);
2006
2007 int n = SkMin32(rowN, srcN);
2008 unsigned rowA = row[1];
2009 if (0xFF == rowA) {
2010 small_memcpy(dst, src, n * sizeof(T));
2011 } else if (0 == rowA) {
2012 small_bzero(dst, n * sizeof(T));
2013 } else {
2014 for (int i = 0; i < n; ++i) {
2015 dst[i] = mergeOne(src[i], rowA);
2016 }
2017 }
2018
2019 if (0 == (srcN -= n)) {
2020 break;
2021 }
2022
2023 src += n;
2024 dst += n;
2025
2026 SkASSERT(rowN == n);
2027 row += 2;
2028 rowN = row[0];
2029 }
2030 }
2031
find_merge_aa_proc(SkMask::Format format)2032 static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2033 switch (format) {
2034 case SkMask::kBW_Format:
2035 SkDEBUGFAIL("unsupported");
2036 return NULL;
2037 case SkMask::kA8_Format:
2038 case SkMask::k3D_Format: {
2039 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
2040 return (MergeAAProc)proc8;
2041 }
2042 case SkMask::kLCD16_Format: {
2043 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
2044 return (MergeAAProc)proc16;
2045 }
2046 case SkMask::kLCD32_Format: {
2047 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
2048 return (MergeAAProc)proc32;
2049 }
2050 default:
2051 SkDEBUGFAIL("unsupported");
2052 return NULL;
2053 }
2054 }
2055
bit2byte(int bitInAByte)2056 static U8CPU bit2byte(int bitInAByte) {
2057 SkASSERT(bitInAByte <= 0xFF);
2058 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2059 // some value >= 8 to get a full FF value
2060 return -bitInAByte >> 8;
2061 }
2062
upscaleBW2A8(SkMask * dstMask,const SkMask & srcMask)2063 static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2064 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2065 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2066
2067 const int width = srcMask.fBounds.width();
2068 const int height = srcMask.fBounds.height();
2069
2070 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2071 const size_t srcRB = srcMask.fRowBytes;
2072 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2073 const size_t dstRB = dstMask->fRowBytes;
2074
2075 const int wholeBytes = width >> 3;
2076 const int leftOverBits = width & 7;
2077
2078 for (int y = 0; y < height; ++y) {
2079 uint8_t* SK_RESTRICT d = dst;
2080 for (int i = 0; i < wholeBytes; ++i) {
2081 int srcByte = src[i];
2082 d[0] = bit2byte(srcByte & (1 << 7));
2083 d[1] = bit2byte(srcByte & (1 << 6));
2084 d[2] = bit2byte(srcByte & (1 << 5));
2085 d[3] = bit2byte(srcByte & (1 << 4));
2086 d[4] = bit2byte(srcByte & (1 << 3));
2087 d[5] = bit2byte(srcByte & (1 << 2));
2088 d[6] = bit2byte(srcByte & (1 << 1));
2089 d[7] = bit2byte(srcByte & (1 << 0));
2090 d += 8;
2091 }
2092 if (leftOverBits) {
2093 int srcByte = src[wholeBytes];
2094 for (int x = 0; x < leftOverBits; ++x) {
2095 *d++ = bit2byte(srcByte & 0x80);
2096 srcByte <<= 1;
2097 }
2098 }
2099 src += srcRB;
2100 dst += dstRB;
2101 }
2102 }
2103
blitMask(const SkMask & origMask,const SkIRect & clip)2104 void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2105 SkASSERT(fAAClip->getBounds().contains(clip));
2106
2107 if (fAAClip->quickContains(clip)) {
2108 fBlitter->blitMask(origMask, clip);
2109 return;
2110 }
2111
2112 const SkMask* mask = &origMask;
2113
2114 // if we're BW, we need to upscale to A8 (ugh)
2115 SkMask grayMask;
2116 grayMask.fImage = NULL;
2117 if (SkMask::kBW_Format == origMask.fFormat) {
2118 grayMask.fFormat = SkMask::kA8_Format;
2119 grayMask.fBounds = origMask.fBounds;
2120 grayMask.fRowBytes = origMask.fBounds.width();
2121 size_t size = grayMask.computeImageSize();
2122 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2123 SkAutoMalloc::kReuse_OnShrink);
2124
2125 upscaleBW2A8(&grayMask, origMask);
2126 mask = &grayMask;
2127 }
2128
2129 this->ensureRunsAndAA();
2130
2131 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2132 // data into a temp block to support it better (ugh)
2133
2134 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2135 const size_t srcRB = mask->fRowBytes;
2136 const int width = clip.width();
2137 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2138
2139 SkMask rowMask;
2140 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2141 rowMask.fBounds.fLeft = clip.fLeft;
2142 rowMask.fBounds.fRight = clip.fRight;
2143 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2144 rowMask.fImage = (uint8_t*)fScanlineScratch;
2145
2146 int y = clip.fTop;
2147 const int stopY = y + clip.height();
2148
2149 do {
2150 int localStopY SK_INIT_TO_AVOID_WARNING;
2151 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2152 // findRow returns last Y, not stop, so we add 1
2153 localStopY = SkMin32(localStopY + 1, stopY);
2154
2155 int initialCount;
2156 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2157 do {
2158 mergeProc(src, width, row, initialCount, rowMask.fImage);
2159 rowMask.fBounds.fTop = y;
2160 rowMask.fBounds.fBottom = y + 1;
2161 fBlitter->blitMask(rowMask, rowMask.fBounds);
2162 src = (const void*)((const char*)src + srcRB);
2163 } while (++y < localStopY);
2164 } while (y < stopY);
2165 }
2166
justAnOpaqueColor(uint32_t * value)2167 const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
2168 return NULL;
2169 }
2170