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