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