blob: 78c73931fead45d4253eada97d7b0b8ccf1357b2 [file] [log] [blame]
reed@google.come36707a2011-10-04 21:38:55 +00001/*
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"
herbb906daf2015-09-29 09:37:59 -07009#include "SkAtomics.h"
reed@google.come36707a2011-10-04 21:38:55 +000010#include "SkBlitter.h"
Cary Clarka4083c92017-09-15 11:59:23 -040011#include "SkColorData.h"
Mike Reed9fc53622018-01-03 15:35:33 -050012#include "SkRectPriv.h"
reed@google.come36707a2011-10-04 21:38:55 +000013#include "SkPath.h"
14#include "SkScan.h"
reed@google.com34f7e472011-10-13 15:11:59 +000015#include "SkUtils.h"
reed@google.come36707a2011-10-04 21:38:55 +000016
reed@google.com045e62d2011-10-24 12:19:46 +000017class AutoAAClipValidate {
18public:
19 AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
20 fClip.validate();
21 }
22 ~AutoAAClipValidate() {
23 fClip.validate();
24 }
25private:
26 const SkAAClip& fClip;
27};
28
29#ifdef SK_DEBUG
30 #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip)
31#else
32 #define AUTO_AACLIP_VALIDATE(clip)
33#endif
34
35///////////////////////////////////////////////////////////////////////////////
36
reed@google.com1c04bf92011-10-10 12:57:12 +000037#define kMaxInt32 0x7FFFFFFF
38
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000039#ifdef SK_DEBUG
reed@google.come36707a2011-10-04 21:38:55 +000040static inline bool x_in_rect(int x, const SkIRect& rect) {
41 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
42}
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000043#endif
reed@google.come36707a2011-10-04 21:38:55 +000044
45static inline bool y_in_rect(int y, const SkIRect& rect) {
46 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
47}
48
49/*
50 * Data runs are packed [count, alpha]
51 */
52
53struct SkAAClip::YOffset {
54 int32_t fY;
55 uint32_t fOffset;
56};
57
58struct SkAAClip::RunHead {
59 int32_t fRefCnt;
60 int32_t fRowCount;
scroggo@google.com493c65f2013-02-05 18:49:00 +000061 size_t fDataSize;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000062
reed@google.come36707a2011-10-04 21:38:55 +000063 YOffset* yoffsets() {
64 return (YOffset*)((char*)this + sizeof(RunHead));
65 }
66 const YOffset* yoffsets() const {
67 return (const YOffset*)((const char*)this + sizeof(RunHead));
68 }
69 uint8_t* data() {
70 return (uint8_t*)(this->yoffsets() + fRowCount);
71 }
72 const uint8_t* data() const {
73 return (const uint8_t*)(this->yoffsets() + fRowCount);
74 }
75
76 static RunHead* Alloc(int rowCount, size_t dataSize) {
77 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
78 RunHead* head = (RunHead*)sk_malloc_throw(size);
79 head->fRefCnt = 1;
80 head->fRowCount = rowCount;
81 head->fDataSize = dataSize;
82 return head;
83 }
reed@google.com045e62d2011-10-24 12:19:46 +000084
85 static int ComputeRowSizeForWidth(int width) {
86 // 2 bytes per segment, where each segment can store up to 255 for count
87 int segments = 0;
88 while (width > 0) {
89 segments += 1;
90 int n = SkMin32(width, 255);
91 width -= n;
92 }
93 return segments * 2; // each segment is row[0] + row[1] (n + alpha)
94 }
95
96 static RunHead* AllocRect(const SkIRect& bounds) {
97 SkASSERT(!bounds.isEmpty());
98 int width = bounds.width();
99 size_t rowSize = ComputeRowSizeForWidth(width);
100 RunHead* head = RunHead::Alloc(1, rowSize);
101 YOffset* yoff = head->yoffsets();
102 yoff->fY = bounds.height() - 1;
103 yoff->fOffset = 0;
104 uint8_t* row = head->data();
105 while (width > 0) {
106 int n = SkMin32(width, 255);
107 row[0] = n;
108 row[1] = 0xFF;
109 width -= n;
110 row += 2;
111 }
112 return head;
113 }
reed@google.come36707a2011-10-04 21:38:55 +0000114};
115
reed@google.com32287892011-10-05 16:27:44 +0000116class SkAAClip::Iter {
117public:
118 Iter(const SkAAClip&);
119
120 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000121 int top() const { return fTop; }
122 int bottom() const { return fBottom; }
123 const uint8_t* data() const { return fData; }
reed@google.com32287892011-10-05 16:27:44 +0000124 void next();
125
126private:
127 const YOffset* fCurrYOff;
128 const YOffset* fStopYOff;
129 const uint8_t* fData;
130
131 int fTop, fBottom;
132 bool fDone;
133};
134
135SkAAClip::Iter::Iter(const SkAAClip& clip) {
136 if (clip.isEmpty()) {
137 fDone = true;
reed@google.com1c04bf92011-10-10 12:57:12 +0000138 fTop = fBottom = clip.fBounds.fBottom;
halcanary96fcdcc2015-08-27 07:41:13 -0700139 fData = nullptr;
140 fCurrYOff = nullptr;
141 fStopYOff = nullptr;
reed@google.com32287892011-10-05 16:27:44 +0000142 return;
143 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000144
reed@google.com32287892011-10-05 16:27:44 +0000145 const RunHead* head = clip.fRunHead;
146 fCurrYOff = head->yoffsets();
147 fStopYOff = fCurrYOff + head->fRowCount;
148 fData = head->data() + fCurrYOff->fOffset;
149
150 // setup first value
151 fTop = clip.fBounds.fTop;
152 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
153 fDone = false;
154}
155
156void SkAAClip::Iter::next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000157 if (!fDone) {
158 const YOffset* prev = fCurrYOff;
159 const YOffset* curr = prev + 1;
160 SkASSERT(curr <= fStopYOff);
reed@google.com32287892011-10-05 16:27:44 +0000161
reed@google.com32287892011-10-05 16:27:44 +0000162 fTop = fBottom;
reed@google.com1c04bf92011-10-10 12:57:12 +0000163 if (curr >= fStopYOff) {
164 fDone = true;
165 fBottom = kMaxInt32;
halcanary96fcdcc2015-08-27 07:41:13 -0700166 fData = nullptr;
reed@google.com1c04bf92011-10-10 12:57:12 +0000167 } else {
168 fBottom += curr->fY - prev->fY;
169 fData += curr->fOffset - prev->fOffset;
170 fCurrYOff = curr;
171 }
reed@google.com32287892011-10-05 16:27:44 +0000172 }
173}
174
reed@google.com045e62d2011-10-24 12:19:46 +0000175#ifdef SK_DEBUG
reed@google.comc9041912011-10-27 16:58:46 +0000176// assert we're exactly width-wide, and then return the number of bytes used
reed@google.com045e62d2011-10-24 12:19:46 +0000177static size_t compute_row_length(const uint8_t row[], int width) {
178 const uint8_t* origRow = row;
179 while (width > 0) {
180 int n = row[0];
reed@google.comc9041912011-10-27 16:58:46 +0000181 SkASSERT(n > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000182 SkASSERT(n <= width);
183 row += 2;
184 width -= n;
185 }
186 SkASSERT(0 == width);
187 return row - origRow;
188}
189
190void SkAAClip::validate() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700191 if (nullptr == fRunHead) {
reed@google.com045e62d2011-10-24 12:19:46 +0000192 SkASSERT(fBounds.isEmpty());
193 return;
194 }
reedd7ec12e2016-06-20 10:21:24 -0700195 SkASSERT(!fBounds.isEmpty());
reed@google.com045e62d2011-10-24 12:19:46 +0000196
197 const RunHead* head = fRunHead;
198 SkASSERT(head->fRefCnt > 0);
199 SkASSERT(head->fRowCount > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000200
201 const YOffset* yoff = head->yoffsets();
202 const YOffset* ystop = yoff + head->fRowCount;
reed@google.comc9041912011-10-27 16:58:46 +0000203 const int lastY = fBounds.height() - 1;
204
205 // Y and offset must be monotonic
206 int prevY = -1;
207 int32_t prevOffset = -1;
reed@google.com045e62d2011-10-24 12:19:46 +0000208 while (yoff < ystop) {
reed@google.comc9041912011-10-27 16:58:46 +0000209 SkASSERT(prevY < yoff->fY);
210 SkASSERT(yoff->fY <= lastY);
211 prevY = yoff->fY;
212 SkASSERT(prevOffset < (int32_t)yoff->fOffset);
213 prevOffset = yoff->fOffset;
214 const uint8_t* row = head->data() + yoff->fOffset;
reed@google.com045e62d2011-10-24 12:19:46 +0000215 size_t rowLength = compute_row_length(row, fBounds.width());
scroggo@google.com493c65f2013-02-05 18:49:00 +0000216 SkASSERT(yoff->fOffset + rowLength <= head->fDataSize);
reed@google.comc9041912011-10-27 16:58:46 +0000217 yoff += 1;
reed@google.com045e62d2011-10-24 12:19:46 +0000218 }
reed@google.com045e62d2011-10-24 12:19:46 +0000219 // check the last entry;
220 --yoff;
reed@google.comc9041912011-10-27 16:58:46 +0000221 SkASSERT(yoff->fY == lastY);
reed@google.com045e62d2011-10-24 12:19:46 +0000222}
humper6d42d9c2014-08-08 11:45:46 -0700223
224static void dump_one_row(const uint8_t* SK_RESTRICT row,
225 int width, int leading_num) {
226 if (leading_num) {
227 SkDebugf( "%03d ", leading_num );
228 }
229 while (width > 0) {
230 int n = row[0];
231 int val = row[1];
232 char out = '.';
233 if (val == 0xff) {
234 out = '*';
235 } else if (val > 0) {
236 out = '+';
237 }
238 for (int i = 0 ; i < n ; i++) {
239 SkDebugf( "%c", out );
240 }
241 row += 2;
242 width -= n;
243 }
244 SkDebugf( "\n" );
245}
246
247void SkAAClip::debug(bool compress_y) const {
248 Iter iter(*this);
249 const int width = fBounds.width();
250
251 int y = fBounds.fTop;
252 while (!iter.done()) {
253 if (compress_y) {
254 dump_one_row(iter.data(), width, iter.bottom() - iter.top() + 1);
255 } else {
256 do {
257 dump_one_row(iter.data(), width, 0);
258 } while (++y < iter.bottom());
259 }
260 iter.next();
261 }
262}
reed@google.com045e62d2011-10-24 12:19:46 +0000263#endif
264
265///////////////////////////////////////////////////////////////////////////////
266
robertphillips@google.com768fee82012-08-02 12:42:43 +0000267// Count the number of zeros on the left and right edges of the passed in
268// RLE row. If 'row' is all zeros return 'width' in both variables.
reed@google.comc9041912011-10-27 16:58:46 +0000269static void count_left_right_zeros(const uint8_t* row, int width,
270 int* leftZ, int* riteZ) {
271 int zeros = 0;
272 do {
273 if (row[1]) {
274 break;
275 }
276 int n = row[0];
277 SkASSERT(n > 0);
278 SkASSERT(n <= width);
279 zeros += n;
280 row += 2;
281 width -= n;
282 } while (width > 0);
283 *leftZ = zeros;
284
robertphillips@google.com768fee82012-08-02 12:42:43 +0000285 if (0 == width) {
286 // this line is completely empty return 'width' in both variables
287 *riteZ = *leftZ;
288 return;
289 }
290
reed@google.comc9041912011-10-27 16:58:46 +0000291 zeros = 0;
292 while (width > 0) {
293 int n = row[0];
294 SkASSERT(n > 0);
295 if (0 == row[1]) {
296 zeros += n;
297 } else {
298 zeros = 0;
299 }
300 row += 2;
301 width -= n;
302 }
303 *riteZ = zeros;
304}
305
306#ifdef SK_DEBUG
307static void test_count_left_right_zeros() {
308 static bool gOnce;
309 if (gOnce) {
310 return;
311 }
312 gOnce = true;
313
314 const uint8_t data0[] = { 0, 0, 10, 0xFF };
315 const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF };
316 const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF };
317 const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 };
318 const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 };
robertphillips@google.com768fee82012-08-02 12:42:43 +0000319 const uint8_t data5[] = { 10, 10, 10, 0 };
reed@google.comc9041912011-10-27 16:58:46 +0000320 const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
321
322 const uint8_t* array[] = {
323 data0, data1, data2, data3, data4, data5, data6
324 };
325
326 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
327 const uint8_t* data = array[i];
328 const int expectedL = *data++;
329 const int expectedR = *data++;
330 int L = 12345, R = 12345;
331 count_left_right_zeros(data, 10, &L, &R);
332 SkASSERT(expectedL == L);
333 SkASSERT(expectedR == R);
334 }
335}
336#endif
337
338// modify row in place, trimming off (zeros) from the left and right sides.
339// return the number of bytes that were completely eliminated from the left
340static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
341 int trim = 0;
342 while (leftZ > 0) {
343 SkASSERT(0 == row[1]);
344 int n = row[0];
345 SkASSERT(n > 0);
346 SkASSERT(n <= width);
347 width -= n;
348 row += 2;
349 if (n > leftZ) {
350 row[-2] = n - leftZ;
351 break;
352 }
353 trim += 2;
354 leftZ -= n;
355 SkASSERT(leftZ >= 0);
356 }
357
358 if (riteZ) {
359 // walk row to the end, and then we'll back up to trim riteZ
360 while (width > 0) {
361 int n = row[0];
362 SkASSERT(n <= width);
363 width -= n;
364 row += 2;
365 }
366 // now skip whole runs of zeros
367 do {
368 row -= 2;
369 SkASSERT(0 == row[1]);
370 int n = row[0];
371 SkASSERT(n > 0);
372 if (n > riteZ) {
373 row[0] = n - riteZ;
374 break;
375 }
376 riteZ -= n;
377 SkASSERT(riteZ >= 0);
378 } while (riteZ > 0);
379 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000380
reed@google.comc9041912011-10-27 16:58:46 +0000381 return trim;
382}
383
384#ifdef SK_DEBUG
385// assert that this row is exactly this width
reed@google.comc5507bf2011-10-27 21:15:36 +0000386static void assert_row_width(const uint8_t* row, int width) {
reed@google.comc9041912011-10-27 16:58:46 +0000387 while (width > 0) {
388 int n = row[0];
389 SkASSERT(n > 0);
390 SkASSERT(n <= width);
391 width -= n;
392 row += 2;
393 }
394 SkASSERT(0 == width);
395}
396
397static void test_trim_row_left_right() {
398 static bool gOnce;
399 if (gOnce) {
400 return;
401 }
402 gOnce = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000403
reed@google.comc9041912011-10-27 16:58:46 +0000404 uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF };
405 uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF };
406 uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
407 uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
408 uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
409 uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
410 uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
411 uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
412 uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
413 uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
414 uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000415
reed@google.comc9041912011-10-27 16:58:46 +0000416 uint8_t* array[] = {
417 data0, data1, data2, data3, data4,
418 data5, data6, data7, data8, data9,
419 data10
420 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000421
reed@google.comc9041912011-10-27 16:58:46 +0000422 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
423 uint8_t* data = array[i];
424 const int trimL = *data++;
425 const int trimR = *data++;
426 const int expectedSkip = *data++;
427 const int origWidth = *data++;
428 assert_row_width(data, origWidth);
429 int skip = trim_row_left_right(data, origWidth, trimL, trimR);
430 SkASSERT(expectedSkip == skip);
431 int expectedWidth = origWidth - trimL - trimR;
432 assert_row_width(data + skip, expectedWidth);
433 }
434}
435#endif
436
437bool SkAAClip::trimLeftRight() {
438 SkDEBUGCODE(test_trim_row_left_right();)
439
440 if (this->isEmpty()) {
441 return false;
442 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000443
reed@google.comc9041912011-10-27 16:58:46 +0000444 AUTO_AACLIP_VALIDATE(*this);
445
446 const int width = fBounds.width();
447 RunHead* head = fRunHead;
448 YOffset* yoff = head->yoffsets();
449 YOffset* stop = yoff + head->fRowCount;
450 uint8_t* base = head->data();
451
robertphillips@google.com768fee82012-08-02 12:42:43 +0000452 // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum
453 // number of zeros on the left and right of the clip. This information
454 // can be used to shrink the bounding box.
reed@google.comc9041912011-10-27 16:58:46 +0000455 int leftZeros = width;
456 int riteZeros = width;
457 while (yoff < stop) {
458 int L, R;
459 count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000460 SkASSERT(L + R < width || (L == width && R == width));
reed@google.comc9041912011-10-27 16:58:46 +0000461 if (L < leftZeros) {
462 leftZeros = L;
463 }
464 if (R < riteZeros) {
465 riteZeros = R;
466 }
467 if (0 == (leftZeros | riteZeros)) {
468 // no trimming to do
469 return true;
470 }
471 yoff += 1;
472 }
473
474 SkASSERT(leftZeros || riteZeros);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000475 if (width == leftZeros) {
476 SkASSERT(width == riteZeros);
reed@google.comc9041912011-10-27 16:58:46 +0000477 return this->setEmpty();
478 }
479
480 this->validate();
481
482 fBounds.fLeft += leftZeros;
483 fBounds.fRight -= riteZeros;
484 SkASSERT(!fBounds.isEmpty());
485
486 // For now we don't realloc the storage (for time), we just shrink in place
487 // This means we don't have to do any memmoves either, since we can just
488 // play tricks with the yoff->fOffset for each row
489 yoff = head->yoffsets();
490 while (yoff < stop) {
491 uint8_t* row = base + yoff->fOffset;
492 SkDEBUGCODE((void)compute_row_length(row, width);)
493 yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
494 SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
495 yoff += 1;
496 }
497 return true;
498}
499
500static bool row_is_all_zeros(const uint8_t* row, int width) {
501 SkASSERT(width > 0);
502 do {
503 if (row[1]) {
504 return false;
505 }
506 int n = row[0];
507 SkASSERT(n <= width);
508 width -= n;
509 row += 2;
510 } while (width > 0);
511 SkASSERT(0 == width);
512 return true;
513}
514
515bool SkAAClip::trimTopBottom() {
516 if (this->isEmpty()) {
517 return false;
518 }
519
reed@google.comd6040f62011-10-28 02:39:17 +0000520 this->validate();
521
reed@google.comc9041912011-10-27 16:58:46 +0000522 const int width = fBounds.width();
523 RunHead* head = fRunHead;
524 YOffset* yoff = head->yoffsets();
525 YOffset* stop = yoff + head->fRowCount;
526 const uint8_t* base = head->data();
527
528 // Look to trim away empty rows from the top.
529 //
530 int skip = 0;
531 while (yoff < stop) {
532 const uint8_t* data = base + yoff->fOffset;
533 if (!row_is_all_zeros(data, width)) {
534 break;
535 }
536 skip += 1;
537 yoff += 1;
538 }
539 SkASSERT(skip <= head->fRowCount);
540 if (skip == head->fRowCount) {
541 return this->setEmpty();
542 }
543 if (skip > 0) {
544 // adjust fRowCount and fBounds.fTop, and slide all the data up
545 // as we remove [skip] number of YOffset entries
546 yoff = head->yoffsets();
547 int dy = yoff[skip - 1].fY + 1;
548 for (int i = skip; i < head->fRowCount; ++i) {
549 SkASSERT(yoff[i].fY >= dy);
550 yoff[i].fY -= dy;
551 }
552 YOffset* dst = head->yoffsets();
553 size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
554 memmove(dst, dst + skip, size - skip * sizeof(YOffset));
555
556 fBounds.fTop += dy;
557 SkASSERT(!fBounds.isEmpty());
558 head->fRowCount -= skip;
559 SkASSERT(head->fRowCount > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000560
reed@google.comd6040f62011-10-28 02:39:17 +0000561 this->validate();
562 // need to reset this after the memmove
563 base = head->data();
reed@google.comc9041912011-10-27 16:58:46 +0000564 }
565
566 // Look to trim away empty rows from the bottom.
567 // We know that we have at least one non-zero row, so we can just walk
568 // backwards without checking for running past the start.
569 //
570 stop = yoff = head->yoffsets() + head->fRowCount;
571 do {
572 yoff -= 1;
573 } while (row_is_all_zeros(base + yoff->fOffset, width));
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +0000574 skip = SkToInt(stop - yoff - 1);
reed@google.comc9041912011-10-27 16:58:46 +0000575 SkASSERT(skip >= 0 && skip < head->fRowCount);
576 if (skip > 0) {
577 // removing from the bottom is easier than from the top, as we don't
578 // have to adjust any of the Y values, we just have to trim the array
579 memmove(stop - skip, stop, head->fDataSize);
580
581 fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
582 SkASSERT(!fBounds.isEmpty());
583 head->fRowCount -= skip;
584 SkASSERT(head->fRowCount > 0);
585 }
reed@google.comd6040f62011-10-28 02:39:17 +0000586 this->validate();
reed@google.comc9041912011-10-27 16:58:46 +0000587
588 return true;
589}
590
reed@google.com045e62d2011-10-24 12:19:46 +0000591// can't validate before we're done, since trimming is part of the process of
592// making us valid after the Builder. Since we build from top to bottom, its
593// possible our fBounds.fBottom is bigger than our last scanline of data, so
594// we trim fBounds.fBottom back up.
595//
reed@google.com045e62d2011-10-24 12:19:46 +0000596// TODO: check for duplicates in X and Y to further compress our data
597//
598bool SkAAClip::trimBounds() {
599 if (this->isEmpty()) {
600 return false;
601 }
602
603 const RunHead* head = fRunHead;
604 const YOffset* yoff = head->yoffsets();
605
606 SkASSERT(head->fRowCount > 0);
607 const YOffset& lastY = yoff[head->fRowCount - 1];
608 SkASSERT(lastY.fY + 1 <= fBounds.height());
609 fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
610 SkASSERT(lastY.fY + 1 == fBounds.height());
reed@google.comc9041912011-10-27 16:58:46 +0000611 SkASSERT(!fBounds.isEmpty());
612
613 return this->trimTopBottom() && this->trimLeftRight();
reed@google.com045e62d2011-10-24 12:19:46 +0000614}
615
reed@google.come36707a2011-10-04 21:38:55 +0000616///////////////////////////////////////////////////////////////////////////////
617
618void SkAAClip::freeRuns() {
reed@google.com47ac84e2011-10-06 13:11:25 +0000619 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000620 SkASSERT(fRunHead->fRefCnt >= 1);
621 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
622 sk_free(fRunHead);
623 }
624 }
625}
626
627SkAAClip::SkAAClip() {
628 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700629 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000630}
631
632SkAAClip::SkAAClip(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000633 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
halcanary96fcdcc2015-08-27 07:41:13 -0700634 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000635 *this = src;
636}
637
638SkAAClip::~SkAAClip() {
639 this->freeRuns();
640}
641
642SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000643 AUTO_AACLIP_VALIDATE(*this);
644 src.validate();
645
reed@google.come36707a2011-10-04 21:38:55 +0000646 if (this != &src) {
647 this->freeRuns();
648 fBounds = src.fBounds;
649 fRunHead = src.fRunHead;
reed@google.com47ac84e2011-10-06 13:11:25 +0000650 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000651 sk_atomic_inc(&fRunHead->fRefCnt);
652 }
653 }
654 return *this;
655}
656
657bool operator==(const SkAAClip& a, const SkAAClip& b) {
reed@google.com045e62d2011-10-24 12:19:46 +0000658 a.validate();
659 b.validate();
660
reed@google.come36707a2011-10-04 21:38:55 +0000661 if (&a == &b) {
662 return true;
663 }
664 if (a.fBounds != b.fBounds) {
665 return false;
666 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000667
reed@google.come36707a2011-10-04 21:38:55 +0000668 const SkAAClip::RunHead* ah = a.fRunHead;
669 const SkAAClip::RunHead* bh = b.fRunHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000670
reed@google.come36707a2011-10-04 21:38:55 +0000671 // this catches empties and rects being equal
672 if (ah == bh) {
673 return true;
674 }
675
676 // now we insist that both are complex (but different ptrs)
reed@google.com47ac84e2011-10-06 13:11:25 +0000677 if (!a.fRunHead || !b.fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000678 return false;
679 }
680
681 return ah->fRowCount == bh->fRowCount &&
682 ah->fDataSize == bh->fDataSize &&
683 !memcmp(ah->data(), bh->data(), ah->fDataSize);
684}
685
686void SkAAClip::swap(SkAAClip& other) {
reed@google.com045e62d2011-10-24 12:19:46 +0000687 AUTO_AACLIP_VALIDATE(*this);
688 other.validate();
689
reed@google.come36707a2011-10-04 21:38:55 +0000690 SkTSwap(fBounds, other.fBounds);
691 SkTSwap(fRunHead, other.fRunHead);
692}
693
reed@google.com32287892011-10-05 16:27:44 +0000694bool SkAAClip::set(const SkAAClip& src) {
695 *this = src;
696 return !this->isEmpty();
697}
698
reed@google.come36707a2011-10-04 21:38:55 +0000699bool SkAAClip::setEmpty() {
700 this->freeRuns();
701 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700702 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000703 return false;
704}
705
706bool SkAAClip::setRect(const SkIRect& bounds) {
Mike Reeda766ca92018-01-09 11:31:53 -0500707 if (bounds.isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000708 return this->setEmpty();
709 }
reed@google.com47ac84e2011-10-06 13:11:25 +0000710
reed@google.com045e62d2011-10-24 12:19:46 +0000711 AUTO_AACLIP_VALIDATE(*this);
reed@google.com47ac84e2011-10-06 13:11:25 +0000712
reed@google.com045e62d2011-10-24 12:19:46 +0000713#if 0
reed@google.com47ac84e2011-10-06 13:11:25 +0000714 SkRect r;
715 r.set(bounds);
716 SkPath path;
717 path.addRect(r);
718 return this->setPath(path);
reed@google.com045e62d2011-10-24 12:19:46 +0000719#else
720 this->freeRuns();
721 fBounds = bounds;
722 fRunHead = RunHead::AllocRect(bounds);
723 SkASSERT(!this->isEmpty());
724 return true;
725#endif
reed@google.come36707a2011-10-04 21:38:55 +0000726}
727
reed202ab2a2014-08-07 11:48:10 -0700728bool SkAAClip::isRect() const {
729 if (this->isEmpty()) {
730 return false;
731 }
732
733 const RunHead* head = fRunHead;
734 if (head->fRowCount != 1) {
735 return false;
736 }
737 const YOffset* yoff = head->yoffsets();
738 if (yoff->fY != fBounds.fBottom - 1) {
739 return false;
740 }
741
742 const uint8_t* row = head->data() + yoff->fOffset;
743 int width = fBounds.width();
744 do {
745 if (row[1] != 0xFF) {
746 return false;
747 }
748 int n = row[0];
749 SkASSERT(n <= width);
750 width -= n;
751 row += 2;
752 } while (width > 0);
753 return true;
754}
755
reed@google.comf3c1da12011-10-10 19:35:47 +0000756bool SkAAClip::setRect(const SkRect& r, bool doAA) {
reed@google.come36707a2011-10-04 21:38:55 +0000757 if (r.isEmpty()) {
758 return this->setEmpty();
759 }
760
reed@google.com045e62d2011-10-24 12:19:46 +0000761 AUTO_AACLIP_VALIDATE(*this);
762
763 // TODO: special case this
764
reed@google.come36707a2011-10-04 21:38:55 +0000765 SkPath path;
766 path.addRect(r);
halcanary96fcdcc2015-08-27 07:41:13 -0700767 return this->setPath(path, nullptr, doAA);
reed@google.comf3c1da12011-10-10 19:35:47 +0000768}
769
reed@google.coma069c8f2011-11-28 19:54:56 +0000770static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
771 SkASSERT(count >= 0);
772 while (count > 0) {
773 int n = count;
774 if (n > 255) {
775 n = 255;
776 }
777 uint8_t* data = array.append(2);
778 data[0] = n;
779 data[1] = value;
780 count -= n;
781 }
782}
783
reed@google.comf3c1da12011-10-10 19:35:47 +0000784bool SkAAClip::setRegion(const SkRegion& rgn) {
785 if (rgn.isEmpty()) {
786 return this->setEmpty();
787 }
788 if (rgn.isRect()) {
789 return this->setRect(rgn.getBounds());
790 }
reed@google.coma069c8f2011-11-28 19:54:56 +0000791
792#if 0
reed@google.comf3c1da12011-10-10 19:35:47 +0000793 SkAAClip clip;
794 SkRegion::Iterator iter(rgn);
795 for (; !iter.done(); iter.next()) {
796 clip.op(iter.rect(), SkRegion::kUnion_Op);
797 }
798 this->swap(clip);
reed@google.com3771a032011-10-11 17:18:04 +0000799 return !this->isEmpty();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000800#else
reed@google.coma069c8f2011-11-28 19:54:56 +0000801 const SkIRect& bounds = rgn.getBounds();
802 const int offsetX = bounds.fLeft;
803 const int offsetY = bounds.fTop;
804
805 SkTDArray<YOffset> yArray;
806 SkTDArray<uint8_t> xArray;
807
808 yArray.setReserve(SkMin32(bounds.height(), 1024));
Mike Reede0673952017-10-04 16:46:42 -0400809 xArray.setReserve(SkMin32(bounds.width(), 512) * 128);
reed@google.coma069c8f2011-11-28 19:54:56 +0000810
811 SkRegion::Iterator iter(rgn);
812 int prevRight = 0;
813 int prevBot = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700814 YOffset* currY = nullptr;
reed@google.coma069c8f2011-11-28 19:54:56 +0000815
816 for (; !iter.done(); iter.next()) {
817 const SkIRect& r = iter.rect();
818 SkASSERT(bounds.contains(r));
819
820 int bot = r.fBottom - offsetY;
821 SkASSERT(bot >= prevBot);
822 if (bot > prevBot) {
823 if (currY) {
824 // flush current row
825 append_run(xArray, 0, bounds.width() - prevRight);
826 }
827 // did we introduce an empty-gap from the prev row?
828 int top = r.fTop - offsetY;
829 if (top > prevBot) {
830 currY = yArray.append();
831 currY->fY = top - 1;
832 currY->fOffset = xArray.count();
833 append_run(xArray, 0, bounds.width());
834 }
835 // create a new record for this Y value
836 currY = yArray.append();
837 currY->fY = bot - 1;
838 currY->fOffset = xArray.count();
839 prevRight = 0;
840 prevBot = bot;
841 }
842
843 int x = r.fLeft - offsetX;
844 append_run(xArray, 0, x - prevRight);
845
846 int w = r.fRight - r.fLeft;
847 append_run(xArray, 0xFF, w);
848 prevRight = x + w;
849 SkASSERT(prevRight <= bounds.width());
850 }
851 // flush last row
852 append_run(xArray, 0, bounds.width() - prevRight);
853
854 // now pack everything into a RunHead
855 RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
856 memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
857 memcpy(head->data(), xArray.begin(), xArray.bytes());
858
859 this->setEmpty();
860 fBounds = bounds;
861 fRunHead = head;
862 this->validate();
863 return true;
864#endif
reed@google.come36707a2011-10-04 21:38:55 +0000865}
866
867///////////////////////////////////////////////////////////////////////////////
868
869const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000870 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000871
872 if (!y_in_rect(y, fBounds)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700873 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000874 }
875 y -= fBounds.y(); // our yoffs values are relative to the top
876
877 const YOffset* yoff = fRunHead->yoffsets();
878 while (yoff->fY < y) {
879 yoff += 1;
880 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
881 }
882
883 if (lastYForRow) {
reed@google.com045e62d2011-10-24 12:19:46 +0000884 *lastYForRow = fBounds.y() + yoff->fY;
reed@google.come36707a2011-10-04 21:38:55 +0000885 }
886 return fRunHead->data() + yoff->fOffset;
887}
888
889const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
890 SkASSERT(x_in_rect(x, fBounds));
891 x -= fBounds.x();
892
893 // first skip up to X
894 for (;;) {
895 int n = data[0];
896 if (x < n) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000897 if (initialCount) {
898 *initialCount = n - x;
899 }
reed@google.come36707a2011-10-04 21:38:55 +0000900 break;
901 }
902 data += 2;
903 x -= n;
904 }
905 return data;
906}
907
908bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
909 if (this->isEmpty()) {
910 return false;
911 }
912 if (!fBounds.contains(left, top, right, bottom)) {
913 return false;
914 }
reed@google.com32287892011-10-05 16:27:44 +0000915#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000916 if (this->isRect()) {
917 return true;
918 }
reed@google.com32287892011-10-05 16:27:44 +0000919#endif
reed@google.come36707a2011-10-04 21:38:55 +0000920
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000921 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +0000922 const uint8_t* row = this->findRow(top, &lastY);
923 if (lastY < bottom) {
924 return false;
925 }
926 // now just need to check in X
reed@google.com045e62d2011-10-24 12:19:46 +0000927 int count;
928 row = this->findX(row, left, &count);
929#if 0
930 return count >= (right - left) && 0xFF == row[1];
931#else
932 int rectWidth = right - left;
933 while (0xFF == row[1]) {
934 if (count >= rectWidth) {
935 return true;
936 }
937 rectWidth -= count;
938 row += 2;
939 count = row[0];
940 }
941 return false;
942#endif
reed@google.come36707a2011-10-04 21:38:55 +0000943}
944
945///////////////////////////////////////////////////////////////////////////////
946
947class SkAAClip::Builder {
948 SkIRect fBounds;
949 struct Row {
950 int fY;
951 int fWidth;
952 SkTDArray<uint8_t>* fData;
953 };
954 SkTDArray<Row> fRows;
955 Row* fCurrRow;
956 int fPrevY;
957 int fWidth;
reed@google.com209c4152011-10-26 15:03:48 +0000958 int fMinY;
reed@google.come36707a2011-10-04 21:38:55 +0000959
960public:
961 Builder(const SkIRect& bounds) : fBounds(bounds) {
962 fPrevY = -1;
963 fWidth = bounds.width();
halcanary96fcdcc2015-08-27 07:41:13 -0700964 fCurrRow = nullptr;
reed@google.com209c4152011-10-26 15:03:48 +0000965 fMinY = bounds.fTop;
reed@google.come36707a2011-10-04 21:38:55 +0000966 }
967
968 ~Builder() {
969 Row* row = fRows.begin();
970 Row* stop = fRows.end();
971 while (row < stop) {
972 delete row->fData;
973 row += 1;
974 }
975 }
976
reed@google.com32287892011-10-05 16:27:44 +0000977 const SkIRect& getBounds() const { return fBounds; }
978
reed@google.come36707a2011-10-04 21:38:55 +0000979 void addRun(int x, int y, U8CPU alpha, int count) {
980 SkASSERT(count > 0);
981 SkASSERT(fBounds.contains(x, y));
982 SkASSERT(fBounds.contains(x + count - 1, y));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000983
reed@google.come36707a2011-10-04 21:38:55 +0000984 x -= fBounds.left();
985 y -= fBounds.top();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000986
reed@google.come36707a2011-10-04 21:38:55 +0000987 Row* row = fCurrRow;
988 if (y != fPrevY) {
989 SkASSERT(y > fPrevY);
990 fPrevY = y;
991 row = this->flushRow(true);
992 row->fY = y;
993 row->fWidth = 0;
994 SkASSERT(row->fData);
995 SkASSERT(0 == row->fData->count());
996 fCurrRow = row;
997 }
998
999 SkASSERT(row->fWidth <= x);
1000 SkASSERT(row->fWidth < fBounds.width());
1001
1002 SkTDArray<uint8_t>& data = *row->fData;
1003
1004 int gap = x - row->fWidth;
1005 if (gap) {
1006 AppendRun(data, 0, gap);
1007 row->fWidth += gap;
1008 SkASSERT(row->fWidth < fBounds.width());
1009 }
1010
1011 AppendRun(data, alpha, count);
1012 row->fWidth += count;
1013 SkASSERT(row->fWidth <= fBounds.width());
1014 }
1015
tomhudson@google.com49eac192011-12-27 13:59:20 +00001016 void addColumn(int x, int y, U8CPU alpha, int height) {
1017 SkASSERT(fBounds.contains(x, y + height - 1));
1018
1019 this->addRun(x, y, alpha, 1);
1020 this->flushRowH(fCurrRow);
1021 y -= fBounds.fTop;
1022 SkASSERT(y == fCurrRow->fY);
1023 fCurrRow->fY = y + height - 1;
1024 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001025
reed@google.com9154eb02011-10-31 16:07:28 +00001026 void addRectRun(int x, int y, int width, int height) {
1027 SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
1028 this->addRun(x, y, 0xFF, width);
1029
reed@google.coma89c77b2011-12-01 21:47:26 +00001030 // we assum the rect must be all we'll see for these scanlines
reed@google.com9154eb02011-10-31 16:07:28 +00001031 // so we ensure our row goes all the way to our right
1032 this->flushRowH(fCurrRow);
1033
1034 y -= fBounds.fTop;
1035 SkASSERT(y == fCurrRow->fY);
1036 fCurrRow->fY = y + height - 1;
1037 }
1038
tomhudson@google.com49eac192011-12-27 13:59:20 +00001039 void addAntiRectRun(int x, int y, int width, int height,
1040 SkAlpha leftAlpha, SkAlpha rightAlpha) {
liyuqian2add0ff2016-10-20 11:04:39 -07001041 // According to SkBlitter.cpp, no matter whether leftAlpha is 0 or positive,
1042 // we should always consider [x, x+1] as the left-most column and [x+1, x+1+width]
1043 // as the rect with full alpha.
1044 SkASSERT(fBounds.contains(x + width + (rightAlpha > 0 ? 1 : 0),
tomhudson@google.com49eac192011-12-27 13:59:20 +00001045 y + height - 1));
1046 SkASSERT(width >= 0);
1047
1048 // Conceptually we're always adding 3 runs, but we should
1049 // merge or omit them if possible.
1050 if (leftAlpha == 0xFF) {
1051 width++;
1052 } else if (leftAlpha > 0) {
1053 this->addRun(x++, y, leftAlpha, 1);
liyuqian2add0ff2016-10-20 11:04:39 -07001054 } else {
1055 // leftAlpha is 0, ignore the left column
1056 x++;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001057 }
1058 if (rightAlpha == 0xFF) {
1059 width++;
1060 }
1061 if (width > 0) {
1062 this->addRun(x, y, 0xFF, width);
1063 }
1064 if (rightAlpha > 0 && rightAlpha < 255) {
1065 this->addRun(x + width, y, rightAlpha, 1);
1066 }
1067
Mike Reed1b7cd332018-06-05 09:55:17 -04001068 // if we never called addRun, we might not have a fCurrRow yet
1069 if (fCurrRow) {
1070 // we assume the rect must be all we'll see for these scanlines
1071 // so we ensure our row goes all the way to our right
1072 this->flushRowH(fCurrRow);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001073
Mike Reed1b7cd332018-06-05 09:55:17 -04001074 y -= fBounds.fTop;
1075 SkASSERT(y == fCurrRow->fY);
1076 fCurrRow->fY = y + height - 1;
1077 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001078 }
1079
reed@google.com045e62d2011-10-24 12:19:46 +00001080 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +00001081 this->flushRow(false);
1082
1083 const Row* row = fRows.begin();
1084 const Row* stop = fRows.end();
1085
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001086 size_t dataSize = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001087 while (row < stop) {
1088 dataSize += row->fData->count();
1089 row += 1;
1090 }
1091
reed@google.com045e62d2011-10-24 12:19:46 +00001092 if (0 == dataSize) {
1093 return target->setEmpty();
1094 }
1095
reed@google.com209c4152011-10-26 15:03:48 +00001096 SkASSERT(fMinY >= fBounds.fTop);
1097 SkASSERT(fMinY < fBounds.fBottom);
1098 int adjustY = fMinY - fBounds.fTop;
1099 fBounds.fTop = fMinY;
1100
reed@google.come36707a2011-10-04 21:38:55 +00001101 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
1102 YOffset* yoffset = head->yoffsets();
1103 uint8_t* data = head->data();
1104 uint8_t* baseData = data;
1105
1106 row = fRows.begin();
reed@google.comc9041912011-10-27 16:58:46 +00001107 SkDEBUGCODE(int prevY = row->fY - 1;)
reed@google.come36707a2011-10-04 21:38:55 +00001108 while (row < stop) {
reed@google.comc9041912011-10-27 16:58:46 +00001109 SkASSERT(prevY < row->fY); // must be monotonic
1110 SkDEBUGCODE(prevY = row->fY);
1111
reed@google.com209c4152011-10-26 15:03:48 +00001112 yoffset->fY = row->fY - adjustY;
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001113 yoffset->fOffset = SkToU32(data - baseData);
reed@google.come36707a2011-10-04 21:38:55 +00001114 yoffset += 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001115
reed@google.come36707a2011-10-04 21:38:55 +00001116 size_t n = row->fData->count();
1117 memcpy(data, row->fData->begin(), n);
reed@google.comc9041912011-10-27 16:58:46 +00001118#ifdef SK_DEBUG
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001119 size_t bytesNeeded = compute_row_length(data, fBounds.width());
reed@google.comc9041912011-10-27 16:58:46 +00001120 SkASSERT(bytesNeeded == n);
1121#endif
reed@google.come36707a2011-10-04 21:38:55 +00001122 data += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001123
reed@google.come36707a2011-10-04 21:38:55 +00001124 row += 1;
1125 }
1126
reed@google.com045e62d2011-10-24 12:19:46 +00001127 target->freeRuns();
1128 target->fBounds = fBounds;
1129 target->fRunHead = head;
1130 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +00001131 }
1132
1133 void dump() {
1134 this->validate();
1135 int y;
1136 for (y = 0; y < fRows.count(); ++y) {
1137 const Row& row = fRows[y];
1138 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
1139 const SkTDArray<uint8_t>& data = *row.fData;
1140 int count = data.count();
1141 SkASSERT(!(count & 1));
1142 const uint8_t* ptr = data.begin();
1143 for (int x = 0; x < count; x += 2) {
1144 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
1145 ptr += 2;
1146 }
1147 SkDebugf("\n");
1148 }
reed@google.come36707a2011-10-04 21:38:55 +00001149 }
1150
1151 void validate() {
1152#ifdef SK_DEBUG
caryclark@google.com803eceb2012-06-06 12:09:34 +00001153 if (false) { // avoid bit rot, suppress warning
1154 test_count_left_right_zeros();
1155 }
reed@google.come36707a2011-10-04 21:38:55 +00001156 int prevY = -1;
1157 for (int i = 0; i < fRows.count(); ++i) {
1158 const Row& row = fRows[i];
1159 SkASSERT(prevY < row.fY);
1160 SkASSERT(fWidth == row.fWidth);
1161 int count = row.fData->count();
1162 const uint8_t* ptr = row.fData->begin();
1163 SkASSERT(!(count & 1));
1164 int w = 0;
1165 for (int x = 0; x < count; x += 2) {
reed@google.comd6040f62011-10-28 02:39:17 +00001166 int n = ptr[0];
1167 SkASSERT(n > 0);
1168 w += n;
reed@google.come36707a2011-10-04 21:38:55 +00001169 SkASSERT(w <= fWidth);
1170 ptr += 2;
1171 }
1172 SkASSERT(w == fWidth);
1173 prevY = row.fY;
1174 }
1175#endif
1176 }
1177
reed@google.com209c4152011-10-26 15:03:48 +00001178 // only called by BuilderBlitter
1179 void setMinY(int y) {
1180 fMinY = y;
1181 }
1182
reed@google.come36707a2011-10-04 21:38:55 +00001183private:
reed@google.com9154eb02011-10-31 16:07:28 +00001184 void flushRowH(Row* row) {
1185 // flush current row if needed
1186 if (row->fWidth < fWidth) {
1187 AppendRun(*row->fData, 0, fWidth - row->fWidth);
1188 row->fWidth = fWidth;
1189 }
1190 }
reed@google.com209c4152011-10-26 15:03:48 +00001191
reed@google.come36707a2011-10-04 21:38:55 +00001192 Row* flushRow(bool readyForAnother) {
halcanary96fcdcc2015-08-27 07:41:13 -07001193 Row* next = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001194 int count = fRows.count();
1195 if (count > 0) {
reed@google.com9154eb02011-10-31 16:07:28 +00001196 this->flushRowH(&fRows[count - 1]);
reed@google.come36707a2011-10-04 21:38:55 +00001197 }
1198 if (count > 1) {
1199 // are our last two runs the same?
1200 Row* prev = &fRows[count - 2];
1201 Row* curr = &fRows[count - 1];
1202 SkASSERT(prev->fWidth == fWidth);
1203 SkASSERT(curr->fWidth == fWidth);
1204 if (*prev->fData == *curr->fData) {
1205 prev->fY = curr->fY;
1206 if (readyForAnother) {
1207 curr->fData->rewind();
1208 next = curr;
1209 } else {
1210 delete curr->fData;
1211 fRows.removeShuffle(count - 1);
1212 }
1213 } else {
1214 if (readyForAnother) {
1215 next = fRows.append();
1216 next->fData = new SkTDArray<uint8_t>;
1217 }
1218 }
1219 } else {
1220 if (readyForAnother) {
1221 next = fRows.append();
1222 next->fData = new SkTDArray<uint8_t>;
1223 }
1224 }
1225 return next;
1226 }
1227
1228 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
1229 do {
1230 int n = count;
1231 if (n > 255) {
1232 n = 255;
1233 }
1234 uint8_t* ptr = data.append(2);
1235 ptr[0] = n;
1236 ptr[1] = alpha;
1237 count -= n;
1238 } while (count > 0);
1239 }
1240};
1241
1242class SkAAClip::BuilderBlitter : public SkBlitter {
reed@google.com80cdb9a2012-02-16 18:56:17 +00001243 int fLastY;
1244
1245 /*
1246 If we see a gap of 1 or more empty scanlines while building in Y-order,
1247 we inject an explicit empty scanline (alpha==0)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001248
reed@google.com80cdb9a2012-02-16 18:56:17 +00001249 See AAClipTest.cpp : test_path_with_hole()
1250 */
1251 void checkForYGap(int y) {
1252 SkASSERT(y >= fLastY);
1253 if (fLastY > -SK_MaxS32) {
1254 int gap = y - fLastY;
1255 if (gap > 1) {
1256 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
1257 }
1258 }
1259 fLastY = y;
1260 }
1261
reed@google.come36707a2011-10-04 21:38:55 +00001262public:
reed@google.com80cdb9a2012-02-16 18:56:17 +00001263
reed@google.come36707a2011-10-04 21:38:55 +00001264 BuilderBlitter(Builder* builder) {
1265 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001266 fLeft = builder->getBounds().fLeft;
1267 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001268 fMinY = SK_MaxS32;
reed@google.com80cdb9a2012-02-16 18:56:17 +00001269 fLastY = -SK_MaxS32; // sentinel
reed@google.com209c4152011-10-26 15:03:48 +00001270 }
1271
1272 void finish() {
1273 if (fMinY < SK_MaxS32) {
1274 fBuilder->setMinY(fMinY);
1275 }
reed@google.come36707a2011-10-04 21:38:55 +00001276 }
1277
tomhudson@google.com49eac192011-12-27 13:59:20 +00001278 /**
1279 Must evaluate clips in scan-line order, so don't want to allow blitV(),
1280 but an AAClip can be clipped down to a single pixel wide, so we
1281 must support it (given AntiRect semantics: minimum width is 2).
1282 Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
1283 any failure cases that misses may have minor artifacts.
1284 */
mtklein36352bf2015-03-25 18:17:31 -07001285 void blitV(int x, int y, int height, SkAlpha alpha) override {
liyuqian2add0ff2016-10-20 11:04:39 -07001286 if (height == 1) {
1287 // We're still in scan-line order if height is 1
1288 // This is useful for Analytic AA
1289 const SkAlpha alphas[2] = {alpha, 0};
1290 const int16_t runs[2] = {1, 0};
1291 this->blitAntiH(x, y, alphas, runs);
1292 } else {
1293 this->recordMinY(y);
1294 fBuilder->addColumn(x, y, alpha, height);
1295 fLastY = y + height - 1;
1296 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001297 }
reed@google.com045e62d2011-10-24 12:19:46 +00001298
mtklein36352bf2015-03-25 18:17:31 -07001299 void blitRect(int x, int y, int width, int height) override {
reed@google.com9154eb02011-10-31 16:07:28 +00001300 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001301 this->checkForYGap(y);
reed@google.com9154eb02011-10-31 16:07:28 +00001302 fBuilder->addRectRun(x, y, width, height);
reed@google.com302b8612012-02-16 19:30:13 +00001303 fLastY = y + height - 1;
reed@google.com562a2ac2011-10-31 14:14:18 +00001304 }
reed@google.com045e62d2011-10-24 12:19:46 +00001305
tomhudson@google.com49eac192011-12-27 13:59:20 +00001306 virtual void blitAntiRect(int x, int y, int width, int height,
mtklein36352bf2015-03-25 18:17:31 -07001307 SkAlpha leftAlpha, SkAlpha rightAlpha) override {
tomhudson@google.com49eac192011-12-27 13:59:20 +00001308 this->recordMinY(y);
reed@google.com302b8612012-02-16 19:30:13 +00001309 this->checkForYGap(y);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001310 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
reed@google.com302b8612012-02-16 19:30:13 +00001311 fLastY = y + height - 1;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001312 }
1313
mtklein36352bf2015-03-25 18:17:31 -07001314 void blitMask(const SkMask&, const SkIRect& clip) override
reed@google.come36707a2011-10-04 21:38:55 +00001315 { unexpected(); }
1316
reed41e010c2015-06-09 12:16:53 -07001317 const SkPixmap* justAnOpaqueColor(uint32_t*) override {
halcanary96fcdcc2015-08-27 07:41:13 -07001318 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001319 }
1320
mtklein36352bf2015-03-25 18:17:31 -07001321 void blitH(int x, int y, int width) override {
reed@google.com209c4152011-10-26 15:03:48 +00001322 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001323 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001324 fBuilder->addRun(x, y, 0xFF, width);
1325 }
1326
1327 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
mtklein36352bf2015-03-25 18:17:31 -07001328 const int16_t runs[]) override {
reed@google.com209c4152011-10-26 15:03:48 +00001329 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001330 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001331 for (;;) {
1332 int count = *runs;
1333 if (count <= 0) {
1334 return;
1335 }
reed@google.com17785642011-10-12 20:23:55 +00001336
1337 // The supersampler's buffer can be the width of the device, so
liyuqian1d3ab122016-11-08 13:55:15 -08001338 // we may have to trim the run to our bounds. Previously, we assert that
1339 // the extra spans are always alpha==0.
1340 // However, the analytic AA is too sensitive to precision errors
1341 // so it may have extra spans with very tiny alpha because after several
1342 // arithmatic operations, the edge may bleed the path boundary a little bit.
1343 // Therefore, instead of always asserting alpha==0, we assert alpha < 0x10.
reed@google.com17785642011-10-12 20:23:55 +00001344 int localX = x;
1345 int localCount = count;
1346 if (x < fLeft) {
liyuqian1d3ab122016-11-08 13:55:15 -08001347 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001348 int gap = fLeft - x;
1349 SkASSERT(gap <= count);
1350 localX += gap;
1351 localCount -= gap;
1352 }
1353 int right = x + count;
1354 if (right > fRight) {
liyuqian1d3ab122016-11-08 13:55:15 -08001355 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001356 localCount -= right - fRight;
1357 SkASSERT(localCount >= 0);
1358 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001359
reed@google.com17785642011-10-12 20:23:55 +00001360 if (localCount) {
1361 fBuilder->addRun(localX, y, *alpha, localCount);
1362 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001363 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001364 runs += count;
1365 alpha += count;
1366 x += count;
1367 }
1368 }
1369
1370private:
1371 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001372 int fLeft; // cache of builder's bounds' left edge
1373 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001374 int fMinY;
1375
1376 /*
1377 * We track this, in case the scan converter skipped some number of
1378 * scanlines at the (relative to the bounds it was given). This allows
1379 * the builder, during its finish, to trip its bounds down to the "real"
1380 * top.
1381 */
1382 void recordMinY(int y) {
1383 if (y < fMinY) {
1384 fMinY = y;
1385 }
1386 }
reed@google.come36707a2011-10-04 21:38:55 +00001387
1388 void unexpected() {
Ben Wagner7ca9a742017-08-17 14:05:04 -04001389 SK_ABORT("---- did not expect to get called here");
reed@google.come36707a2011-10-04 21:38:55 +00001390 }
1391};
1392
reed@google.comf3c1da12011-10-10 19:35:47 +00001393bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001394 AUTO_AACLIP_VALIDATE(*this);
1395
reed@google.com32287892011-10-05 16:27:44 +00001396 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001397 return this->setEmpty();
1398 }
1399
1400 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001401 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001402
reed@google.com32287892011-10-05 16:27:44 +00001403 SkRegion tmpClip;
halcanary96fcdcc2015-08-27 07:41:13 -07001404 if (nullptr == clip) {
reed@google.com32287892011-10-05 16:27:44 +00001405 tmpClip.setRect(ibounds);
1406 clip = &tmpClip;
1407 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001408
Yuqian Lica85fc32016-11-10 09:44:55 -05001409 // Since we assert that the BuilderBlitter will never blit outside the intersection
1410 // of clip and ibounds, we create this snugClip to be that intersection and send it
1411 // to the scan-converter.
1412 SkRegion snugClip(*clip);
1413
reed@google.com045e62d2011-10-24 12:19:46 +00001414 if (path.isInverseFillType()) {
1415 ibounds = clip->getBounds();
1416 } else {
reed@google.com32287892011-10-05 16:27:44 +00001417 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001418 return this->setEmpty();
1419 }
Yuqian Lica85fc32016-11-10 09:44:55 -05001420 snugClip.op(ibounds, SkRegion::kIntersect_Op);
reed@google.come36707a2011-10-04 21:38:55 +00001421 }
1422
1423 Builder builder(ibounds);
1424 BuilderBlitter blitter(&builder);
1425
reed@google.comf3c1da12011-10-10 19:35:47 +00001426 if (doAA) {
Yuqian Li7d99dad2017-07-26 13:47:26 -04001427 SkScan::AntiFillPath(path, snugClip, &blitter, true);
reed@google.comf3c1da12011-10-10 19:35:47 +00001428 } else {
Yuqian Lica85fc32016-11-10 09:44:55 -05001429 SkScan::FillPath(path, snugClip, &blitter);
reed@google.comf3c1da12011-10-10 19:35:47 +00001430 }
reed@google.come36707a2011-10-04 21:38:55 +00001431
reed@google.com209c4152011-10-26 15:03:48 +00001432 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001433 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001434}
1435
1436///////////////////////////////////////////////////////////////////////////////
1437
reed@google.com32287892011-10-05 16:27:44 +00001438typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1439 const uint8_t* rowA, const SkIRect& rectA,
1440 const uint8_t* rowB, const SkIRect& rectB);
1441
reed@google.com32287892011-10-05 16:27:44 +00001442typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1443
1444static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1445 // Multiply
1446 return SkMulDiv255Round(alphaA, alphaB);
1447}
1448
1449static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1450 // SrcOver
1451 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1452}
1453
1454static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1455 // SrcOut
1456 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1457}
1458
1459static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1460 // XOR
1461 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1462}
1463
1464static AlphaProc find_alpha_proc(SkRegion::Op op) {
1465 switch (op) {
1466 case SkRegion::kIntersect_Op:
1467 return sectAlphaProc;
1468 case SkRegion::kDifference_Op:
1469 return diffAlphaProc;
1470 case SkRegion::kUnion_Op:
1471 return unionAlphaProc;
1472 case SkRegion::kXOR_Op:
1473 return xorAlphaProc;
1474 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001475 SkDEBUGFAIL("unexpected region op");
reed@google.com32287892011-10-05 16:27:44 +00001476 return sectAlphaProc;
1477 }
1478}
1479
reed@google.com32287892011-10-05 16:27:44 +00001480class RowIter {
1481public:
1482 RowIter(const uint8_t* row, const SkIRect& bounds) {
1483 fRow = row;
1484 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001485 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001486 if (row) {
1487 fRight = bounds.fLeft + row[0];
1488 SkASSERT(fRight <= fBoundsRight);
1489 fAlpha = row[1];
1490 fDone = false;
1491 } else {
1492 fDone = true;
1493 fRight = kMaxInt32;
1494 fAlpha = 0;
1495 }
reed@google.com32287892011-10-05 16:27:44 +00001496 }
1497
1498 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001499 int left() const { return fLeft; }
1500 int right() const { return fRight; }
1501 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001502 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001503 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001504 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001505 if (fRight == fBoundsRight) {
1506 fDone = true;
1507 fRight = kMaxInt32;
1508 fAlpha = 0;
1509 } else {
1510 fRow += 2;
1511 fRight += fRow[0];
1512 fAlpha = fRow[1];
1513 SkASSERT(fRight <= fBoundsRight);
1514 }
reed@google.com32287892011-10-05 16:27:44 +00001515 }
1516 }
1517
1518private:
1519 const uint8_t* fRow;
1520 int fLeft;
1521 int fRight;
1522 int fBoundsRight;
1523 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001524 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001525};
1526
reed@google.com1c04bf92011-10-10 12:57:12 +00001527static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1528 if (rite == riteA) {
1529 iter.next();
1530 leftA = iter.left();
1531 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001532 }
1533}
1534
caryclark@google.com803eceb2012-06-06 12:09:34 +00001535#if 0 // UNUSED
reed@google.com1c04bf92011-10-10 12:57:12 +00001536static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1537 SkASSERT(min < max);
1538 SkASSERT(boundsMin < boundsMax);
1539 if (min >= boundsMax || max <= boundsMin) {
1540 return false;
1541 }
1542 if (min < boundsMin) {
1543 min = boundsMin;
1544 }
1545 if (max > boundsMax) {
1546 max = boundsMax;
1547 }
1548 return true;
1549}
caryclark@google.com803eceb2012-06-06 12:09:34 +00001550#endif
reed@google.com1c04bf92011-10-10 12:57:12 +00001551
reed@google.com32287892011-10-05 16:27:44 +00001552static void operatorX(SkAAClip::Builder& builder, int lastY,
1553 RowIter& iterA, RowIter& iterB,
1554 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001555 int leftA = iterA.left();
1556 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001557 int leftB = iterB.left();
1558 int riteB = iterB.right();
1559
reed@google.com1c04bf92011-10-10 12:57:12 +00001560 int prevRite = bounds.fLeft;
1561
1562 do {
reed@google.com32287892011-10-05 16:27:44 +00001563 U8CPU alphaA = 0;
1564 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001565 int left, rite;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001566
reed@google.com1c04bf92011-10-10 12:57:12 +00001567 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001568 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001569 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001570 if (riteA <= leftB) {
1571 rite = riteA;
1572 } else {
1573 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001574 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001575 } else if (leftB < leftA) {
1576 left = leftB;
1577 alphaB = iterB.alpha();
1578 if (riteB <= leftA) {
1579 rite = riteB;
1580 } else {
1581 rite = leftB = leftA;
1582 }
1583 } else {
1584 left = leftA; // or leftB, since leftA == leftB
1585 rite = leftA = leftB = SkMin32(riteA, riteB);
1586 alphaA = iterA.alpha();
1587 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001588 }
1589
1590 if (left >= bounds.fRight) {
1591 break;
1592 }
reed@google.com34f7e472011-10-13 15:11:59 +00001593 if (rite > bounds.fRight) {
1594 rite = bounds.fRight;
1595 }
1596
reed@google.com32287892011-10-05 16:27:44 +00001597 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001598 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001599 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001600 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001601 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001602
1603 adjust_row(iterA, leftA, riteA, rite);
1604 adjust_row(iterB, leftB, riteB, rite);
1605 } while (!iterA.done() || !iterB.done());
1606
1607 if (prevRite < bounds.fRight) {
1608 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001609 }
1610}
1611
reed@google.com1c04bf92011-10-10 12:57:12 +00001612static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1613 if (bot == botA) {
1614 iter.next();
1615 topA = botA;
1616 SkASSERT(botA == iter.top());
1617 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001618 }
1619}
1620
1621static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1622 const SkAAClip& B, SkRegion::Op op) {
1623 AlphaProc proc = find_alpha_proc(op);
1624 const SkIRect& bounds = builder.getBounds();
1625
1626 SkAAClip::Iter iterA(A);
1627 SkAAClip::Iter iterB(B);
1628
1629 SkASSERT(!iterA.done());
1630 int topA = iterA.top();
1631 int botA = iterA.bottom();
1632 SkASSERT(!iterB.done());
1633 int topB = iterB.top();
1634 int botB = iterB.bottom();
1635
reed@google.com1c04bf92011-10-10 12:57:12 +00001636 do {
halcanary96fcdcc2015-08-27 07:41:13 -07001637 const uint8_t* rowA = nullptr;
1638 const uint8_t* rowB = nullptr;
reed@google.com32287892011-10-05 16:27:44 +00001639 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001640
1641 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001642 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001643 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001644 if (botA <= topB) {
1645 bot = botA;
1646 } else {
1647 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001648 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001649
reed@google.com1c04bf92011-10-10 12:57:12 +00001650 } else if (topB < topA) {
1651 top = topB;
1652 rowB = iterB.data();
1653 if (botB <= topA) {
1654 bot = botB;
1655 } else {
1656 bot = topB = topA;
1657 }
1658 } else {
1659 top = topA; // or topB, since topA == topB
1660 bot = topA = topB = SkMin32(botA, botB);
1661 rowA = iterA.data();
1662 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001663 }
1664
1665 if (top >= bounds.fBottom) {
1666 break;
1667 }
reed@google.com34f7e472011-10-13 15:11:59 +00001668
1669 if (bot > bounds.fBottom) {
1670 bot = bounds.fBottom;
1671 }
1672 SkASSERT(top < bot);
1673
reed@google.com1c04bf92011-10-10 12:57:12 +00001674 if (!rowA && !rowB) {
1675 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1676 } else if (top >= bounds.fTop) {
1677 SkASSERT(bot <= bounds.fBottom);
1678 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1679 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001680 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001681 }
1682
reed@google.com1c04bf92011-10-10 12:57:12 +00001683 adjust_iter(iterA, topA, botA, bot);
1684 adjust_iter(iterB, topB, botB, bot);
1685 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001686}
1687
1688bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1689 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001690 AUTO_AACLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001691
reed@google.com32287892011-10-05 16:27:44 +00001692 if (SkRegion::kReplace_Op == op) {
1693 return this->set(clipBOrig);
1694 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001695
reed@google.com32287892011-10-05 16:27:44 +00001696 const SkAAClip* clipA = &clipAOrig;
1697 const SkAAClip* clipB = &clipBOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001698
reed@google.com32287892011-10-05 16:27:44 +00001699 if (SkRegion::kReverseDifference_Op == op) {
1700 SkTSwap(clipA, clipB);
1701 op = SkRegion::kDifference_Op;
1702 }
1703
1704 bool a_empty = clipA->isEmpty();
1705 bool b_empty = clipB->isEmpty();
1706
1707 SkIRect bounds;
1708 switch (op) {
1709 case SkRegion::kDifference_Op:
1710 if (a_empty) {
1711 return this->setEmpty();
1712 }
1713 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1714 return this->set(*clipA);
1715 }
1716 bounds = clipA->fBounds;
1717 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001718
reed@google.com32287892011-10-05 16:27:44 +00001719 case SkRegion::kIntersect_Op:
1720 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1721 clipB->fBounds)) {
1722 return this->setEmpty();
1723 }
1724 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001725
reed@google.com32287892011-10-05 16:27:44 +00001726 case SkRegion::kUnion_Op:
1727 case SkRegion::kXOR_Op:
1728 if (a_empty) {
1729 return this->set(*clipB);
1730 }
1731 if (b_empty) {
1732 return this->set(*clipA);
1733 }
1734 bounds = clipA->fBounds;
1735 bounds.join(clipB->fBounds);
1736 break;
1737
1738 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001739 SkDEBUGFAIL("unknown region op");
reed@google.com32287892011-10-05 16:27:44 +00001740 return !this->isEmpty();
1741 }
1742
reed@google.com32287892011-10-05 16:27:44 +00001743 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1744 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1745
1746 Builder builder(bounds);
1747 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001748
1749 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001750}
1751
reed@google.com045e62d2011-10-24 12:19:46 +00001752/*
1753 * It can be expensive to build a local aaclip before applying the op, so
1754 * we first see if we can restrict the bounds of new rect to our current
1755 * bounds, or note that the new rect subsumes our current clip.
1756 */
1757
1758bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1759 SkIRect rStorage;
1760 const SkIRect* r = &rOrig;
1761
1762 switch (op) {
1763 case SkRegion::kIntersect_Op:
1764 if (!rStorage.intersect(rOrig, fBounds)) {
1765 // no overlap, so we're empty
1766 return this->setEmpty();
1767 }
1768 if (rStorage == fBounds) {
1769 // we were wholly inside the rect, no change
1770 return !this->isEmpty();
1771 }
1772 if (this->quickContains(rStorage)) {
1773 // the intersection is wholly inside us, we're a rect
1774 return this->setRect(rStorage);
1775 }
1776 r = &rStorage; // use the intersected bounds
1777 break;
1778 case SkRegion::kDifference_Op:
1779 break;
1780 case SkRegion::kUnion_Op:
1781 if (rOrig.contains(fBounds)) {
1782 return this->setRect(rOrig);
1783 }
1784 break;
1785 default:
1786 break;
1787 }
1788
reed@google.com47ac84e2011-10-06 13:11:25 +00001789 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001790 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001791 return this->op(*this, clip, op);
1792}
1793
reed@google.com045e62d2011-10-24 12:19:46 +00001794bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1795 SkRect rStorage, boundsStorage;
1796 const SkRect* r = &rOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001797
reed@google.com045e62d2011-10-24 12:19:46 +00001798 boundsStorage.set(fBounds);
1799 switch (op) {
1800 case SkRegion::kIntersect_Op:
1801 case SkRegion::kDifference_Op:
1802 if (!rStorage.intersect(rOrig, boundsStorage)) {
reed@google.come56513d2012-06-25 20:06:33 +00001803 if (SkRegion::kIntersect_Op == op) {
1804 return this->setEmpty();
1805 } else { // kDifference
1806 return !this->isEmpty();
1807 }
reed@google.com045e62d2011-10-24 12:19:46 +00001808 }
1809 r = &rStorage; // use the intersected bounds
1810 break;
1811 case SkRegion::kUnion_Op:
1812 if (rOrig.contains(boundsStorage)) {
1813 return this->setRect(rOrig);
1814 }
1815 break;
1816 default:
1817 break;
1818 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001819
reed@google.com47ac84e2011-10-06 13:11:25 +00001820 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001821 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001822 return this->op(*this, clip, op);
1823}
1824
1825bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1826 return this->op(*this, clip, op);
1827}
1828
reed@google.come36707a2011-10-04 21:38:55 +00001829///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001830
1831bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -07001832 if (nullptr == dst) {
reed@google.com045e62d2011-10-24 12:19:46 +00001833 return !this->isEmpty();
1834 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001835
reed@google.com045e62d2011-10-24 12:19:46 +00001836 if (this->isEmpty()) {
1837 return dst->setEmpty();
1838 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001839
reed@google.com045e62d2011-10-24 12:19:46 +00001840 if (this != dst) {
1841 sk_atomic_inc(&fRunHead->fRefCnt);
tomhudson@google.com19224c32012-03-28 15:46:37 +00001842 dst->freeRuns();
reed@google.com045e62d2011-10-24 12:19:46 +00001843 dst->fRunHead = fRunHead;
1844 dst->fBounds = fBounds;
1845 }
1846 dst->fBounds.offset(dx, dy);
1847 return true;
1848}
1849
1850static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1851 const uint8_t* SK_RESTRICT row,
1852 int width) {
1853 while (width > 0) {
1854 int n = row[0];
1855 SkASSERT(width >= n);
1856 memset(mask, row[1], n);
1857 mask += n;
1858 row += 2;
1859 width -= n;
1860 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001861 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001862}
1863
1864void SkAAClip::copyToMask(SkMask* mask) const {
1865 mask->fFormat = SkMask::kA8_Format;
1866 if (this->isEmpty()) {
1867 mask->fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -07001868 mask->fImage = nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00001869 mask->fRowBytes = 0;
1870 return;
1871 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001872
reed@google.com045e62d2011-10-24 12:19:46 +00001873 mask->fBounds = fBounds;
1874 mask->fRowBytes = fBounds.width();
1875 size_t size = mask->computeImageSize();
1876 mask->fImage = SkMask::AllocImage(size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001877
reed@google.com045e62d2011-10-24 12:19:46 +00001878 Iter iter(*this);
1879 uint8_t* dst = mask->fImage;
1880 const int width = fBounds.width();
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001881
reed@google.com045e62d2011-10-24 12:19:46 +00001882 int y = fBounds.fTop;
1883 while (!iter.done()) {
1884 do {
1885 expand_row_to_mask(dst, iter.data(), width);
1886 dst += mask->fRowBytes;
1887 } while (++y < iter.bottom());
1888 iter.next();
1889 }
1890}
1891
1892///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001893///////////////////////////////////////////////////////////////////////////////
1894
1895static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1896 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1897 // we don't read our initial n from data, since the caller may have had to
1898 // clip it, hence the initialCount parameter.
1899 int n = initialCount;
1900 for (;;) {
1901 if (n > width) {
1902 n = width;
1903 }
1904 SkASSERT(n > 0);
1905 runs[0] = n;
1906 runs += n;
1907
1908 aa[0] = data[1];
1909 aa += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001910
reed@google.come36707a2011-10-04 21:38:55 +00001911 data += 2;
1912 width -= n;
1913 if (0 == width) {
1914 break;
1915 }
1916 // load the next count
1917 n = data[0];
1918 }
1919 runs[0] = 0; // sentinel
1920}
1921
1922SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001923 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001924}
1925
1926void SkAAClipBlitter::ensureRunsAndAA() {
halcanary96fcdcc2015-08-27 07:41:13 -07001927 if (nullptr == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001928 // add 1 so we can store the terminating run count of 0
1929 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001930 // we use this either for fRuns + fAA, or a scaline of a mask
1931 // which may be as deep as 32bits
1932 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1933 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001934 fAA = (SkAlpha*)(fRuns + count);
1935 }
1936}
1937
1938void SkAAClipBlitter::blitH(int x, int y, int width) {
1939 SkASSERT(width > 0);
1940 SkASSERT(fAAClipBounds.contains(x, y));
1941 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1942
reed@google.coma4c6e4d2012-06-20 14:29:50 +00001943 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00001944 int initialCount;
1945 row = fAAClip->findX(row, x, &initialCount);
1946
1947 if (initialCount >= width) {
1948 SkAlpha alpha = row[1];
1949 if (0 == alpha) {
1950 return;
1951 }
1952 if (0xFF == alpha) {
1953 fBlitter->blitH(x, y, width);
1954 return;
1955 }
1956 }
1957
1958 this->ensureRunsAndAA();
1959 expandToRuns(row, initialCount, width, fRuns, fAA);
1960
1961 fBlitter->blitAntiH(x, y, fAA, fRuns);
1962}
1963
1964static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1965 const SkAlpha* SK_RESTRICT srcAA,
1966 const int16_t* SK_RESTRICT srcRuns,
1967 SkAlpha* SK_RESTRICT dstAA,
1968 int16_t* SK_RESTRICT dstRuns,
1969 int width) {
1970 SkDEBUGCODE(int accumulated = 0;)
1971 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001972 // do we need this check?
1973 if (0 == srcN) {
1974 return;
1975 }
1976
reed@google.come36707a2011-10-04 21:38:55 +00001977 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001978 SkASSERT(rowN > 0);
1979 SkASSERT(srcN > 0);
1980
1981 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1982 int minN = SkMin32(srcN, rowN);
1983 dstRuns[0] = minN;
1984 dstRuns += minN;
1985 dstAA[0] = newAlpha;
1986 dstAA += minN;
1987
1988 if (0 == (srcN -= minN)) {
1989 srcN = srcRuns[0]; // refresh
1990 srcRuns += srcN;
1991 srcAA += srcN;
1992 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001993 if (0 == srcN) {
1994 break;
1995 }
reed@google.come36707a2011-10-04 21:38:55 +00001996 }
1997 if (0 == (rowN -= minN)) {
1998 row += 2;
1999 rowN = row[0]; // reload
2000 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002001
reed@google.come36707a2011-10-04 21:38:55 +00002002 SkDEBUGCODE(accumulated += minN;)
2003 SkASSERT(accumulated <= width);
2004 }
reed@google.com34f7e472011-10-13 15:11:59 +00002005 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00002006}
2007
2008void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
2009 const int16_t runs[]) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002010
2011 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00002012 int initialCount;
2013 row = fAAClip->findX(row, x, &initialCount);
2014
2015 this->ensureRunsAndAA();
2016
2017 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
2018 fBlitter->blitAntiH(x, y, fAA, fRuns);
2019}
2020
2021void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
2022 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
2023 fBlitter->blitV(x, y, height, alpha);
2024 return;
2025 }
2026
reed@google.com045e62d2011-10-24 12:19:46 +00002027 for (;;) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002028 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +00002029 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00002030 int dy = lastY - y + 1;
2031 if (dy > height) {
2032 dy = height;
2033 }
2034 height -= dy;
2035
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002036 row = fAAClip->findX(row, x);
reed@google.come36707a2011-10-04 21:38:55 +00002037 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
2038 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00002039 fBlitter->blitV(x, y, dy, newAlpha);
2040 }
2041 SkASSERT(height >= 0);
2042 if (height <= 0) {
2043 break;
reed@google.come36707a2011-10-04 21:38:55 +00002044 }
2045 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00002046 }
reed@google.come36707a2011-10-04 21:38:55 +00002047}
2048
2049void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
2050 if (fAAClip->quickContains(x, y, x + width, y + height)) {
2051 fBlitter->blitRect(x, y, width, height);
2052 return;
2053 }
2054
2055 while (--height >= 0) {
2056 this->blitH(x, y, width);
2057 y += 1;
2058 }
2059}
2060
reed@google.com045e62d2011-10-24 12:19:46 +00002061typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
2062 int initialRowCount, void* dst);
2063
2064static void small_memcpy(void* dst, const void* src, size_t n) {
2065 memcpy(dst, src, n);
2066}
2067
2068static void small_bzero(void* dst, size_t n) {
2069 sk_bzero(dst, n);
2070}
2071
2072static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
2073 return SkMulDiv255Round(value, alpha);
2074}
reedd54d3fc2014-11-13 14:39:58 -08002075
reed@google.com045e62d2011-10-24 12:19:46 +00002076static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
2077 unsigned r = SkGetPackedR16(value);
2078 unsigned g = SkGetPackedG16(value);
2079 unsigned b = SkGetPackedB16(value);
2080 return SkPackRGB16(SkMulDiv255Round(r, alpha),
caryclark@google.com803eceb2012-06-06 12:09:34 +00002081 SkMulDiv255Round(g, alpha),
2082 SkMulDiv255Round(b, alpha));
reed@google.com045e62d2011-10-24 12:19:46 +00002083}
reed@google.com045e62d2011-10-24 12:19:46 +00002084
herb94496162015-12-10 14:17:41 -08002085template <typename T>
2086void mergeT(const void* inSrc, int srcN, const uint8_t* SK_RESTRICT row, int rowN, void* inDst) {
2087 const T* SK_RESTRICT src = static_cast<const T*>(inSrc);
2088 T* SK_RESTRICT dst = static_cast<T*>(inDst);
reed@google.com045e62d2011-10-24 12:19:46 +00002089 for (;;) {
2090 SkASSERT(rowN > 0);
2091 SkASSERT(srcN > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002092
reed@google.com045e62d2011-10-24 12:19:46 +00002093 int n = SkMin32(rowN, srcN);
2094 unsigned rowA = row[1];
2095 if (0xFF == rowA) {
2096 small_memcpy(dst, src, n * sizeof(T));
2097 } else if (0 == rowA) {
2098 small_bzero(dst, n * sizeof(T));
2099 } else {
2100 for (int i = 0; i < n; ++i) {
2101 dst[i] = mergeOne(src[i], rowA);
2102 }
2103 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002104
reed@google.com045e62d2011-10-24 12:19:46 +00002105 if (0 == (srcN -= n)) {
2106 break;
2107 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002108
reed@google.com045e62d2011-10-24 12:19:46 +00002109 src += n;
2110 dst += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002111
reed@google.com045e62d2011-10-24 12:19:46 +00002112 SkASSERT(rowN == n);
2113 row += 2;
2114 rowN = row[0];
2115 }
2116}
2117
2118static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2119 switch (format) {
2120 case SkMask::kBW_Format:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002121 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002122 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002123 case SkMask::kA8_Format:
herb94496162015-12-10 14:17:41 -08002124 case SkMask::k3D_Format:
2125 return mergeT<uint8_t> ;
2126 case SkMask::kLCD16_Format:
2127 return mergeT<uint16_t>;
reed@google.com045e62d2011-10-24 12:19:46 +00002128 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002129 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002130 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002131 }
2132}
2133
2134static U8CPU bit2byte(int bitInAByte) {
2135 SkASSERT(bitInAByte <= 0xFF);
2136 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2137 // some value >= 8 to get a full FF value
2138 return -bitInAByte >> 8;
2139}
2140
2141static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2142 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2143 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2144
2145 const int width = srcMask.fBounds.width();
2146 const int height = srcMask.fBounds.height();
2147
2148 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2149 const size_t srcRB = srcMask.fRowBytes;
2150 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2151 const size_t dstRB = dstMask->fRowBytes;
2152
2153 const int wholeBytes = width >> 3;
2154 const int leftOverBits = width & 7;
2155
2156 for (int y = 0; y < height; ++y) {
2157 uint8_t* SK_RESTRICT d = dst;
2158 for (int i = 0; i < wholeBytes; ++i) {
2159 int srcByte = src[i];
2160 d[0] = bit2byte(srcByte & (1 << 7));
2161 d[1] = bit2byte(srcByte & (1 << 6));
2162 d[2] = bit2byte(srcByte & (1 << 5));
2163 d[3] = bit2byte(srcByte & (1 << 4));
2164 d[4] = bit2byte(srcByte & (1 << 3));
2165 d[5] = bit2byte(srcByte & (1 << 2));
2166 d[6] = bit2byte(srcByte & (1 << 1));
2167 d[7] = bit2byte(srcByte & (1 << 0));
2168 d += 8;
2169 }
2170 if (leftOverBits) {
2171 int srcByte = src[wholeBytes];
2172 for (int x = 0; x < leftOverBits; ++x) {
2173 *d++ = bit2byte(srcByte & 0x80);
2174 srcByte <<= 1;
2175 }
2176 }
2177 src += srcRB;
2178 dst += dstRB;
2179 }
2180}
2181
2182void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2183 SkASSERT(fAAClip->getBounds().contains(clip));
2184
2185 if (fAAClip->quickContains(clip)) {
2186 fBlitter->blitMask(origMask, clip);
2187 return;
2188 }
2189
2190 const SkMask* mask = &origMask;
2191
2192 // if we're BW, we need to upscale to A8 (ugh)
2193 SkMask grayMask;
reed@google.com045e62d2011-10-24 12:19:46 +00002194 if (SkMask::kBW_Format == origMask.fFormat) {
2195 grayMask.fFormat = SkMask::kA8_Format;
2196 grayMask.fBounds = origMask.fBounds;
2197 grayMask.fRowBytes = origMask.fBounds.width();
2198 size_t size = grayMask.computeImageSize();
2199 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2200 SkAutoMalloc::kReuse_OnShrink);
2201
2202 upscaleBW2A8(&grayMask, origMask);
2203 mask = &grayMask;
2204 }
2205
2206 this->ensureRunsAndAA();
2207
2208 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2209 // data into a temp block to support it better (ugh)
2210
2211 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2212 const size_t srcRB = mask->fRowBytes;
2213 const int width = clip.width();
2214 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2215
2216 SkMask rowMask;
2217 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2218 rowMask.fBounds.fLeft = clip.fLeft;
2219 rowMask.fBounds.fRight = clip.fRight;
2220 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2221 rowMask.fImage = (uint8_t*)fScanlineScratch;
2222
2223 int y = clip.fTop;
2224 const int stopY = y + clip.height();
2225
2226 do {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002227 int localStopY SK_INIT_TO_AVOID_WARNING;
reed@google.com045e62d2011-10-24 12:19:46 +00002228 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2229 // findRow returns last Y, not stop, so we add 1
2230 localStopY = SkMin32(localStopY + 1, stopY);
2231
2232 int initialCount;
2233 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2234 do {
2235 mergeProc(src, width, row, initialCount, rowMask.fImage);
2236 rowMask.fBounds.fTop = y;
2237 rowMask.fBounds.fBottom = y + 1;
2238 fBlitter->blitMask(rowMask, rowMask.fBounds);
2239 src = (const void*)((const char*)src + srcRB);
2240 } while (++y < localStopY);
2241 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002242}
2243
reed41e010c2015-06-09 12:16:53 -07002244const SkPixmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
halcanary96fcdcc2015-08-27 07:41:13 -07002245 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00002246}