blob: 54d6726e6531ccdb0c986db70f55139eb937d4b0 [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"
Hal Canary2a2f6752018-06-11 21:44:01 -04009
herbb906daf2015-09-29 09:37:59 -070010#include "SkAtomics.h"
reed@google.come36707a2011-10-04 21:38:55 +000011#include "SkBlitter.h"
Cary Clarka4083c92017-09-15 11:59:23 -040012#include "SkColorData.h"
reed@google.come36707a2011-10-04 21:38:55 +000013#include "SkPath.h"
Hal Canary2a2f6752018-06-11 21:44:01 -040014#include "SkRectPriv.h"
reed@google.come36707a2011-10-04 21:38:55 +000015#include "SkScan.h"
Hal Canary2a2f6752018-06-11 21:44:01 -040016#include "SkTo.h"
reed@google.com34f7e472011-10-13 15:11:59 +000017#include "SkUtils.h"
reed@google.come36707a2011-10-04 21:38:55 +000018
reed@google.com045e62d2011-10-24 12:19:46 +000019class AutoAAClipValidate {
20public:
21 AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
22 fClip.validate();
23 }
24 ~AutoAAClipValidate() {
25 fClip.validate();
26 }
27private:
28 const SkAAClip& fClip;
29};
30
31#ifdef SK_DEBUG
32 #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip)
33#else
34 #define AUTO_AACLIP_VALIDATE(clip)
35#endif
36
37///////////////////////////////////////////////////////////////////////////////
38
reed@google.com1c04bf92011-10-10 12:57:12 +000039#define kMaxInt32 0x7FFFFFFF
40
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000041#ifdef SK_DEBUG
reed@google.come36707a2011-10-04 21:38:55 +000042static inline bool x_in_rect(int x, const SkIRect& rect) {
43 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
44}
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000045#endif
reed@google.come36707a2011-10-04 21:38:55 +000046
47static inline bool y_in_rect(int y, const SkIRect& rect) {
48 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
49}
50
51/*
52 * Data runs are packed [count, alpha]
53 */
54
55struct SkAAClip::YOffset {
56 int32_t fY;
57 uint32_t fOffset;
58};
59
60struct SkAAClip::RunHead {
61 int32_t fRefCnt;
62 int32_t fRowCount;
scroggo@google.com493c65f2013-02-05 18:49:00 +000063 size_t fDataSize;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000064
reed@google.come36707a2011-10-04 21:38:55 +000065 YOffset* yoffsets() {
66 return (YOffset*)((char*)this + sizeof(RunHead));
67 }
68 const YOffset* yoffsets() const {
69 return (const YOffset*)((const char*)this + sizeof(RunHead));
70 }
71 uint8_t* data() {
72 return (uint8_t*)(this->yoffsets() + fRowCount);
73 }
74 const uint8_t* data() const {
75 return (const uint8_t*)(this->yoffsets() + fRowCount);
76 }
77
78 static RunHead* Alloc(int rowCount, size_t dataSize) {
79 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
80 RunHead* head = (RunHead*)sk_malloc_throw(size);
81 head->fRefCnt = 1;
82 head->fRowCount = rowCount;
83 head->fDataSize = dataSize;
84 return head;
85 }
reed@google.com045e62d2011-10-24 12:19:46 +000086
87 static int ComputeRowSizeForWidth(int width) {
88 // 2 bytes per segment, where each segment can store up to 255 for count
89 int segments = 0;
90 while (width > 0) {
91 segments += 1;
92 int n = SkMin32(width, 255);
93 width -= n;
94 }
95 return segments * 2; // each segment is row[0] + row[1] (n + alpha)
96 }
97
98 static RunHead* AllocRect(const SkIRect& bounds) {
99 SkASSERT(!bounds.isEmpty());
100 int width = bounds.width();
101 size_t rowSize = ComputeRowSizeForWidth(width);
102 RunHead* head = RunHead::Alloc(1, rowSize);
103 YOffset* yoff = head->yoffsets();
104 yoff->fY = bounds.height() - 1;
105 yoff->fOffset = 0;
106 uint8_t* row = head->data();
107 while (width > 0) {
108 int n = SkMin32(width, 255);
109 row[0] = n;
110 row[1] = 0xFF;
111 width -= n;
112 row += 2;
113 }
114 return head;
115 }
reed@google.come36707a2011-10-04 21:38:55 +0000116};
117
reed@google.com32287892011-10-05 16:27:44 +0000118class SkAAClip::Iter {
119public:
120 Iter(const SkAAClip&);
121
122 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000123 int top() const { return fTop; }
124 int bottom() const { return fBottom; }
125 const uint8_t* data() const { return fData; }
reed@google.com32287892011-10-05 16:27:44 +0000126 void next();
127
128private:
129 const YOffset* fCurrYOff;
130 const YOffset* fStopYOff;
131 const uint8_t* fData;
132
133 int fTop, fBottom;
134 bool fDone;
135};
136
137SkAAClip::Iter::Iter(const SkAAClip& clip) {
138 if (clip.isEmpty()) {
139 fDone = true;
reed@google.com1c04bf92011-10-10 12:57:12 +0000140 fTop = fBottom = clip.fBounds.fBottom;
halcanary96fcdcc2015-08-27 07:41:13 -0700141 fData = nullptr;
142 fCurrYOff = nullptr;
143 fStopYOff = nullptr;
reed@google.com32287892011-10-05 16:27:44 +0000144 return;
145 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000146
reed@google.com32287892011-10-05 16:27:44 +0000147 const RunHead* head = clip.fRunHead;
148 fCurrYOff = head->yoffsets();
149 fStopYOff = fCurrYOff + head->fRowCount;
150 fData = head->data() + fCurrYOff->fOffset;
151
152 // setup first value
153 fTop = clip.fBounds.fTop;
154 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
155 fDone = false;
156}
157
158void SkAAClip::Iter::next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000159 if (!fDone) {
160 const YOffset* prev = fCurrYOff;
161 const YOffset* curr = prev + 1;
162 SkASSERT(curr <= fStopYOff);
reed@google.com32287892011-10-05 16:27:44 +0000163
reed@google.com32287892011-10-05 16:27:44 +0000164 fTop = fBottom;
reed@google.com1c04bf92011-10-10 12:57:12 +0000165 if (curr >= fStopYOff) {
166 fDone = true;
167 fBottom = kMaxInt32;
halcanary96fcdcc2015-08-27 07:41:13 -0700168 fData = nullptr;
reed@google.com1c04bf92011-10-10 12:57:12 +0000169 } else {
170 fBottom += curr->fY - prev->fY;
171 fData += curr->fOffset - prev->fOffset;
172 fCurrYOff = curr;
173 }
reed@google.com32287892011-10-05 16:27:44 +0000174 }
175}
176
reed@google.com045e62d2011-10-24 12:19:46 +0000177#ifdef SK_DEBUG
reed@google.comc9041912011-10-27 16:58:46 +0000178// assert we're exactly width-wide, and then return the number of bytes used
reed@google.com045e62d2011-10-24 12:19:46 +0000179static size_t compute_row_length(const uint8_t row[], int width) {
180 const uint8_t* origRow = row;
181 while (width > 0) {
182 int n = row[0];
reed@google.comc9041912011-10-27 16:58:46 +0000183 SkASSERT(n > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000184 SkASSERT(n <= width);
185 row += 2;
186 width -= n;
187 }
188 SkASSERT(0 == width);
189 return row - origRow;
190}
191
192void SkAAClip::validate() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700193 if (nullptr == fRunHead) {
reed@google.com045e62d2011-10-24 12:19:46 +0000194 SkASSERT(fBounds.isEmpty());
195 return;
196 }
reedd7ec12e2016-06-20 10:21:24 -0700197 SkASSERT(!fBounds.isEmpty());
reed@google.com045e62d2011-10-24 12:19:46 +0000198
199 const RunHead* head = fRunHead;
200 SkASSERT(head->fRefCnt > 0);
201 SkASSERT(head->fRowCount > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000202
203 const YOffset* yoff = head->yoffsets();
204 const YOffset* ystop = yoff + head->fRowCount;
reed@google.comc9041912011-10-27 16:58:46 +0000205 const int lastY = fBounds.height() - 1;
206
207 // Y and offset must be monotonic
208 int prevY = -1;
209 int32_t prevOffset = -1;
reed@google.com045e62d2011-10-24 12:19:46 +0000210 while (yoff < ystop) {
reed@google.comc9041912011-10-27 16:58:46 +0000211 SkASSERT(prevY < yoff->fY);
212 SkASSERT(yoff->fY <= lastY);
213 prevY = yoff->fY;
214 SkASSERT(prevOffset < (int32_t)yoff->fOffset);
215 prevOffset = yoff->fOffset;
216 const uint8_t* row = head->data() + yoff->fOffset;
reed@google.com045e62d2011-10-24 12:19:46 +0000217 size_t rowLength = compute_row_length(row, fBounds.width());
scroggo@google.com493c65f2013-02-05 18:49:00 +0000218 SkASSERT(yoff->fOffset + rowLength <= head->fDataSize);
reed@google.comc9041912011-10-27 16:58:46 +0000219 yoff += 1;
reed@google.com045e62d2011-10-24 12:19:46 +0000220 }
reed@google.com045e62d2011-10-24 12:19:46 +0000221 // check the last entry;
222 --yoff;
reed@google.comc9041912011-10-27 16:58:46 +0000223 SkASSERT(yoff->fY == lastY);
reed@google.com045e62d2011-10-24 12:19:46 +0000224}
humper6d42d9c2014-08-08 11:45:46 -0700225
226static void dump_one_row(const uint8_t* SK_RESTRICT row,
227 int width, int leading_num) {
228 if (leading_num) {
229 SkDebugf( "%03d ", leading_num );
230 }
231 while (width > 0) {
232 int n = row[0];
233 int val = row[1];
234 char out = '.';
235 if (val == 0xff) {
236 out = '*';
237 } else if (val > 0) {
238 out = '+';
239 }
240 for (int i = 0 ; i < n ; i++) {
241 SkDebugf( "%c", out );
242 }
243 row += 2;
244 width -= n;
245 }
246 SkDebugf( "\n" );
247}
248
249void SkAAClip::debug(bool compress_y) const {
250 Iter iter(*this);
251 const int width = fBounds.width();
252
253 int y = fBounds.fTop;
254 while (!iter.done()) {
255 if (compress_y) {
256 dump_one_row(iter.data(), width, iter.bottom() - iter.top() + 1);
257 } else {
258 do {
259 dump_one_row(iter.data(), width, 0);
260 } while (++y < iter.bottom());
261 }
262 iter.next();
263 }
264}
reed@google.com045e62d2011-10-24 12:19:46 +0000265#endif
266
267///////////////////////////////////////////////////////////////////////////////
268
robertphillips@google.com768fee82012-08-02 12:42:43 +0000269// Count the number of zeros on the left and right edges of the passed in
270// RLE row. If 'row' is all zeros return 'width' in both variables.
reed@google.comc9041912011-10-27 16:58:46 +0000271static void count_left_right_zeros(const uint8_t* row, int width,
272 int* leftZ, int* riteZ) {
273 int zeros = 0;
274 do {
275 if (row[1]) {
276 break;
277 }
278 int n = row[0];
279 SkASSERT(n > 0);
280 SkASSERT(n <= width);
281 zeros += n;
282 row += 2;
283 width -= n;
284 } while (width > 0);
285 *leftZ = zeros;
286
robertphillips@google.com768fee82012-08-02 12:42:43 +0000287 if (0 == width) {
288 // this line is completely empty return 'width' in both variables
289 *riteZ = *leftZ;
290 return;
291 }
292
reed@google.comc9041912011-10-27 16:58:46 +0000293 zeros = 0;
294 while (width > 0) {
295 int n = row[0];
296 SkASSERT(n > 0);
297 if (0 == row[1]) {
298 zeros += n;
299 } else {
300 zeros = 0;
301 }
302 row += 2;
303 width -= n;
304 }
305 *riteZ = zeros;
306}
307
308#ifdef SK_DEBUG
309static void test_count_left_right_zeros() {
310 static bool gOnce;
311 if (gOnce) {
312 return;
313 }
314 gOnce = true;
315
316 const uint8_t data0[] = { 0, 0, 10, 0xFF };
317 const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF };
318 const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF };
319 const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 };
320 const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 };
robertphillips@google.com768fee82012-08-02 12:42:43 +0000321 const uint8_t data5[] = { 10, 10, 10, 0 };
reed@google.comc9041912011-10-27 16:58:46 +0000322 const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
323
324 const uint8_t* array[] = {
325 data0, data1, data2, data3, data4, data5, data6
326 };
327
328 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
329 const uint8_t* data = array[i];
330 const int expectedL = *data++;
331 const int expectedR = *data++;
332 int L = 12345, R = 12345;
333 count_left_right_zeros(data, 10, &L, &R);
334 SkASSERT(expectedL == L);
335 SkASSERT(expectedR == R);
336 }
337}
338#endif
339
340// modify row in place, trimming off (zeros) from the left and right sides.
341// return the number of bytes that were completely eliminated from the left
342static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
343 int trim = 0;
344 while (leftZ > 0) {
345 SkASSERT(0 == row[1]);
346 int n = row[0];
347 SkASSERT(n > 0);
348 SkASSERT(n <= width);
349 width -= n;
350 row += 2;
351 if (n > leftZ) {
352 row[-2] = n - leftZ;
353 break;
354 }
355 trim += 2;
356 leftZ -= n;
357 SkASSERT(leftZ >= 0);
358 }
359
360 if (riteZ) {
361 // walk row to the end, and then we'll back up to trim riteZ
362 while (width > 0) {
363 int n = row[0];
364 SkASSERT(n <= width);
365 width -= n;
366 row += 2;
367 }
368 // now skip whole runs of zeros
369 do {
370 row -= 2;
371 SkASSERT(0 == row[1]);
372 int n = row[0];
373 SkASSERT(n > 0);
374 if (n > riteZ) {
375 row[0] = n - riteZ;
376 break;
377 }
378 riteZ -= n;
379 SkASSERT(riteZ >= 0);
380 } while (riteZ > 0);
381 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000382
reed@google.comc9041912011-10-27 16:58:46 +0000383 return trim;
384}
385
386#ifdef SK_DEBUG
387// assert that this row is exactly this width
reed@google.comc5507bf2011-10-27 21:15:36 +0000388static void assert_row_width(const uint8_t* row, int width) {
reed@google.comc9041912011-10-27 16:58:46 +0000389 while (width > 0) {
390 int n = row[0];
391 SkASSERT(n > 0);
392 SkASSERT(n <= width);
393 width -= n;
394 row += 2;
395 }
396 SkASSERT(0 == width);
397}
398
399static void test_trim_row_left_right() {
400 static bool gOnce;
401 if (gOnce) {
402 return;
403 }
404 gOnce = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000405
reed@google.comc9041912011-10-27 16:58:46 +0000406 uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF };
407 uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF };
408 uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
409 uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
410 uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
411 uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
412 uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
413 uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
414 uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
415 uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
416 uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000417
reed@google.comc9041912011-10-27 16:58:46 +0000418 uint8_t* array[] = {
419 data0, data1, data2, data3, data4,
420 data5, data6, data7, data8, data9,
421 data10
422 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000423
reed@google.comc9041912011-10-27 16:58:46 +0000424 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
425 uint8_t* data = array[i];
426 const int trimL = *data++;
427 const int trimR = *data++;
428 const int expectedSkip = *data++;
429 const int origWidth = *data++;
430 assert_row_width(data, origWidth);
431 int skip = trim_row_left_right(data, origWidth, trimL, trimR);
432 SkASSERT(expectedSkip == skip);
433 int expectedWidth = origWidth - trimL - trimR;
434 assert_row_width(data + skip, expectedWidth);
435 }
436}
437#endif
438
439bool SkAAClip::trimLeftRight() {
440 SkDEBUGCODE(test_trim_row_left_right();)
441
442 if (this->isEmpty()) {
443 return false;
444 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000445
reed@google.comc9041912011-10-27 16:58:46 +0000446 AUTO_AACLIP_VALIDATE(*this);
447
448 const int width = fBounds.width();
449 RunHead* head = fRunHead;
450 YOffset* yoff = head->yoffsets();
451 YOffset* stop = yoff + head->fRowCount;
452 uint8_t* base = head->data();
453
robertphillips@google.com768fee82012-08-02 12:42:43 +0000454 // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum
455 // number of zeros on the left and right of the clip. This information
456 // can be used to shrink the bounding box.
reed@google.comc9041912011-10-27 16:58:46 +0000457 int leftZeros = width;
458 int riteZeros = width;
459 while (yoff < stop) {
460 int L, R;
461 count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000462 SkASSERT(L + R < width || (L == width && R == width));
reed@google.comc9041912011-10-27 16:58:46 +0000463 if (L < leftZeros) {
464 leftZeros = L;
465 }
466 if (R < riteZeros) {
467 riteZeros = R;
468 }
469 if (0 == (leftZeros | riteZeros)) {
470 // no trimming to do
471 return true;
472 }
473 yoff += 1;
474 }
475
476 SkASSERT(leftZeros || riteZeros);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000477 if (width == leftZeros) {
478 SkASSERT(width == riteZeros);
reed@google.comc9041912011-10-27 16:58:46 +0000479 return this->setEmpty();
480 }
481
482 this->validate();
483
484 fBounds.fLeft += leftZeros;
485 fBounds.fRight -= riteZeros;
486 SkASSERT(!fBounds.isEmpty());
487
488 // For now we don't realloc the storage (for time), we just shrink in place
489 // This means we don't have to do any memmoves either, since we can just
490 // play tricks with the yoff->fOffset for each row
491 yoff = head->yoffsets();
492 while (yoff < stop) {
493 uint8_t* row = base + yoff->fOffset;
494 SkDEBUGCODE((void)compute_row_length(row, width);)
495 yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
496 SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
497 yoff += 1;
498 }
499 return true;
500}
501
502static bool row_is_all_zeros(const uint8_t* row, int width) {
503 SkASSERT(width > 0);
504 do {
505 if (row[1]) {
506 return false;
507 }
508 int n = row[0];
509 SkASSERT(n <= width);
510 width -= n;
511 row += 2;
512 } while (width > 0);
513 SkASSERT(0 == width);
514 return true;
515}
516
517bool SkAAClip::trimTopBottom() {
518 if (this->isEmpty()) {
519 return false;
520 }
521
reed@google.comd6040f62011-10-28 02:39:17 +0000522 this->validate();
523
reed@google.comc9041912011-10-27 16:58:46 +0000524 const int width = fBounds.width();
525 RunHead* head = fRunHead;
526 YOffset* yoff = head->yoffsets();
527 YOffset* stop = yoff + head->fRowCount;
528 const uint8_t* base = head->data();
529
530 // Look to trim away empty rows from the top.
531 //
532 int skip = 0;
533 while (yoff < stop) {
534 const uint8_t* data = base + yoff->fOffset;
535 if (!row_is_all_zeros(data, width)) {
536 break;
537 }
538 skip += 1;
539 yoff += 1;
540 }
541 SkASSERT(skip <= head->fRowCount);
542 if (skip == head->fRowCount) {
543 return this->setEmpty();
544 }
545 if (skip > 0) {
546 // adjust fRowCount and fBounds.fTop, and slide all the data up
547 // as we remove [skip] number of YOffset entries
548 yoff = head->yoffsets();
549 int dy = yoff[skip - 1].fY + 1;
550 for (int i = skip; i < head->fRowCount; ++i) {
551 SkASSERT(yoff[i].fY >= dy);
552 yoff[i].fY -= dy;
553 }
554 YOffset* dst = head->yoffsets();
555 size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
556 memmove(dst, dst + skip, size - skip * sizeof(YOffset));
557
558 fBounds.fTop += dy;
559 SkASSERT(!fBounds.isEmpty());
560 head->fRowCount -= skip;
561 SkASSERT(head->fRowCount > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000562
reed@google.comd6040f62011-10-28 02:39:17 +0000563 this->validate();
564 // need to reset this after the memmove
565 base = head->data();
reed@google.comc9041912011-10-27 16:58:46 +0000566 }
567
568 // Look to trim away empty rows from the bottom.
569 // We know that we have at least one non-zero row, so we can just walk
570 // backwards without checking for running past the start.
571 //
572 stop = yoff = head->yoffsets() + head->fRowCount;
573 do {
574 yoff -= 1;
575 } while (row_is_all_zeros(base + yoff->fOffset, width));
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +0000576 skip = SkToInt(stop - yoff - 1);
reed@google.comc9041912011-10-27 16:58:46 +0000577 SkASSERT(skip >= 0 && skip < head->fRowCount);
578 if (skip > 0) {
579 // removing from the bottom is easier than from the top, as we don't
580 // have to adjust any of the Y values, we just have to trim the array
581 memmove(stop - skip, stop, head->fDataSize);
582
583 fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
584 SkASSERT(!fBounds.isEmpty());
585 head->fRowCount -= skip;
586 SkASSERT(head->fRowCount > 0);
587 }
reed@google.comd6040f62011-10-28 02:39:17 +0000588 this->validate();
reed@google.comc9041912011-10-27 16:58:46 +0000589
590 return true;
591}
592
reed@google.com045e62d2011-10-24 12:19:46 +0000593// can't validate before we're done, since trimming is part of the process of
594// making us valid after the Builder. Since we build from top to bottom, its
595// possible our fBounds.fBottom is bigger than our last scanline of data, so
596// we trim fBounds.fBottom back up.
597//
reed@google.com045e62d2011-10-24 12:19:46 +0000598// TODO: check for duplicates in X and Y to further compress our data
599//
600bool SkAAClip::trimBounds() {
601 if (this->isEmpty()) {
602 return false;
603 }
604
605 const RunHead* head = fRunHead;
606 const YOffset* yoff = head->yoffsets();
607
608 SkASSERT(head->fRowCount > 0);
609 const YOffset& lastY = yoff[head->fRowCount - 1];
610 SkASSERT(lastY.fY + 1 <= fBounds.height());
611 fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
612 SkASSERT(lastY.fY + 1 == fBounds.height());
reed@google.comc9041912011-10-27 16:58:46 +0000613 SkASSERT(!fBounds.isEmpty());
614
615 return this->trimTopBottom() && this->trimLeftRight();
reed@google.com045e62d2011-10-24 12:19:46 +0000616}
617
reed@google.come36707a2011-10-04 21:38:55 +0000618///////////////////////////////////////////////////////////////////////////////
619
620void SkAAClip::freeRuns() {
reed@google.com47ac84e2011-10-06 13:11:25 +0000621 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000622 SkASSERT(fRunHead->fRefCnt >= 1);
623 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
624 sk_free(fRunHead);
625 }
626 }
627}
628
629SkAAClip::SkAAClip() {
630 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700631 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000632}
633
634SkAAClip::SkAAClip(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000635 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
halcanary96fcdcc2015-08-27 07:41:13 -0700636 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000637 *this = src;
638}
639
640SkAAClip::~SkAAClip() {
641 this->freeRuns();
642}
643
644SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000645 AUTO_AACLIP_VALIDATE(*this);
646 src.validate();
647
reed@google.come36707a2011-10-04 21:38:55 +0000648 if (this != &src) {
649 this->freeRuns();
650 fBounds = src.fBounds;
651 fRunHead = src.fRunHead;
reed@google.com47ac84e2011-10-06 13:11:25 +0000652 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000653 sk_atomic_inc(&fRunHead->fRefCnt);
654 }
655 }
656 return *this;
657}
658
659bool operator==(const SkAAClip& a, const SkAAClip& b) {
reed@google.com045e62d2011-10-24 12:19:46 +0000660 a.validate();
661 b.validate();
662
reed@google.come36707a2011-10-04 21:38:55 +0000663 if (&a == &b) {
664 return true;
665 }
666 if (a.fBounds != b.fBounds) {
667 return false;
668 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000669
reed@google.come36707a2011-10-04 21:38:55 +0000670 const SkAAClip::RunHead* ah = a.fRunHead;
671 const SkAAClip::RunHead* bh = b.fRunHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000672
reed@google.come36707a2011-10-04 21:38:55 +0000673 // this catches empties and rects being equal
674 if (ah == bh) {
675 return true;
676 }
677
678 // now we insist that both are complex (but different ptrs)
reed@google.com47ac84e2011-10-06 13:11:25 +0000679 if (!a.fRunHead || !b.fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000680 return false;
681 }
682
683 return ah->fRowCount == bh->fRowCount &&
684 ah->fDataSize == bh->fDataSize &&
685 !memcmp(ah->data(), bh->data(), ah->fDataSize);
686}
687
688void SkAAClip::swap(SkAAClip& other) {
reed@google.com045e62d2011-10-24 12:19:46 +0000689 AUTO_AACLIP_VALIDATE(*this);
690 other.validate();
691
reed@google.come36707a2011-10-04 21:38:55 +0000692 SkTSwap(fBounds, other.fBounds);
693 SkTSwap(fRunHead, other.fRunHead);
694}
695
reed@google.com32287892011-10-05 16:27:44 +0000696bool SkAAClip::set(const SkAAClip& src) {
697 *this = src;
698 return !this->isEmpty();
699}
700
reed@google.come36707a2011-10-04 21:38:55 +0000701bool SkAAClip::setEmpty() {
702 this->freeRuns();
703 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700704 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000705 return false;
706}
707
708bool SkAAClip::setRect(const SkIRect& bounds) {
Mike Reeda766ca92018-01-09 11:31:53 -0500709 if (bounds.isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000710 return this->setEmpty();
711 }
reed@google.com47ac84e2011-10-06 13:11:25 +0000712
reed@google.com045e62d2011-10-24 12:19:46 +0000713 AUTO_AACLIP_VALIDATE(*this);
reed@google.com47ac84e2011-10-06 13:11:25 +0000714
reed@google.com045e62d2011-10-24 12:19:46 +0000715#if 0
reed@google.com47ac84e2011-10-06 13:11:25 +0000716 SkRect r;
717 r.set(bounds);
718 SkPath path;
719 path.addRect(r);
720 return this->setPath(path);
reed@google.com045e62d2011-10-24 12:19:46 +0000721#else
722 this->freeRuns();
723 fBounds = bounds;
724 fRunHead = RunHead::AllocRect(bounds);
725 SkASSERT(!this->isEmpty());
726 return true;
727#endif
reed@google.come36707a2011-10-04 21:38:55 +0000728}
729
reed202ab2a2014-08-07 11:48:10 -0700730bool SkAAClip::isRect() const {
731 if (this->isEmpty()) {
732 return false;
733 }
734
735 const RunHead* head = fRunHead;
736 if (head->fRowCount != 1) {
737 return false;
738 }
739 const YOffset* yoff = head->yoffsets();
740 if (yoff->fY != fBounds.fBottom - 1) {
741 return false;
742 }
743
744 const uint8_t* row = head->data() + yoff->fOffset;
745 int width = fBounds.width();
746 do {
747 if (row[1] != 0xFF) {
748 return false;
749 }
750 int n = row[0];
751 SkASSERT(n <= width);
752 width -= n;
753 row += 2;
754 } while (width > 0);
755 return true;
756}
757
reed@google.comf3c1da12011-10-10 19:35:47 +0000758bool SkAAClip::setRect(const SkRect& r, bool doAA) {
reed@google.come36707a2011-10-04 21:38:55 +0000759 if (r.isEmpty()) {
760 return this->setEmpty();
761 }
762
reed@google.com045e62d2011-10-24 12:19:46 +0000763 AUTO_AACLIP_VALIDATE(*this);
764
765 // TODO: special case this
766
reed@google.come36707a2011-10-04 21:38:55 +0000767 SkPath path;
768 path.addRect(r);
halcanary96fcdcc2015-08-27 07:41:13 -0700769 return this->setPath(path, nullptr, doAA);
reed@google.comf3c1da12011-10-10 19:35:47 +0000770}
771
reed@google.coma069c8f2011-11-28 19:54:56 +0000772static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
773 SkASSERT(count >= 0);
774 while (count > 0) {
775 int n = count;
776 if (n > 255) {
777 n = 255;
778 }
779 uint8_t* data = array.append(2);
780 data[0] = n;
781 data[1] = value;
782 count -= n;
783 }
784}
785
reed@google.comf3c1da12011-10-10 19:35:47 +0000786bool SkAAClip::setRegion(const SkRegion& rgn) {
787 if (rgn.isEmpty()) {
788 return this->setEmpty();
789 }
790 if (rgn.isRect()) {
791 return this->setRect(rgn.getBounds());
792 }
reed@google.coma069c8f2011-11-28 19:54:56 +0000793
794#if 0
reed@google.comf3c1da12011-10-10 19:35:47 +0000795 SkAAClip clip;
796 SkRegion::Iterator iter(rgn);
797 for (; !iter.done(); iter.next()) {
798 clip.op(iter.rect(), SkRegion::kUnion_Op);
799 }
800 this->swap(clip);
reed@google.com3771a032011-10-11 17:18:04 +0000801 return !this->isEmpty();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000802#else
reed@google.coma069c8f2011-11-28 19:54:56 +0000803 const SkIRect& bounds = rgn.getBounds();
804 const int offsetX = bounds.fLeft;
805 const int offsetY = bounds.fTop;
806
807 SkTDArray<YOffset> yArray;
808 SkTDArray<uint8_t> xArray;
809
810 yArray.setReserve(SkMin32(bounds.height(), 1024));
Mike Reede0673952017-10-04 16:46:42 -0400811 xArray.setReserve(SkMin32(bounds.width(), 512) * 128);
reed@google.coma069c8f2011-11-28 19:54:56 +0000812
813 SkRegion::Iterator iter(rgn);
814 int prevRight = 0;
815 int prevBot = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700816 YOffset* currY = nullptr;
reed@google.coma069c8f2011-11-28 19:54:56 +0000817
818 for (; !iter.done(); iter.next()) {
819 const SkIRect& r = iter.rect();
820 SkASSERT(bounds.contains(r));
821
822 int bot = r.fBottom - offsetY;
823 SkASSERT(bot >= prevBot);
824 if (bot > prevBot) {
825 if (currY) {
826 // flush current row
827 append_run(xArray, 0, bounds.width() - prevRight);
828 }
829 // did we introduce an empty-gap from the prev row?
830 int top = r.fTop - offsetY;
831 if (top > prevBot) {
832 currY = yArray.append();
833 currY->fY = top - 1;
834 currY->fOffset = xArray.count();
835 append_run(xArray, 0, bounds.width());
836 }
837 // create a new record for this Y value
838 currY = yArray.append();
839 currY->fY = bot - 1;
840 currY->fOffset = xArray.count();
841 prevRight = 0;
842 prevBot = bot;
843 }
844
845 int x = r.fLeft - offsetX;
846 append_run(xArray, 0, x - prevRight);
847
848 int w = r.fRight - r.fLeft;
849 append_run(xArray, 0xFF, w);
850 prevRight = x + w;
851 SkASSERT(prevRight <= bounds.width());
852 }
853 // flush last row
854 append_run(xArray, 0, bounds.width() - prevRight);
855
856 // now pack everything into a RunHead
857 RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
858 memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
859 memcpy(head->data(), xArray.begin(), xArray.bytes());
860
861 this->setEmpty();
862 fBounds = bounds;
863 fRunHead = head;
864 this->validate();
865 return true;
866#endif
reed@google.come36707a2011-10-04 21:38:55 +0000867}
868
869///////////////////////////////////////////////////////////////////////////////
870
871const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000872 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000873
874 if (!y_in_rect(y, fBounds)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700875 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000876 }
877 y -= fBounds.y(); // our yoffs values are relative to the top
878
879 const YOffset* yoff = fRunHead->yoffsets();
880 while (yoff->fY < y) {
881 yoff += 1;
882 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
883 }
884
885 if (lastYForRow) {
reed@google.com045e62d2011-10-24 12:19:46 +0000886 *lastYForRow = fBounds.y() + yoff->fY;
reed@google.come36707a2011-10-04 21:38:55 +0000887 }
888 return fRunHead->data() + yoff->fOffset;
889}
890
891const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
892 SkASSERT(x_in_rect(x, fBounds));
893 x -= fBounds.x();
894
895 // first skip up to X
896 for (;;) {
897 int n = data[0];
898 if (x < n) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000899 if (initialCount) {
900 *initialCount = n - x;
901 }
reed@google.come36707a2011-10-04 21:38:55 +0000902 break;
903 }
904 data += 2;
905 x -= n;
906 }
907 return data;
908}
909
910bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
911 if (this->isEmpty()) {
912 return false;
913 }
914 if (!fBounds.contains(left, top, right, bottom)) {
915 return false;
916 }
reed@google.com32287892011-10-05 16:27:44 +0000917#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000918 if (this->isRect()) {
919 return true;
920 }
reed@google.com32287892011-10-05 16:27:44 +0000921#endif
reed@google.come36707a2011-10-04 21:38:55 +0000922
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000923 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +0000924 const uint8_t* row = this->findRow(top, &lastY);
925 if (lastY < bottom) {
926 return false;
927 }
928 // now just need to check in X
reed@google.com045e62d2011-10-24 12:19:46 +0000929 int count;
930 row = this->findX(row, left, &count);
931#if 0
932 return count >= (right - left) && 0xFF == row[1];
933#else
934 int rectWidth = right - left;
935 while (0xFF == row[1]) {
936 if (count >= rectWidth) {
937 return true;
938 }
939 rectWidth -= count;
940 row += 2;
941 count = row[0];
942 }
943 return false;
944#endif
reed@google.come36707a2011-10-04 21:38:55 +0000945}
946
947///////////////////////////////////////////////////////////////////////////////
948
949class SkAAClip::Builder {
950 SkIRect fBounds;
951 struct Row {
952 int fY;
953 int fWidth;
954 SkTDArray<uint8_t>* fData;
955 };
956 SkTDArray<Row> fRows;
957 Row* fCurrRow;
958 int fPrevY;
959 int fWidth;
reed@google.com209c4152011-10-26 15:03:48 +0000960 int fMinY;
reed@google.come36707a2011-10-04 21:38:55 +0000961
962public:
963 Builder(const SkIRect& bounds) : fBounds(bounds) {
964 fPrevY = -1;
965 fWidth = bounds.width();
halcanary96fcdcc2015-08-27 07:41:13 -0700966 fCurrRow = nullptr;
reed@google.com209c4152011-10-26 15:03:48 +0000967 fMinY = bounds.fTop;
reed@google.come36707a2011-10-04 21:38:55 +0000968 }
969
970 ~Builder() {
971 Row* row = fRows.begin();
972 Row* stop = fRows.end();
973 while (row < stop) {
974 delete row->fData;
975 row += 1;
976 }
977 }
978
reed@google.com32287892011-10-05 16:27:44 +0000979 const SkIRect& getBounds() const { return fBounds; }
980
reed@google.come36707a2011-10-04 21:38:55 +0000981 void addRun(int x, int y, U8CPU alpha, int count) {
982 SkASSERT(count > 0);
983 SkASSERT(fBounds.contains(x, y));
984 SkASSERT(fBounds.contains(x + count - 1, y));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000985
reed@google.come36707a2011-10-04 21:38:55 +0000986 x -= fBounds.left();
987 y -= fBounds.top();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000988
reed@google.come36707a2011-10-04 21:38:55 +0000989 Row* row = fCurrRow;
990 if (y != fPrevY) {
991 SkASSERT(y > fPrevY);
992 fPrevY = y;
993 row = this->flushRow(true);
994 row->fY = y;
995 row->fWidth = 0;
996 SkASSERT(row->fData);
997 SkASSERT(0 == row->fData->count());
998 fCurrRow = row;
999 }
1000
1001 SkASSERT(row->fWidth <= x);
1002 SkASSERT(row->fWidth < fBounds.width());
1003
1004 SkTDArray<uint8_t>& data = *row->fData;
1005
1006 int gap = x - row->fWidth;
1007 if (gap) {
1008 AppendRun(data, 0, gap);
1009 row->fWidth += gap;
1010 SkASSERT(row->fWidth < fBounds.width());
1011 }
1012
1013 AppendRun(data, alpha, count);
1014 row->fWidth += count;
1015 SkASSERT(row->fWidth <= fBounds.width());
1016 }
1017
tomhudson@google.com49eac192011-12-27 13:59:20 +00001018 void addColumn(int x, int y, U8CPU alpha, int height) {
1019 SkASSERT(fBounds.contains(x, y + height - 1));
1020
1021 this->addRun(x, y, alpha, 1);
1022 this->flushRowH(fCurrRow);
1023 y -= fBounds.fTop;
1024 SkASSERT(y == fCurrRow->fY);
1025 fCurrRow->fY = y + height - 1;
1026 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001027
reed@google.com9154eb02011-10-31 16:07:28 +00001028 void addRectRun(int x, int y, int width, int height) {
1029 SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
1030 this->addRun(x, y, 0xFF, width);
1031
reed@google.coma89c77b2011-12-01 21:47:26 +00001032 // we assum the rect must be all we'll see for these scanlines
reed@google.com9154eb02011-10-31 16:07:28 +00001033 // so we ensure our row goes all the way to our right
1034 this->flushRowH(fCurrRow);
1035
1036 y -= fBounds.fTop;
1037 SkASSERT(y == fCurrRow->fY);
1038 fCurrRow->fY = y + height - 1;
1039 }
1040
tomhudson@google.com49eac192011-12-27 13:59:20 +00001041 void addAntiRectRun(int x, int y, int width, int height,
1042 SkAlpha leftAlpha, SkAlpha rightAlpha) {
liyuqian2add0ff2016-10-20 11:04:39 -07001043 // According to SkBlitter.cpp, no matter whether leftAlpha is 0 or positive,
1044 // we should always consider [x, x+1] as the left-most column and [x+1, x+1+width]
1045 // as the rect with full alpha.
1046 SkASSERT(fBounds.contains(x + width + (rightAlpha > 0 ? 1 : 0),
tomhudson@google.com49eac192011-12-27 13:59:20 +00001047 y + height - 1));
1048 SkASSERT(width >= 0);
1049
1050 // Conceptually we're always adding 3 runs, but we should
1051 // merge or omit them if possible.
1052 if (leftAlpha == 0xFF) {
1053 width++;
1054 } else if (leftAlpha > 0) {
1055 this->addRun(x++, y, leftAlpha, 1);
liyuqian2add0ff2016-10-20 11:04:39 -07001056 } else {
1057 // leftAlpha is 0, ignore the left column
1058 x++;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001059 }
1060 if (rightAlpha == 0xFF) {
1061 width++;
1062 }
1063 if (width > 0) {
1064 this->addRun(x, y, 0xFF, width);
1065 }
1066 if (rightAlpha > 0 && rightAlpha < 255) {
1067 this->addRun(x + width, y, rightAlpha, 1);
1068 }
1069
Mike Reed1b7cd332018-06-05 09:55:17 -04001070 // if we never called addRun, we might not have a fCurrRow yet
1071 if (fCurrRow) {
1072 // we assume the rect must be all we'll see for these scanlines
1073 // so we ensure our row goes all the way to our right
1074 this->flushRowH(fCurrRow);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001075
Mike Reed1b7cd332018-06-05 09:55:17 -04001076 y -= fBounds.fTop;
1077 SkASSERT(y == fCurrRow->fY);
1078 fCurrRow->fY = y + height - 1;
1079 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001080 }
1081
reed@google.com045e62d2011-10-24 12:19:46 +00001082 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +00001083 this->flushRow(false);
1084
1085 const Row* row = fRows.begin();
1086 const Row* stop = fRows.end();
1087
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001088 size_t dataSize = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001089 while (row < stop) {
1090 dataSize += row->fData->count();
1091 row += 1;
1092 }
1093
reed@google.com045e62d2011-10-24 12:19:46 +00001094 if (0 == dataSize) {
1095 return target->setEmpty();
1096 }
1097
reed@google.com209c4152011-10-26 15:03:48 +00001098 SkASSERT(fMinY >= fBounds.fTop);
1099 SkASSERT(fMinY < fBounds.fBottom);
1100 int adjustY = fMinY - fBounds.fTop;
1101 fBounds.fTop = fMinY;
1102
reed@google.come36707a2011-10-04 21:38:55 +00001103 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
1104 YOffset* yoffset = head->yoffsets();
1105 uint8_t* data = head->data();
1106 uint8_t* baseData = data;
1107
1108 row = fRows.begin();
reed@google.comc9041912011-10-27 16:58:46 +00001109 SkDEBUGCODE(int prevY = row->fY - 1;)
reed@google.come36707a2011-10-04 21:38:55 +00001110 while (row < stop) {
reed@google.comc9041912011-10-27 16:58:46 +00001111 SkASSERT(prevY < row->fY); // must be monotonic
1112 SkDEBUGCODE(prevY = row->fY);
1113
reed@google.com209c4152011-10-26 15:03:48 +00001114 yoffset->fY = row->fY - adjustY;
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001115 yoffset->fOffset = SkToU32(data - baseData);
reed@google.come36707a2011-10-04 21:38:55 +00001116 yoffset += 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001117
reed@google.come36707a2011-10-04 21:38:55 +00001118 size_t n = row->fData->count();
1119 memcpy(data, row->fData->begin(), n);
reed@google.comc9041912011-10-27 16:58:46 +00001120#ifdef SK_DEBUG
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001121 size_t bytesNeeded = compute_row_length(data, fBounds.width());
reed@google.comc9041912011-10-27 16:58:46 +00001122 SkASSERT(bytesNeeded == n);
1123#endif
reed@google.come36707a2011-10-04 21:38:55 +00001124 data += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001125
reed@google.come36707a2011-10-04 21:38:55 +00001126 row += 1;
1127 }
1128
reed@google.com045e62d2011-10-24 12:19:46 +00001129 target->freeRuns();
1130 target->fBounds = fBounds;
1131 target->fRunHead = head;
1132 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +00001133 }
1134
1135 void dump() {
1136 this->validate();
1137 int y;
1138 for (y = 0; y < fRows.count(); ++y) {
1139 const Row& row = fRows[y];
1140 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
1141 const SkTDArray<uint8_t>& data = *row.fData;
1142 int count = data.count();
1143 SkASSERT(!(count & 1));
1144 const uint8_t* ptr = data.begin();
1145 for (int x = 0; x < count; x += 2) {
1146 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
1147 ptr += 2;
1148 }
1149 SkDebugf("\n");
1150 }
reed@google.come36707a2011-10-04 21:38:55 +00001151 }
1152
1153 void validate() {
1154#ifdef SK_DEBUG
caryclark@google.com803eceb2012-06-06 12:09:34 +00001155 if (false) { // avoid bit rot, suppress warning
1156 test_count_left_right_zeros();
1157 }
reed@google.come36707a2011-10-04 21:38:55 +00001158 int prevY = -1;
1159 for (int i = 0; i < fRows.count(); ++i) {
1160 const Row& row = fRows[i];
1161 SkASSERT(prevY < row.fY);
1162 SkASSERT(fWidth == row.fWidth);
1163 int count = row.fData->count();
1164 const uint8_t* ptr = row.fData->begin();
1165 SkASSERT(!(count & 1));
1166 int w = 0;
1167 for (int x = 0; x < count; x += 2) {
reed@google.comd6040f62011-10-28 02:39:17 +00001168 int n = ptr[0];
1169 SkASSERT(n > 0);
1170 w += n;
reed@google.come36707a2011-10-04 21:38:55 +00001171 SkASSERT(w <= fWidth);
1172 ptr += 2;
1173 }
1174 SkASSERT(w == fWidth);
1175 prevY = row.fY;
1176 }
1177#endif
1178 }
1179
reed@google.com209c4152011-10-26 15:03:48 +00001180 // only called by BuilderBlitter
1181 void setMinY(int y) {
1182 fMinY = y;
1183 }
1184
reed@google.come36707a2011-10-04 21:38:55 +00001185private:
reed@google.com9154eb02011-10-31 16:07:28 +00001186 void flushRowH(Row* row) {
1187 // flush current row if needed
1188 if (row->fWidth < fWidth) {
1189 AppendRun(*row->fData, 0, fWidth - row->fWidth);
1190 row->fWidth = fWidth;
1191 }
1192 }
reed@google.com209c4152011-10-26 15:03:48 +00001193
reed@google.come36707a2011-10-04 21:38:55 +00001194 Row* flushRow(bool readyForAnother) {
halcanary96fcdcc2015-08-27 07:41:13 -07001195 Row* next = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001196 int count = fRows.count();
1197 if (count > 0) {
reed@google.com9154eb02011-10-31 16:07:28 +00001198 this->flushRowH(&fRows[count - 1]);
reed@google.come36707a2011-10-04 21:38:55 +00001199 }
1200 if (count > 1) {
1201 // are our last two runs the same?
1202 Row* prev = &fRows[count - 2];
1203 Row* curr = &fRows[count - 1];
1204 SkASSERT(prev->fWidth == fWidth);
1205 SkASSERT(curr->fWidth == fWidth);
1206 if (*prev->fData == *curr->fData) {
1207 prev->fY = curr->fY;
1208 if (readyForAnother) {
1209 curr->fData->rewind();
1210 next = curr;
1211 } else {
1212 delete curr->fData;
1213 fRows.removeShuffle(count - 1);
1214 }
1215 } else {
1216 if (readyForAnother) {
1217 next = fRows.append();
1218 next->fData = new SkTDArray<uint8_t>;
1219 }
1220 }
1221 } else {
1222 if (readyForAnother) {
1223 next = fRows.append();
1224 next->fData = new SkTDArray<uint8_t>;
1225 }
1226 }
1227 return next;
1228 }
1229
1230 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
1231 do {
1232 int n = count;
1233 if (n > 255) {
1234 n = 255;
1235 }
1236 uint8_t* ptr = data.append(2);
1237 ptr[0] = n;
1238 ptr[1] = alpha;
1239 count -= n;
1240 } while (count > 0);
1241 }
1242};
1243
1244class SkAAClip::BuilderBlitter : public SkBlitter {
reed@google.com80cdb9a2012-02-16 18:56:17 +00001245 int fLastY;
1246
1247 /*
1248 If we see a gap of 1 or more empty scanlines while building in Y-order,
1249 we inject an explicit empty scanline (alpha==0)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001250
reed@google.com80cdb9a2012-02-16 18:56:17 +00001251 See AAClipTest.cpp : test_path_with_hole()
1252 */
1253 void checkForYGap(int y) {
1254 SkASSERT(y >= fLastY);
1255 if (fLastY > -SK_MaxS32) {
1256 int gap = y - fLastY;
1257 if (gap > 1) {
1258 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
1259 }
1260 }
1261 fLastY = y;
1262 }
1263
reed@google.come36707a2011-10-04 21:38:55 +00001264public:
reed@google.com80cdb9a2012-02-16 18:56:17 +00001265
reed@google.come36707a2011-10-04 21:38:55 +00001266 BuilderBlitter(Builder* builder) {
1267 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001268 fLeft = builder->getBounds().fLeft;
1269 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001270 fMinY = SK_MaxS32;
reed@google.com80cdb9a2012-02-16 18:56:17 +00001271 fLastY = -SK_MaxS32; // sentinel
reed@google.com209c4152011-10-26 15:03:48 +00001272 }
1273
1274 void finish() {
1275 if (fMinY < SK_MaxS32) {
1276 fBuilder->setMinY(fMinY);
1277 }
reed@google.come36707a2011-10-04 21:38:55 +00001278 }
1279
tomhudson@google.com49eac192011-12-27 13:59:20 +00001280 /**
1281 Must evaluate clips in scan-line order, so don't want to allow blitV(),
1282 but an AAClip can be clipped down to a single pixel wide, so we
1283 must support it (given AntiRect semantics: minimum width is 2).
1284 Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
1285 any failure cases that misses may have minor artifacts.
1286 */
mtklein36352bf2015-03-25 18:17:31 -07001287 void blitV(int x, int y, int height, SkAlpha alpha) override {
liyuqian2add0ff2016-10-20 11:04:39 -07001288 if (height == 1) {
1289 // We're still in scan-line order if height is 1
1290 // This is useful for Analytic AA
1291 const SkAlpha alphas[2] = {alpha, 0};
1292 const int16_t runs[2] = {1, 0};
1293 this->blitAntiH(x, y, alphas, runs);
1294 } else {
1295 this->recordMinY(y);
1296 fBuilder->addColumn(x, y, alpha, height);
1297 fLastY = y + height - 1;
1298 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001299 }
reed@google.com045e62d2011-10-24 12:19:46 +00001300
mtklein36352bf2015-03-25 18:17:31 -07001301 void blitRect(int x, int y, int width, int height) override {
reed@google.com9154eb02011-10-31 16:07:28 +00001302 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001303 this->checkForYGap(y);
reed@google.com9154eb02011-10-31 16:07:28 +00001304 fBuilder->addRectRun(x, y, width, height);
reed@google.com302b8612012-02-16 19:30:13 +00001305 fLastY = y + height - 1;
reed@google.com562a2ac2011-10-31 14:14:18 +00001306 }
reed@google.com045e62d2011-10-24 12:19:46 +00001307
tomhudson@google.com49eac192011-12-27 13:59:20 +00001308 virtual void blitAntiRect(int x, int y, int width, int height,
mtklein36352bf2015-03-25 18:17:31 -07001309 SkAlpha leftAlpha, SkAlpha rightAlpha) override {
tomhudson@google.com49eac192011-12-27 13:59:20 +00001310 this->recordMinY(y);
reed@google.com302b8612012-02-16 19:30:13 +00001311 this->checkForYGap(y);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001312 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
reed@google.com302b8612012-02-16 19:30:13 +00001313 fLastY = y + height - 1;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001314 }
1315
mtklein36352bf2015-03-25 18:17:31 -07001316 void blitMask(const SkMask&, const SkIRect& clip) override
reed@google.come36707a2011-10-04 21:38:55 +00001317 { unexpected(); }
1318
reed41e010c2015-06-09 12:16:53 -07001319 const SkPixmap* justAnOpaqueColor(uint32_t*) override {
halcanary96fcdcc2015-08-27 07:41:13 -07001320 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001321 }
1322
mtklein36352bf2015-03-25 18:17:31 -07001323 void blitH(int x, int y, int width) override {
reed@google.com209c4152011-10-26 15:03:48 +00001324 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001325 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001326 fBuilder->addRun(x, y, 0xFF, width);
1327 }
1328
1329 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
mtklein36352bf2015-03-25 18:17:31 -07001330 const int16_t runs[]) override {
reed@google.com209c4152011-10-26 15:03:48 +00001331 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001332 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001333 for (;;) {
1334 int count = *runs;
1335 if (count <= 0) {
1336 return;
1337 }
reed@google.com17785642011-10-12 20:23:55 +00001338
1339 // The supersampler's buffer can be the width of the device, so
liyuqian1d3ab122016-11-08 13:55:15 -08001340 // we may have to trim the run to our bounds. Previously, we assert that
1341 // the extra spans are always alpha==0.
1342 // However, the analytic AA is too sensitive to precision errors
1343 // so it may have extra spans with very tiny alpha because after several
1344 // arithmatic operations, the edge may bleed the path boundary a little bit.
1345 // Therefore, instead of always asserting alpha==0, we assert alpha < 0x10.
reed@google.com17785642011-10-12 20:23:55 +00001346 int localX = x;
1347 int localCount = count;
1348 if (x < fLeft) {
liyuqian1d3ab122016-11-08 13:55:15 -08001349 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001350 int gap = fLeft - x;
1351 SkASSERT(gap <= count);
1352 localX += gap;
1353 localCount -= gap;
1354 }
1355 int right = x + count;
1356 if (right > fRight) {
liyuqian1d3ab122016-11-08 13:55:15 -08001357 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001358 localCount -= right - fRight;
1359 SkASSERT(localCount >= 0);
1360 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001361
reed@google.com17785642011-10-12 20:23:55 +00001362 if (localCount) {
1363 fBuilder->addRun(localX, y, *alpha, localCount);
1364 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001365 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001366 runs += count;
1367 alpha += count;
1368 x += count;
1369 }
1370 }
1371
1372private:
1373 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001374 int fLeft; // cache of builder's bounds' left edge
1375 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001376 int fMinY;
1377
1378 /*
1379 * We track this, in case the scan converter skipped some number of
1380 * scanlines at the (relative to the bounds it was given). This allows
1381 * the builder, during its finish, to trip its bounds down to the "real"
1382 * top.
1383 */
1384 void recordMinY(int y) {
1385 if (y < fMinY) {
1386 fMinY = y;
1387 }
1388 }
reed@google.come36707a2011-10-04 21:38:55 +00001389
1390 void unexpected() {
Ben Wagner7ca9a742017-08-17 14:05:04 -04001391 SK_ABORT("---- did not expect to get called here");
reed@google.come36707a2011-10-04 21:38:55 +00001392 }
1393};
1394
reed@google.comf3c1da12011-10-10 19:35:47 +00001395bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001396 AUTO_AACLIP_VALIDATE(*this);
1397
reed@google.com32287892011-10-05 16:27:44 +00001398 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001399 return this->setEmpty();
1400 }
1401
1402 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001403 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001404
reed@google.com32287892011-10-05 16:27:44 +00001405 SkRegion tmpClip;
halcanary96fcdcc2015-08-27 07:41:13 -07001406 if (nullptr == clip) {
reed@google.com32287892011-10-05 16:27:44 +00001407 tmpClip.setRect(ibounds);
1408 clip = &tmpClip;
1409 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001410
Yuqian Lica85fc32016-11-10 09:44:55 -05001411 // Since we assert that the BuilderBlitter will never blit outside the intersection
1412 // of clip and ibounds, we create this snugClip to be that intersection and send it
1413 // to the scan-converter.
1414 SkRegion snugClip(*clip);
1415
reed@google.com045e62d2011-10-24 12:19:46 +00001416 if (path.isInverseFillType()) {
1417 ibounds = clip->getBounds();
1418 } else {
reed@google.com32287892011-10-05 16:27:44 +00001419 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001420 return this->setEmpty();
1421 }
Yuqian Lica85fc32016-11-10 09:44:55 -05001422 snugClip.op(ibounds, SkRegion::kIntersect_Op);
reed@google.come36707a2011-10-04 21:38:55 +00001423 }
1424
1425 Builder builder(ibounds);
1426 BuilderBlitter blitter(&builder);
1427
reed@google.comf3c1da12011-10-10 19:35:47 +00001428 if (doAA) {
Yuqian Li7d99dad2017-07-26 13:47:26 -04001429 SkScan::AntiFillPath(path, snugClip, &blitter, true);
reed@google.comf3c1da12011-10-10 19:35:47 +00001430 } else {
Yuqian Lica85fc32016-11-10 09:44:55 -05001431 SkScan::FillPath(path, snugClip, &blitter);
reed@google.comf3c1da12011-10-10 19:35:47 +00001432 }
reed@google.come36707a2011-10-04 21:38:55 +00001433
reed@google.com209c4152011-10-26 15:03:48 +00001434 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001435 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001436}
1437
1438///////////////////////////////////////////////////////////////////////////////
1439
reed@google.com32287892011-10-05 16:27:44 +00001440typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1441 const uint8_t* rowA, const SkIRect& rectA,
1442 const uint8_t* rowB, const SkIRect& rectB);
1443
reed@google.com32287892011-10-05 16:27:44 +00001444typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1445
1446static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1447 // Multiply
1448 return SkMulDiv255Round(alphaA, alphaB);
1449}
1450
1451static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1452 // SrcOver
1453 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1454}
1455
1456static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1457 // SrcOut
1458 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1459}
1460
1461static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1462 // XOR
1463 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1464}
1465
1466static AlphaProc find_alpha_proc(SkRegion::Op op) {
1467 switch (op) {
1468 case SkRegion::kIntersect_Op:
1469 return sectAlphaProc;
1470 case SkRegion::kDifference_Op:
1471 return diffAlphaProc;
1472 case SkRegion::kUnion_Op:
1473 return unionAlphaProc;
1474 case SkRegion::kXOR_Op:
1475 return xorAlphaProc;
1476 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001477 SkDEBUGFAIL("unexpected region op");
reed@google.com32287892011-10-05 16:27:44 +00001478 return sectAlphaProc;
1479 }
1480}
1481
reed@google.com32287892011-10-05 16:27:44 +00001482class RowIter {
1483public:
1484 RowIter(const uint8_t* row, const SkIRect& bounds) {
1485 fRow = row;
1486 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001487 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001488 if (row) {
1489 fRight = bounds.fLeft + row[0];
1490 SkASSERT(fRight <= fBoundsRight);
1491 fAlpha = row[1];
1492 fDone = false;
1493 } else {
1494 fDone = true;
1495 fRight = kMaxInt32;
1496 fAlpha = 0;
1497 }
reed@google.com32287892011-10-05 16:27:44 +00001498 }
1499
1500 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001501 int left() const { return fLeft; }
1502 int right() const { return fRight; }
1503 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001504 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001505 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001506 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001507 if (fRight == fBoundsRight) {
1508 fDone = true;
1509 fRight = kMaxInt32;
1510 fAlpha = 0;
1511 } else {
1512 fRow += 2;
1513 fRight += fRow[0];
1514 fAlpha = fRow[1];
1515 SkASSERT(fRight <= fBoundsRight);
1516 }
reed@google.com32287892011-10-05 16:27:44 +00001517 }
1518 }
1519
1520private:
1521 const uint8_t* fRow;
1522 int fLeft;
1523 int fRight;
1524 int fBoundsRight;
1525 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001526 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001527};
1528
reed@google.com1c04bf92011-10-10 12:57:12 +00001529static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1530 if (rite == riteA) {
1531 iter.next();
1532 leftA = iter.left();
1533 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001534 }
1535}
1536
caryclark@google.com803eceb2012-06-06 12:09:34 +00001537#if 0 // UNUSED
reed@google.com1c04bf92011-10-10 12:57:12 +00001538static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1539 SkASSERT(min < max);
1540 SkASSERT(boundsMin < boundsMax);
1541 if (min >= boundsMax || max <= boundsMin) {
1542 return false;
1543 }
1544 if (min < boundsMin) {
1545 min = boundsMin;
1546 }
1547 if (max > boundsMax) {
1548 max = boundsMax;
1549 }
1550 return true;
1551}
caryclark@google.com803eceb2012-06-06 12:09:34 +00001552#endif
reed@google.com1c04bf92011-10-10 12:57:12 +00001553
reed@google.com32287892011-10-05 16:27:44 +00001554static void operatorX(SkAAClip::Builder& builder, int lastY,
1555 RowIter& iterA, RowIter& iterB,
1556 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001557 int leftA = iterA.left();
1558 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001559 int leftB = iterB.left();
1560 int riteB = iterB.right();
1561
reed@google.com1c04bf92011-10-10 12:57:12 +00001562 int prevRite = bounds.fLeft;
1563
1564 do {
reed@google.com32287892011-10-05 16:27:44 +00001565 U8CPU alphaA = 0;
1566 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001567 int left, rite;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001568
reed@google.com1c04bf92011-10-10 12:57:12 +00001569 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001570 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001571 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001572 if (riteA <= leftB) {
1573 rite = riteA;
1574 } else {
1575 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001576 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001577 } else if (leftB < leftA) {
1578 left = leftB;
1579 alphaB = iterB.alpha();
1580 if (riteB <= leftA) {
1581 rite = riteB;
1582 } else {
1583 rite = leftB = leftA;
1584 }
1585 } else {
1586 left = leftA; // or leftB, since leftA == leftB
1587 rite = leftA = leftB = SkMin32(riteA, riteB);
1588 alphaA = iterA.alpha();
1589 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001590 }
1591
1592 if (left >= bounds.fRight) {
1593 break;
1594 }
reed@google.com34f7e472011-10-13 15:11:59 +00001595 if (rite > bounds.fRight) {
1596 rite = bounds.fRight;
1597 }
1598
reed@google.com32287892011-10-05 16:27:44 +00001599 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001600 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001601 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001602 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001603 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001604
1605 adjust_row(iterA, leftA, riteA, rite);
1606 adjust_row(iterB, leftB, riteB, rite);
1607 } while (!iterA.done() || !iterB.done());
1608
1609 if (prevRite < bounds.fRight) {
1610 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001611 }
1612}
1613
reed@google.com1c04bf92011-10-10 12:57:12 +00001614static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1615 if (bot == botA) {
1616 iter.next();
1617 topA = botA;
1618 SkASSERT(botA == iter.top());
1619 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001620 }
1621}
1622
1623static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1624 const SkAAClip& B, SkRegion::Op op) {
1625 AlphaProc proc = find_alpha_proc(op);
1626 const SkIRect& bounds = builder.getBounds();
1627
1628 SkAAClip::Iter iterA(A);
1629 SkAAClip::Iter iterB(B);
1630
1631 SkASSERT(!iterA.done());
1632 int topA = iterA.top();
1633 int botA = iterA.bottom();
1634 SkASSERT(!iterB.done());
1635 int topB = iterB.top();
1636 int botB = iterB.bottom();
1637
reed@google.com1c04bf92011-10-10 12:57:12 +00001638 do {
halcanary96fcdcc2015-08-27 07:41:13 -07001639 const uint8_t* rowA = nullptr;
1640 const uint8_t* rowB = nullptr;
reed@google.com32287892011-10-05 16:27:44 +00001641 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001642
1643 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001644 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001645 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001646 if (botA <= topB) {
1647 bot = botA;
1648 } else {
1649 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001650 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001651
reed@google.com1c04bf92011-10-10 12:57:12 +00001652 } else if (topB < topA) {
1653 top = topB;
1654 rowB = iterB.data();
1655 if (botB <= topA) {
1656 bot = botB;
1657 } else {
1658 bot = topB = topA;
1659 }
1660 } else {
1661 top = topA; // or topB, since topA == topB
1662 bot = topA = topB = SkMin32(botA, botB);
1663 rowA = iterA.data();
1664 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001665 }
1666
1667 if (top >= bounds.fBottom) {
1668 break;
1669 }
reed@google.com34f7e472011-10-13 15:11:59 +00001670
1671 if (bot > bounds.fBottom) {
1672 bot = bounds.fBottom;
1673 }
1674 SkASSERT(top < bot);
1675
reed@google.com1c04bf92011-10-10 12:57:12 +00001676 if (!rowA && !rowB) {
1677 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1678 } else if (top >= bounds.fTop) {
1679 SkASSERT(bot <= bounds.fBottom);
1680 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1681 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001682 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001683 }
1684
reed@google.com1c04bf92011-10-10 12:57:12 +00001685 adjust_iter(iterA, topA, botA, bot);
1686 adjust_iter(iterB, topB, botB, bot);
1687 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001688}
1689
1690bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1691 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001692 AUTO_AACLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001693
reed@google.com32287892011-10-05 16:27:44 +00001694 if (SkRegion::kReplace_Op == op) {
1695 return this->set(clipBOrig);
1696 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001697
reed@google.com32287892011-10-05 16:27:44 +00001698 const SkAAClip* clipA = &clipAOrig;
1699 const SkAAClip* clipB = &clipBOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001700
reed@google.com32287892011-10-05 16:27:44 +00001701 if (SkRegion::kReverseDifference_Op == op) {
1702 SkTSwap(clipA, clipB);
1703 op = SkRegion::kDifference_Op;
1704 }
1705
1706 bool a_empty = clipA->isEmpty();
1707 bool b_empty = clipB->isEmpty();
1708
1709 SkIRect bounds;
1710 switch (op) {
1711 case SkRegion::kDifference_Op:
1712 if (a_empty) {
1713 return this->setEmpty();
1714 }
1715 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1716 return this->set(*clipA);
1717 }
1718 bounds = clipA->fBounds;
1719 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001720
reed@google.com32287892011-10-05 16:27:44 +00001721 case SkRegion::kIntersect_Op:
1722 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1723 clipB->fBounds)) {
1724 return this->setEmpty();
1725 }
1726 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001727
reed@google.com32287892011-10-05 16:27:44 +00001728 case SkRegion::kUnion_Op:
1729 case SkRegion::kXOR_Op:
1730 if (a_empty) {
1731 return this->set(*clipB);
1732 }
1733 if (b_empty) {
1734 return this->set(*clipA);
1735 }
1736 bounds = clipA->fBounds;
1737 bounds.join(clipB->fBounds);
1738 break;
1739
1740 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001741 SkDEBUGFAIL("unknown region op");
reed@google.com32287892011-10-05 16:27:44 +00001742 return !this->isEmpty();
1743 }
1744
reed@google.com32287892011-10-05 16:27:44 +00001745 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1746 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1747
1748 Builder builder(bounds);
1749 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001750
1751 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001752}
1753
reed@google.com045e62d2011-10-24 12:19:46 +00001754/*
1755 * It can be expensive to build a local aaclip before applying the op, so
1756 * we first see if we can restrict the bounds of new rect to our current
1757 * bounds, or note that the new rect subsumes our current clip.
1758 */
1759
1760bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1761 SkIRect rStorage;
1762 const SkIRect* r = &rOrig;
1763
1764 switch (op) {
1765 case SkRegion::kIntersect_Op:
1766 if (!rStorage.intersect(rOrig, fBounds)) {
1767 // no overlap, so we're empty
1768 return this->setEmpty();
1769 }
1770 if (rStorage == fBounds) {
1771 // we were wholly inside the rect, no change
1772 return !this->isEmpty();
1773 }
1774 if (this->quickContains(rStorage)) {
1775 // the intersection is wholly inside us, we're a rect
1776 return this->setRect(rStorage);
1777 }
1778 r = &rStorage; // use the intersected bounds
1779 break;
1780 case SkRegion::kDifference_Op:
1781 break;
1782 case SkRegion::kUnion_Op:
1783 if (rOrig.contains(fBounds)) {
1784 return this->setRect(rOrig);
1785 }
1786 break;
1787 default:
1788 break;
1789 }
1790
reed@google.com47ac84e2011-10-06 13:11:25 +00001791 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001792 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001793 return this->op(*this, clip, op);
1794}
1795
reed@google.com045e62d2011-10-24 12:19:46 +00001796bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1797 SkRect rStorage, boundsStorage;
1798 const SkRect* r = &rOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001799
reed@google.com045e62d2011-10-24 12:19:46 +00001800 boundsStorage.set(fBounds);
1801 switch (op) {
1802 case SkRegion::kIntersect_Op:
1803 case SkRegion::kDifference_Op:
1804 if (!rStorage.intersect(rOrig, boundsStorage)) {
reed@google.come56513d2012-06-25 20:06:33 +00001805 if (SkRegion::kIntersect_Op == op) {
1806 return this->setEmpty();
1807 } else { // kDifference
1808 return !this->isEmpty();
1809 }
reed@google.com045e62d2011-10-24 12:19:46 +00001810 }
1811 r = &rStorage; // use the intersected bounds
1812 break;
1813 case SkRegion::kUnion_Op:
1814 if (rOrig.contains(boundsStorage)) {
1815 return this->setRect(rOrig);
1816 }
1817 break;
1818 default:
1819 break;
1820 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001821
reed@google.com47ac84e2011-10-06 13:11:25 +00001822 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001823 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001824 return this->op(*this, clip, op);
1825}
1826
1827bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1828 return this->op(*this, clip, op);
1829}
1830
reed@google.come36707a2011-10-04 21:38:55 +00001831///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001832
1833bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -07001834 if (nullptr == dst) {
reed@google.com045e62d2011-10-24 12:19:46 +00001835 return !this->isEmpty();
1836 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001837
reed@google.com045e62d2011-10-24 12:19:46 +00001838 if (this->isEmpty()) {
1839 return dst->setEmpty();
1840 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001841
reed@google.com045e62d2011-10-24 12:19:46 +00001842 if (this != dst) {
1843 sk_atomic_inc(&fRunHead->fRefCnt);
tomhudson@google.com19224c32012-03-28 15:46:37 +00001844 dst->freeRuns();
reed@google.com045e62d2011-10-24 12:19:46 +00001845 dst->fRunHead = fRunHead;
1846 dst->fBounds = fBounds;
1847 }
1848 dst->fBounds.offset(dx, dy);
1849 return true;
1850}
1851
1852static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1853 const uint8_t* SK_RESTRICT row,
1854 int width) {
1855 while (width > 0) {
1856 int n = row[0];
1857 SkASSERT(width >= n);
1858 memset(mask, row[1], n);
1859 mask += n;
1860 row += 2;
1861 width -= n;
1862 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001863 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001864}
1865
1866void SkAAClip::copyToMask(SkMask* mask) const {
1867 mask->fFormat = SkMask::kA8_Format;
1868 if (this->isEmpty()) {
1869 mask->fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -07001870 mask->fImage = nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00001871 mask->fRowBytes = 0;
1872 return;
1873 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001874
reed@google.com045e62d2011-10-24 12:19:46 +00001875 mask->fBounds = fBounds;
1876 mask->fRowBytes = fBounds.width();
1877 size_t size = mask->computeImageSize();
1878 mask->fImage = SkMask::AllocImage(size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001879
reed@google.com045e62d2011-10-24 12:19:46 +00001880 Iter iter(*this);
1881 uint8_t* dst = mask->fImage;
1882 const int width = fBounds.width();
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001883
reed@google.com045e62d2011-10-24 12:19:46 +00001884 int y = fBounds.fTop;
1885 while (!iter.done()) {
1886 do {
1887 expand_row_to_mask(dst, iter.data(), width);
1888 dst += mask->fRowBytes;
1889 } while (++y < iter.bottom());
1890 iter.next();
1891 }
1892}
1893
1894///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001895///////////////////////////////////////////////////////////////////////////////
1896
1897static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1898 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1899 // we don't read our initial n from data, since the caller may have had to
1900 // clip it, hence the initialCount parameter.
1901 int n = initialCount;
1902 for (;;) {
1903 if (n > width) {
1904 n = width;
1905 }
1906 SkASSERT(n > 0);
1907 runs[0] = n;
1908 runs += n;
1909
1910 aa[0] = data[1];
1911 aa += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001912
reed@google.come36707a2011-10-04 21:38:55 +00001913 data += 2;
1914 width -= n;
1915 if (0 == width) {
1916 break;
1917 }
1918 // load the next count
1919 n = data[0];
1920 }
1921 runs[0] = 0; // sentinel
1922}
1923
1924SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001925 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001926}
1927
1928void SkAAClipBlitter::ensureRunsAndAA() {
halcanary96fcdcc2015-08-27 07:41:13 -07001929 if (nullptr == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001930 // add 1 so we can store the terminating run count of 0
1931 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001932 // we use this either for fRuns + fAA, or a scaline of a mask
1933 // which may be as deep as 32bits
1934 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1935 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001936 fAA = (SkAlpha*)(fRuns + count);
1937 }
1938}
1939
1940void SkAAClipBlitter::blitH(int x, int y, int width) {
1941 SkASSERT(width > 0);
1942 SkASSERT(fAAClipBounds.contains(x, y));
1943 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1944
reed@google.coma4c6e4d2012-06-20 14:29:50 +00001945 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00001946 int initialCount;
1947 row = fAAClip->findX(row, x, &initialCount);
1948
1949 if (initialCount >= width) {
1950 SkAlpha alpha = row[1];
1951 if (0 == alpha) {
1952 return;
1953 }
1954 if (0xFF == alpha) {
1955 fBlitter->blitH(x, y, width);
1956 return;
1957 }
1958 }
1959
1960 this->ensureRunsAndAA();
1961 expandToRuns(row, initialCount, width, fRuns, fAA);
1962
1963 fBlitter->blitAntiH(x, y, fAA, fRuns);
1964}
1965
1966static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1967 const SkAlpha* SK_RESTRICT srcAA,
1968 const int16_t* SK_RESTRICT srcRuns,
1969 SkAlpha* SK_RESTRICT dstAA,
1970 int16_t* SK_RESTRICT dstRuns,
1971 int width) {
1972 SkDEBUGCODE(int accumulated = 0;)
1973 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001974 // do we need this check?
1975 if (0 == srcN) {
1976 return;
1977 }
1978
reed@google.come36707a2011-10-04 21:38:55 +00001979 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001980 SkASSERT(rowN > 0);
1981 SkASSERT(srcN > 0);
1982
1983 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1984 int minN = SkMin32(srcN, rowN);
1985 dstRuns[0] = minN;
1986 dstRuns += minN;
1987 dstAA[0] = newAlpha;
1988 dstAA += minN;
1989
1990 if (0 == (srcN -= minN)) {
1991 srcN = srcRuns[0]; // refresh
1992 srcRuns += srcN;
1993 srcAA += srcN;
1994 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001995 if (0 == srcN) {
1996 break;
1997 }
reed@google.come36707a2011-10-04 21:38:55 +00001998 }
1999 if (0 == (rowN -= minN)) {
2000 row += 2;
2001 rowN = row[0]; // reload
2002 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002003
reed@google.come36707a2011-10-04 21:38:55 +00002004 SkDEBUGCODE(accumulated += minN;)
2005 SkASSERT(accumulated <= width);
2006 }
reed@google.com34f7e472011-10-13 15:11:59 +00002007 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00002008}
2009
2010void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
2011 const int16_t runs[]) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002012
2013 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00002014 int initialCount;
2015 row = fAAClip->findX(row, x, &initialCount);
2016
2017 this->ensureRunsAndAA();
2018
2019 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
2020 fBlitter->blitAntiH(x, y, fAA, fRuns);
2021}
2022
2023void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
2024 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
2025 fBlitter->blitV(x, y, height, alpha);
2026 return;
2027 }
2028
reed@google.com045e62d2011-10-24 12:19:46 +00002029 for (;;) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002030 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +00002031 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00002032 int dy = lastY - y + 1;
2033 if (dy > height) {
2034 dy = height;
2035 }
2036 height -= dy;
2037
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002038 row = fAAClip->findX(row, x);
reed@google.come36707a2011-10-04 21:38:55 +00002039 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
2040 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00002041 fBlitter->blitV(x, y, dy, newAlpha);
2042 }
2043 SkASSERT(height >= 0);
2044 if (height <= 0) {
2045 break;
reed@google.come36707a2011-10-04 21:38:55 +00002046 }
2047 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00002048 }
reed@google.come36707a2011-10-04 21:38:55 +00002049}
2050
2051void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
2052 if (fAAClip->quickContains(x, y, x + width, y + height)) {
2053 fBlitter->blitRect(x, y, width, height);
2054 return;
2055 }
2056
2057 while (--height >= 0) {
2058 this->blitH(x, y, width);
2059 y += 1;
2060 }
2061}
2062
reed@google.com045e62d2011-10-24 12:19:46 +00002063typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
2064 int initialRowCount, void* dst);
2065
2066static void small_memcpy(void* dst, const void* src, size_t n) {
2067 memcpy(dst, src, n);
2068}
2069
2070static void small_bzero(void* dst, size_t n) {
2071 sk_bzero(dst, n);
2072}
2073
2074static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
2075 return SkMulDiv255Round(value, alpha);
2076}
reedd54d3fc2014-11-13 14:39:58 -08002077
reed@google.com045e62d2011-10-24 12:19:46 +00002078static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
2079 unsigned r = SkGetPackedR16(value);
2080 unsigned g = SkGetPackedG16(value);
2081 unsigned b = SkGetPackedB16(value);
2082 return SkPackRGB16(SkMulDiv255Round(r, alpha),
caryclark@google.com803eceb2012-06-06 12:09:34 +00002083 SkMulDiv255Round(g, alpha),
2084 SkMulDiv255Round(b, alpha));
reed@google.com045e62d2011-10-24 12:19:46 +00002085}
reed@google.com045e62d2011-10-24 12:19:46 +00002086
herb94496162015-12-10 14:17:41 -08002087template <typename T>
2088void mergeT(const void* inSrc, int srcN, const uint8_t* SK_RESTRICT row, int rowN, void* inDst) {
2089 const T* SK_RESTRICT src = static_cast<const T*>(inSrc);
2090 T* SK_RESTRICT dst = static_cast<T*>(inDst);
reed@google.com045e62d2011-10-24 12:19:46 +00002091 for (;;) {
2092 SkASSERT(rowN > 0);
2093 SkASSERT(srcN > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002094
reed@google.com045e62d2011-10-24 12:19:46 +00002095 int n = SkMin32(rowN, srcN);
2096 unsigned rowA = row[1];
2097 if (0xFF == rowA) {
2098 small_memcpy(dst, src, n * sizeof(T));
2099 } else if (0 == rowA) {
2100 small_bzero(dst, n * sizeof(T));
2101 } else {
2102 for (int i = 0; i < n; ++i) {
2103 dst[i] = mergeOne(src[i], rowA);
2104 }
2105 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002106
reed@google.com045e62d2011-10-24 12:19:46 +00002107 if (0 == (srcN -= n)) {
2108 break;
2109 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002110
reed@google.com045e62d2011-10-24 12:19:46 +00002111 src += n;
2112 dst += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002113
reed@google.com045e62d2011-10-24 12:19:46 +00002114 SkASSERT(rowN == n);
2115 row += 2;
2116 rowN = row[0];
2117 }
2118}
2119
2120static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2121 switch (format) {
2122 case SkMask::kBW_Format:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002123 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002124 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002125 case SkMask::kA8_Format:
herb94496162015-12-10 14:17:41 -08002126 case SkMask::k3D_Format:
2127 return mergeT<uint8_t> ;
2128 case SkMask::kLCD16_Format:
2129 return mergeT<uint16_t>;
reed@google.com045e62d2011-10-24 12:19:46 +00002130 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002131 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002132 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002133 }
2134}
2135
2136static U8CPU bit2byte(int bitInAByte) {
2137 SkASSERT(bitInAByte <= 0xFF);
2138 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2139 // some value >= 8 to get a full FF value
2140 return -bitInAByte >> 8;
2141}
2142
2143static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2144 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2145 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2146
2147 const int width = srcMask.fBounds.width();
2148 const int height = srcMask.fBounds.height();
2149
2150 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2151 const size_t srcRB = srcMask.fRowBytes;
2152 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2153 const size_t dstRB = dstMask->fRowBytes;
2154
2155 const int wholeBytes = width >> 3;
2156 const int leftOverBits = width & 7;
2157
2158 for (int y = 0; y < height; ++y) {
2159 uint8_t* SK_RESTRICT d = dst;
2160 for (int i = 0; i < wholeBytes; ++i) {
2161 int srcByte = src[i];
2162 d[0] = bit2byte(srcByte & (1 << 7));
2163 d[1] = bit2byte(srcByte & (1 << 6));
2164 d[2] = bit2byte(srcByte & (1 << 5));
2165 d[3] = bit2byte(srcByte & (1 << 4));
2166 d[4] = bit2byte(srcByte & (1 << 3));
2167 d[5] = bit2byte(srcByte & (1 << 2));
2168 d[6] = bit2byte(srcByte & (1 << 1));
2169 d[7] = bit2byte(srcByte & (1 << 0));
2170 d += 8;
2171 }
2172 if (leftOverBits) {
2173 int srcByte = src[wholeBytes];
2174 for (int x = 0; x < leftOverBits; ++x) {
2175 *d++ = bit2byte(srcByte & 0x80);
2176 srcByte <<= 1;
2177 }
2178 }
2179 src += srcRB;
2180 dst += dstRB;
2181 }
2182}
2183
2184void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2185 SkASSERT(fAAClip->getBounds().contains(clip));
2186
2187 if (fAAClip->quickContains(clip)) {
2188 fBlitter->blitMask(origMask, clip);
2189 return;
2190 }
2191
2192 const SkMask* mask = &origMask;
2193
2194 // if we're BW, we need to upscale to A8 (ugh)
2195 SkMask grayMask;
reed@google.com045e62d2011-10-24 12:19:46 +00002196 if (SkMask::kBW_Format == origMask.fFormat) {
2197 grayMask.fFormat = SkMask::kA8_Format;
2198 grayMask.fBounds = origMask.fBounds;
2199 grayMask.fRowBytes = origMask.fBounds.width();
2200 size_t size = grayMask.computeImageSize();
2201 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2202 SkAutoMalloc::kReuse_OnShrink);
2203
2204 upscaleBW2A8(&grayMask, origMask);
2205 mask = &grayMask;
2206 }
2207
2208 this->ensureRunsAndAA();
2209
2210 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2211 // data into a temp block to support it better (ugh)
2212
2213 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2214 const size_t srcRB = mask->fRowBytes;
2215 const int width = clip.width();
2216 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2217
2218 SkMask rowMask;
2219 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2220 rowMask.fBounds.fLeft = clip.fLeft;
2221 rowMask.fBounds.fRight = clip.fRight;
2222 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2223 rowMask.fImage = (uint8_t*)fScanlineScratch;
2224
2225 int y = clip.fTop;
2226 const int stopY = y + clip.height();
2227
2228 do {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002229 int localStopY SK_INIT_TO_AVOID_WARNING;
reed@google.com045e62d2011-10-24 12:19:46 +00002230 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2231 // findRow returns last Y, not stop, so we add 1
2232 localStopY = SkMin32(localStopY + 1, stopY);
2233
2234 int initialCount;
2235 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2236 do {
2237 mergeProc(src, width, row, initialCount, rowMask.fImage);
2238 rowMask.fBounds.fTop = y;
2239 rowMask.fBounds.fBottom = y + 1;
2240 fBlitter->blitMask(rowMask, rowMask.fBounds);
2241 src = (const void*)((const char*)src + srcRB);
2242 } while (++y < localStopY);
2243 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002244}
2245
reed41e010c2015-06-09 12:16:53 -07002246const SkPixmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
halcanary96fcdcc2015-08-27 07:41:13 -07002247 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00002248}