blob: 46c09e0ca5c66d65aa404f672b8e16f97b3dfa6f [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 Canaryc640d0d2018-06-13 09:59:02 -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"
Hal Canary50dbc092018-06-12 14:50:37 -040013#include "SkMacros.h"
reed@google.come36707a2011-10-04 21:38:55 +000014#include "SkPath.h"
Hal Canary2a2f6752018-06-11 21:44:01 -040015#include "SkRectPriv.h"
reed@google.come36707a2011-10-04 21:38:55 +000016#include "SkScan.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040017#include "SkTo.h"
reed@google.com34f7e472011-10-13 15:11:59 +000018#include "SkUtils.h"
reed@google.come36707a2011-10-04 21:38:55 +000019
reed@google.com045e62d2011-10-24 12:19:46 +000020class AutoAAClipValidate {
21public:
22 AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
23 fClip.validate();
24 }
25 ~AutoAAClipValidate() {
26 fClip.validate();
27 }
28private:
29 const SkAAClip& fClip;
30};
31
32#ifdef SK_DEBUG
33 #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip)
34#else
35 #define AUTO_AACLIP_VALIDATE(clip)
36#endif
37
38///////////////////////////////////////////////////////////////////////////////
39
reed@google.com1c04bf92011-10-10 12:57:12 +000040#define kMaxInt32 0x7FFFFFFF
41
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000042#ifdef SK_DEBUG
reed@google.come36707a2011-10-04 21:38:55 +000043static inline bool x_in_rect(int x, const SkIRect& rect) {
44 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
45}
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000046#endif
reed@google.come36707a2011-10-04 21:38:55 +000047
48static inline bool y_in_rect(int y, const SkIRect& rect) {
49 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
50}
51
52/*
53 * Data runs are packed [count, alpha]
54 */
55
56struct SkAAClip::YOffset {
57 int32_t fY;
58 uint32_t fOffset;
59};
60
61struct SkAAClip::RunHead {
62 int32_t fRefCnt;
63 int32_t fRowCount;
scroggo@google.com493c65f2013-02-05 18:49:00 +000064 size_t fDataSize;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000065
reed@google.come36707a2011-10-04 21:38:55 +000066 YOffset* yoffsets() {
67 return (YOffset*)((char*)this + sizeof(RunHead));
68 }
69 const YOffset* yoffsets() const {
70 return (const YOffset*)((const char*)this + sizeof(RunHead));
71 }
72 uint8_t* data() {
73 return (uint8_t*)(this->yoffsets() + fRowCount);
74 }
75 const uint8_t* data() const {
76 return (const uint8_t*)(this->yoffsets() + fRowCount);
77 }
78
79 static RunHead* Alloc(int rowCount, size_t dataSize) {
80 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
81 RunHead* head = (RunHead*)sk_malloc_throw(size);
82 head->fRefCnt = 1;
83 head->fRowCount = rowCount;
84 head->fDataSize = dataSize;
85 return head;
86 }
reed@google.com045e62d2011-10-24 12:19:46 +000087
88 static int ComputeRowSizeForWidth(int width) {
89 // 2 bytes per segment, where each segment can store up to 255 for count
90 int segments = 0;
91 while (width > 0) {
92 segments += 1;
93 int n = SkMin32(width, 255);
94 width -= n;
95 }
96 return segments * 2; // each segment is row[0] + row[1] (n + alpha)
97 }
98
99 static RunHead* AllocRect(const SkIRect& bounds) {
100 SkASSERT(!bounds.isEmpty());
101 int width = bounds.width();
102 size_t rowSize = ComputeRowSizeForWidth(width);
103 RunHead* head = RunHead::Alloc(1, rowSize);
104 YOffset* yoff = head->yoffsets();
105 yoff->fY = bounds.height() - 1;
106 yoff->fOffset = 0;
107 uint8_t* row = head->data();
108 while (width > 0) {
109 int n = SkMin32(width, 255);
110 row[0] = n;
111 row[1] = 0xFF;
112 width -= n;
113 row += 2;
114 }
115 return head;
116 }
reed@google.come36707a2011-10-04 21:38:55 +0000117};
118
reed@google.com32287892011-10-05 16:27:44 +0000119class SkAAClip::Iter {
120public:
121 Iter(const SkAAClip&);
122
123 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000124 int top() const { return fTop; }
125 int bottom() const { return fBottom; }
126 const uint8_t* data() const { return fData; }
reed@google.com32287892011-10-05 16:27:44 +0000127 void next();
128
129private:
130 const YOffset* fCurrYOff;
131 const YOffset* fStopYOff;
132 const uint8_t* fData;
133
134 int fTop, fBottom;
135 bool fDone;
136};
137
138SkAAClip::Iter::Iter(const SkAAClip& clip) {
139 if (clip.isEmpty()) {
140 fDone = true;
reed@google.com1c04bf92011-10-10 12:57:12 +0000141 fTop = fBottom = clip.fBounds.fBottom;
halcanary96fcdcc2015-08-27 07:41:13 -0700142 fData = nullptr;
143 fCurrYOff = nullptr;
144 fStopYOff = nullptr;
reed@google.com32287892011-10-05 16:27:44 +0000145 return;
146 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000147
reed@google.com32287892011-10-05 16:27:44 +0000148 const RunHead* head = clip.fRunHead;
149 fCurrYOff = head->yoffsets();
150 fStopYOff = fCurrYOff + head->fRowCount;
151 fData = head->data() + fCurrYOff->fOffset;
152
153 // setup first value
154 fTop = clip.fBounds.fTop;
155 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
156 fDone = false;
157}
158
159void SkAAClip::Iter::next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000160 if (!fDone) {
161 const YOffset* prev = fCurrYOff;
162 const YOffset* curr = prev + 1;
163 SkASSERT(curr <= fStopYOff);
reed@google.com32287892011-10-05 16:27:44 +0000164
reed@google.com32287892011-10-05 16:27:44 +0000165 fTop = fBottom;
reed@google.com1c04bf92011-10-10 12:57:12 +0000166 if (curr >= fStopYOff) {
167 fDone = true;
168 fBottom = kMaxInt32;
halcanary96fcdcc2015-08-27 07:41:13 -0700169 fData = nullptr;
reed@google.com1c04bf92011-10-10 12:57:12 +0000170 } else {
171 fBottom += curr->fY - prev->fY;
172 fData += curr->fOffset - prev->fOffset;
173 fCurrYOff = curr;
174 }
reed@google.com32287892011-10-05 16:27:44 +0000175 }
176}
177
reed@google.com045e62d2011-10-24 12:19:46 +0000178#ifdef SK_DEBUG
reed@google.comc9041912011-10-27 16:58:46 +0000179// assert we're exactly width-wide, and then return the number of bytes used
reed@google.com045e62d2011-10-24 12:19:46 +0000180static size_t compute_row_length(const uint8_t row[], int width) {
181 const uint8_t* origRow = row;
182 while (width > 0) {
183 int n = row[0];
reed@google.comc9041912011-10-27 16:58:46 +0000184 SkASSERT(n > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000185 SkASSERT(n <= width);
186 row += 2;
187 width -= n;
188 }
189 SkASSERT(0 == width);
190 return row - origRow;
191}
192
193void SkAAClip::validate() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700194 if (nullptr == fRunHead) {
reed@google.com045e62d2011-10-24 12:19:46 +0000195 SkASSERT(fBounds.isEmpty());
196 return;
197 }
reedd7ec12e2016-06-20 10:21:24 -0700198 SkASSERT(!fBounds.isEmpty());
reed@google.com045e62d2011-10-24 12:19:46 +0000199
200 const RunHead* head = fRunHead;
201 SkASSERT(head->fRefCnt > 0);
202 SkASSERT(head->fRowCount > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000203
204 const YOffset* yoff = head->yoffsets();
205 const YOffset* ystop = yoff + head->fRowCount;
reed@google.comc9041912011-10-27 16:58:46 +0000206 const int lastY = fBounds.height() - 1;
207
208 // Y and offset must be monotonic
209 int prevY = -1;
210 int32_t prevOffset = -1;
reed@google.com045e62d2011-10-24 12:19:46 +0000211 while (yoff < ystop) {
reed@google.comc9041912011-10-27 16:58:46 +0000212 SkASSERT(prevY < yoff->fY);
213 SkASSERT(yoff->fY <= lastY);
214 prevY = yoff->fY;
215 SkASSERT(prevOffset < (int32_t)yoff->fOffset);
216 prevOffset = yoff->fOffset;
217 const uint8_t* row = head->data() + yoff->fOffset;
reed@google.com045e62d2011-10-24 12:19:46 +0000218 size_t rowLength = compute_row_length(row, fBounds.width());
scroggo@google.com493c65f2013-02-05 18:49:00 +0000219 SkASSERT(yoff->fOffset + rowLength <= head->fDataSize);
reed@google.comc9041912011-10-27 16:58:46 +0000220 yoff += 1;
reed@google.com045e62d2011-10-24 12:19:46 +0000221 }
reed@google.com045e62d2011-10-24 12:19:46 +0000222 // check the last entry;
223 --yoff;
reed@google.comc9041912011-10-27 16:58:46 +0000224 SkASSERT(yoff->fY == lastY);
reed@google.com045e62d2011-10-24 12:19:46 +0000225}
humper6d42d9c2014-08-08 11:45:46 -0700226
227static void dump_one_row(const uint8_t* SK_RESTRICT row,
228 int width, int leading_num) {
229 if (leading_num) {
230 SkDebugf( "%03d ", leading_num );
231 }
232 while (width > 0) {
233 int n = row[0];
234 int val = row[1];
235 char out = '.';
236 if (val == 0xff) {
237 out = '*';
238 } else if (val > 0) {
239 out = '+';
240 }
241 for (int i = 0 ; i < n ; i++) {
242 SkDebugf( "%c", out );
243 }
244 row += 2;
245 width -= n;
246 }
247 SkDebugf( "\n" );
248}
249
250void SkAAClip::debug(bool compress_y) const {
251 Iter iter(*this);
252 const int width = fBounds.width();
253
254 int y = fBounds.fTop;
255 while (!iter.done()) {
256 if (compress_y) {
257 dump_one_row(iter.data(), width, iter.bottom() - iter.top() + 1);
258 } else {
259 do {
260 dump_one_row(iter.data(), width, 0);
261 } while (++y < iter.bottom());
262 }
263 iter.next();
264 }
265}
reed@google.com045e62d2011-10-24 12:19:46 +0000266#endif
267
268///////////////////////////////////////////////////////////////////////////////
269
robertphillips@google.com768fee82012-08-02 12:42:43 +0000270// Count the number of zeros on the left and right edges of the passed in
271// RLE row. If 'row' is all zeros return 'width' in both variables.
reed@google.comc9041912011-10-27 16:58:46 +0000272static void count_left_right_zeros(const uint8_t* row, int width,
273 int* leftZ, int* riteZ) {
274 int zeros = 0;
275 do {
276 if (row[1]) {
277 break;
278 }
279 int n = row[0];
280 SkASSERT(n > 0);
281 SkASSERT(n <= width);
282 zeros += n;
283 row += 2;
284 width -= n;
285 } while (width > 0);
286 *leftZ = zeros;
287
robertphillips@google.com768fee82012-08-02 12:42:43 +0000288 if (0 == width) {
289 // this line is completely empty return 'width' in both variables
290 *riteZ = *leftZ;
291 return;
292 }
293
reed@google.comc9041912011-10-27 16:58:46 +0000294 zeros = 0;
295 while (width > 0) {
296 int n = row[0];
297 SkASSERT(n > 0);
298 if (0 == row[1]) {
299 zeros += n;
300 } else {
301 zeros = 0;
302 }
303 row += 2;
304 width -= n;
305 }
306 *riteZ = zeros;
307}
308
309#ifdef SK_DEBUG
310static void test_count_left_right_zeros() {
311 static bool gOnce;
312 if (gOnce) {
313 return;
314 }
315 gOnce = true;
316
317 const uint8_t data0[] = { 0, 0, 10, 0xFF };
318 const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF };
319 const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF };
320 const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 };
321 const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 };
robertphillips@google.com768fee82012-08-02 12:42:43 +0000322 const uint8_t data5[] = { 10, 10, 10, 0 };
reed@google.comc9041912011-10-27 16:58:46 +0000323 const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
324
325 const uint8_t* array[] = {
326 data0, data1, data2, data3, data4, data5, data6
327 };
328
329 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
330 const uint8_t* data = array[i];
331 const int expectedL = *data++;
332 const int expectedR = *data++;
333 int L = 12345, R = 12345;
334 count_left_right_zeros(data, 10, &L, &R);
335 SkASSERT(expectedL == L);
336 SkASSERT(expectedR == R);
337 }
338}
339#endif
340
341// modify row in place, trimming off (zeros) from the left and right sides.
342// return the number of bytes that were completely eliminated from the left
343static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
344 int trim = 0;
345 while (leftZ > 0) {
346 SkASSERT(0 == row[1]);
347 int n = row[0];
348 SkASSERT(n > 0);
349 SkASSERT(n <= width);
350 width -= n;
351 row += 2;
352 if (n > leftZ) {
353 row[-2] = n - leftZ;
354 break;
355 }
356 trim += 2;
357 leftZ -= n;
358 SkASSERT(leftZ >= 0);
359 }
360
361 if (riteZ) {
362 // walk row to the end, and then we'll back up to trim riteZ
363 while (width > 0) {
364 int n = row[0];
365 SkASSERT(n <= width);
366 width -= n;
367 row += 2;
368 }
369 // now skip whole runs of zeros
370 do {
371 row -= 2;
372 SkASSERT(0 == row[1]);
373 int n = row[0];
374 SkASSERT(n > 0);
375 if (n > riteZ) {
376 row[0] = n - riteZ;
377 break;
378 }
379 riteZ -= n;
380 SkASSERT(riteZ >= 0);
381 } while (riteZ > 0);
382 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000383
reed@google.comc9041912011-10-27 16:58:46 +0000384 return trim;
385}
386
387#ifdef SK_DEBUG
388// assert that this row is exactly this width
reed@google.comc5507bf2011-10-27 21:15:36 +0000389static void assert_row_width(const uint8_t* row, int width) {
reed@google.comc9041912011-10-27 16:58:46 +0000390 while (width > 0) {
391 int n = row[0];
392 SkASSERT(n > 0);
393 SkASSERT(n <= width);
394 width -= n;
395 row += 2;
396 }
397 SkASSERT(0 == width);
398}
399
400static void test_trim_row_left_right() {
401 static bool gOnce;
402 if (gOnce) {
403 return;
404 }
405 gOnce = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000406
reed@google.comc9041912011-10-27 16:58:46 +0000407 uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF };
408 uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF };
409 uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
410 uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
411 uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
412 uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
413 uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
414 uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
415 uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
416 uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
417 uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000418
reed@google.comc9041912011-10-27 16:58:46 +0000419 uint8_t* array[] = {
420 data0, data1, data2, data3, data4,
421 data5, data6, data7, data8, data9,
422 data10
423 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000424
reed@google.comc9041912011-10-27 16:58:46 +0000425 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
426 uint8_t* data = array[i];
427 const int trimL = *data++;
428 const int trimR = *data++;
429 const int expectedSkip = *data++;
430 const int origWidth = *data++;
431 assert_row_width(data, origWidth);
432 int skip = trim_row_left_right(data, origWidth, trimL, trimR);
433 SkASSERT(expectedSkip == skip);
434 int expectedWidth = origWidth - trimL - trimR;
435 assert_row_width(data + skip, expectedWidth);
436 }
437}
438#endif
439
440bool SkAAClip::trimLeftRight() {
441 SkDEBUGCODE(test_trim_row_left_right();)
442
443 if (this->isEmpty()) {
444 return false;
445 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000446
reed@google.comc9041912011-10-27 16:58:46 +0000447 AUTO_AACLIP_VALIDATE(*this);
448
449 const int width = fBounds.width();
450 RunHead* head = fRunHead;
451 YOffset* yoff = head->yoffsets();
452 YOffset* stop = yoff + head->fRowCount;
453 uint8_t* base = head->data();
454
robertphillips@google.com768fee82012-08-02 12:42:43 +0000455 // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum
456 // number of zeros on the left and right of the clip. This information
457 // can be used to shrink the bounding box.
reed@google.comc9041912011-10-27 16:58:46 +0000458 int leftZeros = width;
459 int riteZeros = width;
460 while (yoff < stop) {
461 int L, R;
462 count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000463 SkASSERT(L + R < width || (L == width && R == width));
reed@google.comc9041912011-10-27 16:58:46 +0000464 if (L < leftZeros) {
465 leftZeros = L;
466 }
467 if (R < riteZeros) {
468 riteZeros = R;
469 }
470 if (0 == (leftZeros | riteZeros)) {
471 // no trimming to do
472 return true;
473 }
474 yoff += 1;
475 }
476
477 SkASSERT(leftZeros || riteZeros);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000478 if (width == leftZeros) {
479 SkASSERT(width == riteZeros);
reed@google.comc9041912011-10-27 16:58:46 +0000480 return this->setEmpty();
481 }
482
483 this->validate();
484
485 fBounds.fLeft += leftZeros;
486 fBounds.fRight -= riteZeros;
487 SkASSERT(!fBounds.isEmpty());
488
489 // For now we don't realloc the storage (for time), we just shrink in place
490 // This means we don't have to do any memmoves either, since we can just
491 // play tricks with the yoff->fOffset for each row
492 yoff = head->yoffsets();
493 while (yoff < stop) {
494 uint8_t* row = base + yoff->fOffset;
495 SkDEBUGCODE((void)compute_row_length(row, width);)
496 yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
497 SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
498 yoff += 1;
499 }
500 return true;
501}
502
503static bool row_is_all_zeros(const uint8_t* row, int width) {
504 SkASSERT(width > 0);
505 do {
506 if (row[1]) {
507 return false;
508 }
509 int n = row[0];
510 SkASSERT(n <= width);
511 width -= n;
512 row += 2;
513 } while (width > 0);
514 SkASSERT(0 == width);
515 return true;
516}
517
518bool SkAAClip::trimTopBottom() {
519 if (this->isEmpty()) {
520 return false;
521 }
522
reed@google.comd6040f62011-10-28 02:39:17 +0000523 this->validate();
524
reed@google.comc9041912011-10-27 16:58:46 +0000525 const int width = fBounds.width();
526 RunHead* head = fRunHead;
527 YOffset* yoff = head->yoffsets();
528 YOffset* stop = yoff + head->fRowCount;
529 const uint8_t* base = head->data();
530
531 // Look to trim away empty rows from the top.
532 //
533 int skip = 0;
534 while (yoff < stop) {
535 const uint8_t* data = base + yoff->fOffset;
536 if (!row_is_all_zeros(data, width)) {
537 break;
538 }
539 skip += 1;
540 yoff += 1;
541 }
542 SkASSERT(skip <= head->fRowCount);
543 if (skip == head->fRowCount) {
544 return this->setEmpty();
545 }
546 if (skip > 0) {
547 // adjust fRowCount and fBounds.fTop, and slide all the data up
548 // as we remove [skip] number of YOffset entries
549 yoff = head->yoffsets();
550 int dy = yoff[skip - 1].fY + 1;
551 for (int i = skip; i < head->fRowCount; ++i) {
552 SkASSERT(yoff[i].fY >= dy);
553 yoff[i].fY -= dy;
554 }
555 YOffset* dst = head->yoffsets();
556 size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
557 memmove(dst, dst + skip, size - skip * sizeof(YOffset));
558
559 fBounds.fTop += dy;
560 SkASSERT(!fBounds.isEmpty());
561 head->fRowCount -= skip;
562 SkASSERT(head->fRowCount > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000563
reed@google.comd6040f62011-10-28 02:39:17 +0000564 this->validate();
565 // need to reset this after the memmove
566 base = head->data();
reed@google.comc9041912011-10-27 16:58:46 +0000567 }
568
569 // Look to trim away empty rows from the bottom.
570 // We know that we have at least one non-zero row, so we can just walk
571 // backwards without checking for running past the start.
572 //
573 stop = yoff = head->yoffsets() + head->fRowCount;
574 do {
575 yoff -= 1;
576 } while (row_is_all_zeros(base + yoff->fOffset, width));
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +0000577 skip = SkToInt(stop - yoff - 1);
reed@google.comc9041912011-10-27 16:58:46 +0000578 SkASSERT(skip >= 0 && skip < head->fRowCount);
579 if (skip > 0) {
580 // removing from the bottom is easier than from the top, as we don't
581 // have to adjust any of the Y values, we just have to trim the array
582 memmove(stop - skip, stop, head->fDataSize);
583
584 fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
585 SkASSERT(!fBounds.isEmpty());
586 head->fRowCount -= skip;
587 SkASSERT(head->fRowCount > 0);
588 }
reed@google.comd6040f62011-10-28 02:39:17 +0000589 this->validate();
reed@google.comc9041912011-10-27 16:58:46 +0000590
591 return true;
592}
593
reed@google.com045e62d2011-10-24 12:19:46 +0000594// can't validate before we're done, since trimming is part of the process of
595// making us valid after the Builder. Since we build from top to bottom, its
596// possible our fBounds.fBottom is bigger than our last scanline of data, so
597// we trim fBounds.fBottom back up.
598//
reed@google.com045e62d2011-10-24 12:19:46 +0000599// TODO: check for duplicates in X and Y to further compress our data
600//
601bool SkAAClip::trimBounds() {
602 if (this->isEmpty()) {
603 return false;
604 }
605
606 const RunHead* head = fRunHead;
607 const YOffset* yoff = head->yoffsets();
608
609 SkASSERT(head->fRowCount > 0);
610 const YOffset& lastY = yoff[head->fRowCount - 1];
611 SkASSERT(lastY.fY + 1 <= fBounds.height());
612 fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
613 SkASSERT(lastY.fY + 1 == fBounds.height());
reed@google.comc9041912011-10-27 16:58:46 +0000614 SkASSERT(!fBounds.isEmpty());
615
616 return this->trimTopBottom() && this->trimLeftRight();
reed@google.com045e62d2011-10-24 12:19:46 +0000617}
618
reed@google.come36707a2011-10-04 21:38:55 +0000619///////////////////////////////////////////////////////////////////////////////
620
621void SkAAClip::freeRuns() {
reed@google.com47ac84e2011-10-06 13:11:25 +0000622 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000623 SkASSERT(fRunHead->fRefCnt >= 1);
624 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
625 sk_free(fRunHead);
626 }
627 }
628}
629
630SkAAClip::SkAAClip() {
631 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700632 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000633}
634
635SkAAClip::SkAAClip(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000636 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
halcanary96fcdcc2015-08-27 07:41:13 -0700637 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000638 *this = src;
639}
640
641SkAAClip::~SkAAClip() {
642 this->freeRuns();
643}
644
645SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000646 AUTO_AACLIP_VALIDATE(*this);
647 src.validate();
648
reed@google.come36707a2011-10-04 21:38:55 +0000649 if (this != &src) {
650 this->freeRuns();
651 fBounds = src.fBounds;
652 fRunHead = src.fRunHead;
reed@google.com47ac84e2011-10-06 13:11:25 +0000653 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000654 sk_atomic_inc(&fRunHead->fRefCnt);
655 }
656 }
657 return *this;
658}
659
660bool operator==(const SkAAClip& a, const SkAAClip& b) {
reed@google.com045e62d2011-10-24 12:19:46 +0000661 a.validate();
662 b.validate();
663
reed@google.come36707a2011-10-04 21:38:55 +0000664 if (&a == &b) {
665 return true;
666 }
667 if (a.fBounds != b.fBounds) {
668 return false;
669 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000670
reed@google.come36707a2011-10-04 21:38:55 +0000671 const SkAAClip::RunHead* ah = a.fRunHead;
672 const SkAAClip::RunHead* bh = b.fRunHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000673
reed@google.come36707a2011-10-04 21:38:55 +0000674 // this catches empties and rects being equal
675 if (ah == bh) {
676 return true;
677 }
678
679 // now we insist that both are complex (but different ptrs)
reed@google.com47ac84e2011-10-06 13:11:25 +0000680 if (!a.fRunHead || !b.fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000681 return false;
682 }
683
684 return ah->fRowCount == bh->fRowCount &&
685 ah->fDataSize == bh->fDataSize &&
686 !memcmp(ah->data(), bh->data(), ah->fDataSize);
687}
688
689void SkAAClip::swap(SkAAClip& other) {
reed@google.com045e62d2011-10-24 12:19:46 +0000690 AUTO_AACLIP_VALIDATE(*this);
691 other.validate();
692
reed@google.come36707a2011-10-04 21:38:55 +0000693 SkTSwap(fBounds, other.fBounds);
694 SkTSwap(fRunHead, other.fRunHead);
695}
696
reed@google.com32287892011-10-05 16:27:44 +0000697bool SkAAClip::set(const SkAAClip& src) {
698 *this = src;
699 return !this->isEmpty();
700}
701
reed@google.come36707a2011-10-04 21:38:55 +0000702bool SkAAClip::setEmpty() {
703 this->freeRuns();
704 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700705 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000706 return false;
707}
708
709bool SkAAClip::setRect(const SkIRect& bounds) {
Mike Reeda766ca92018-01-09 11:31:53 -0500710 if (bounds.isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000711 return this->setEmpty();
712 }
reed@google.com47ac84e2011-10-06 13:11:25 +0000713
reed@google.com045e62d2011-10-24 12:19:46 +0000714 AUTO_AACLIP_VALIDATE(*this);
reed@google.com47ac84e2011-10-06 13:11:25 +0000715
reed@google.com045e62d2011-10-24 12:19:46 +0000716#if 0
reed@google.com47ac84e2011-10-06 13:11:25 +0000717 SkRect r;
718 r.set(bounds);
719 SkPath path;
720 path.addRect(r);
721 return this->setPath(path);
reed@google.com045e62d2011-10-24 12:19:46 +0000722#else
723 this->freeRuns();
724 fBounds = bounds;
725 fRunHead = RunHead::AllocRect(bounds);
726 SkASSERT(!this->isEmpty());
727 return true;
728#endif
reed@google.come36707a2011-10-04 21:38:55 +0000729}
730
reed202ab2a2014-08-07 11:48:10 -0700731bool SkAAClip::isRect() const {
732 if (this->isEmpty()) {
733 return false;
734 }
735
736 const RunHead* head = fRunHead;
737 if (head->fRowCount != 1) {
738 return false;
739 }
740 const YOffset* yoff = head->yoffsets();
741 if (yoff->fY != fBounds.fBottom - 1) {
742 return false;
743 }
744
745 const uint8_t* row = head->data() + yoff->fOffset;
746 int width = fBounds.width();
747 do {
748 if (row[1] != 0xFF) {
749 return false;
750 }
751 int n = row[0];
752 SkASSERT(n <= width);
753 width -= n;
754 row += 2;
755 } while (width > 0);
756 return true;
757}
758
reed@google.comf3c1da12011-10-10 19:35:47 +0000759bool SkAAClip::setRect(const SkRect& r, bool doAA) {
reed@google.come36707a2011-10-04 21:38:55 +0000760 if (r.isEmpty()) {
761 return this->setEmpty();
762 }
763
reed@google.com045e62d2011-10-24 12:19:46 +0000764 AUTO_AACLIP_VALIDATE(*this);
765
766 // TODO: special case this
767
reed@google.come36707a2011-10-04 21:38:55 +0000768 SkPath path;
769 path.addRect(r);
halcanary96fcdcc2015-08-27 07:41:13 -0700770 return this->setPath(path, nullptr, doAA);
reed@google.comf3c1da12011-10-10 19:35:47 +0000771}
772
reed@google.coma069c8f2011-11-28 19:54:56 +0000773static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
774 SkASSERT(count >= 0);
775 while (count > 0) {
776 int n = count;
777 if (n > 255) {
778 n = 255;
779 }
780 uint8_t* data = array.append(2);
781 data[0] = n;
782 data[1] = value;
783 count -= n;
784 }
785}
786
reed@google.comf3c1da12011-10-10 19:35:47 +0000787bool SkAAClip::setRegion(const SkRegion& rgn) {
788 if (rgn.isEmpty()) {
789 return this->setEmpty();
790 }
791 if (rgn.isRect()) {
792 return this->setRect(rgn.getBounds());
793 }
reed@google.coma069c8f2011-11-28 19:54:56 +0000794
795#if 0
reed@google.comf3c1da12011-10-10 19:35:47 +0000796 SkAAClip clip;
797 SkRegion::Iterator iter(rgn);
798 for (; !iter.done(); iter.next()) {
799 clip.op(iter.rect(), SkRegion::kUnion_Op);
800 }
801 this->swap(clip);
reed@google.com3771a032011-10-11 17:18:04 +0000802 return !this->isEmpty();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000803#else
reed@google.coma069c8f2011-11-28 19:54:56 +0000804 const SkIRect& bounds = rgn.getBounds();
805 const int offsetX = bounds.fLeft;
806 const int offsetY = bounds.fTop;
807
808 SkTDArray<YOffset> yArray;
809 SkTDArray<uint8_t> xArray;
810
811 yArray.setReserve(SkMin32(bounds.height(), 1024));
Mike Reede0673952017-10-04 16:46:42 -0400812 xArray.setReserve(SkMin32(bounds.width(), 512) * 128);
reed@google.coma069c8f2011-11-28 19:54:56 +0000813
814 SkRegion::Iterator iter(rgn);
815 int prevRight = 0;
816 int prevBot = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700817 YOffset* currY = nullptr;
reed@google.coma069c8f2011-11-28 19:54:56 +0000818
819 for (; !iter.done(); iter.next()) {
820 const SkIRect& r = iter.rect();
821 SkASSERT(bounds.contains(r));
822
823 int bot = r.fBottom - offsetY;
824 SkASSERT(bot >= prevBot);
825 if (bot > prevBot) {
826 if (currY) {
827 // flush current row
828 append_run(xArray, 0, bounds.width() - prevRight);
829 }
830 // did we introduce an empty-gap from the prev row?
831 int top = r.fTop - offsetY;
832 if (top > prevBot) {
833 currY = yArray.append();
834 currY->fY = top - 1;
835 currY->fOffset = xArray.count();
836 append_run(xArray, 0, bounds.width());
837 }
838 // create a new record for this Y value
839 currY = yArray.append();
840 currY->fY = bot - 1;
841 currY->fOffset = xArray.count();
842 prevRight = 0;
843 prevBot = bot;
844 }
845
846 int x = r.fLeft - offsetX;
847 append_run(xArray, 0, x - prevRight);
848
849 int w = r.fRight - r.fLeft;
850 append_run(xArray, 0xFF, w);
851 prevRight = x + w;
852 SkASSERT(prevRight <= bounds.width());
853 }
854 // flush last row
855 append_run(xArray, 0, bounds.width() - prevRight);
856
857 // now pack everything into a RunHead
858 RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
859 memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
860 memcpy(head->data(), xArray.begin(), xArray.bytes());
861
862 this->setEmpty();
863 fBounds = bounds;
864 fRunHead = head;
865 this->validate();
866 return true;
867#endif
reed@google.come36707a2011-10-04 21:38:55 +0000868}
869
870///////////////////////////////////////////////////////////////////////////////
871
872const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000873 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000874
875 if (!y_in_rect(y, fBounds)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700876 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000877 }
878 y -= fBounds.y(); // our yoffs values are relative to the top
879
880 const YOffset* yoff = fRunHead->yoffsets();
881 while (yoff->fY < y) {
882 yoff += 1;
883 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
884 }
885
886 if (lastYForRow) {
reed@google.com045e62d2011-10-24 12:19:46 +0000887 *lastYForRow = fBounds.y() + yoff->fY;
reed@google.come36707a2011-10-04 21:38:55 +0000888 }
889 return fRunHead->data() + yoff->fOffset;
890}
891
892const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
893 SkASSERT(x_in_rect(x, fBounds));
894 x -= fBounds.x();
895
896 // first skip up to X
897 for (;;) {
898 int n = data[0];
899 if (x < n) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000900 if (initialCount) {
901 *initialCount = n - x;
902 }
reed@google.come36707a2011-10-04 21:38:55 +0000903 break;
904 }
905 data += 2;
906 x -= n;
907 }
908 return data;
909}
910
911bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
912 if (this->isEmpty()) {
913 return false;
914 }
915 if (!fBounds.contains(left, top, right, bottom)) {
916 return false;
917 }
reed@google.com32287892011-10-05 16:27:44 +0000918#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000919 if (this->isRect()) {
920 return true;
921 }
reed@google.com32287892011-10-05 16:27:44 +0000922#endif
reed@google.come36707a2011-10-04 21:38:55 +0000923
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000924 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +0000925 const uint8_t* row = this->findRow(top, &lastY);
926 if (lastY < bottom) {
927 return false;
928 }
929 // now just need to check in X
reed@google.com045e62d2011-10-24 12:19:46 +0000930 int count;
931 row = this->findX(row, left, &count);
932#if 0
933 return count >= (right - left) && 0xFF == row[1];
934#else
935 int rectWidth = right - left;
936 while (0xFF == row[1]) {
937 if (count >= rectWidth) {
938 return true;
939 }
940 rectWidth -= count;
941 row += 2;
942 count = row[0];
943 }
944 return false;
945#endif
reed@google.come36707a2011-10-04 21:38:55 +0000946}
947
948///////////////////////////////////////////////////////////////////////////////
949
950class SkAAClip::Builder {
951 SkIRect fBounds;
952 struct Row {
953 int fY;
954 int fWidth;
955 SkTDArray<uint8_t>* fData;
956 };
957 SkTDArray<Row> fRows;
958 Row* fCurrRow;
959 int fPrevY;
960 int fWidth;
reed@google.com209c4152011-10-26 15:03:48 +0000961 int fMinY;
reed@google.come36707a2011-10-04 21:38:55 +0000962
963public:
964 Builder(const SkIRect& bounds) : fBounds(bounds) {
965 fPrevY = -1;
966 fWidth = bounds.width();
halcanary96fcdcc2015-08-27 07:41:13 -0700967 fCurrRow = nullptr;
reed@google.com209c4152011-10-26 15:03:48 +0000968 fMinY = bounds.fTop;
reed@google.come36707a2011-10-04 21:38:55 +0000969 }
970
971 ~Builder() {
972 Row* row = fRows.begin();
973 Row* stop = fRows.end();
974 while (row < stop) {
975 delete row->fData;
976 row += 1;
977 }
978 }
979
reed@google.com32287892011-10-05 16:27:44 +0000980 const SkIRect& getBounds() const { return fBounds; }
981
reed@google.come36707a2011-10-04 21:38:55 +0000982 void addRun(int x, int y, U8CPU alpha, int count) {
983 SkASSERT(count > 0);
984 SkASSERT(fBounds.contains(x, y));
985 SkASSERT(fBounds.contains(x + count - 1, y));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000986
reed@google.come36707a2011-10-04 21:38:55 +0000987 x -= fBounds.left();
988 y -= fBounds.top();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000989
reed@google.come36707a2011-10-04 21:38:55 +0000990 Row* row = fCurrRow;
991 if (y != fPrevY) {
992 SkASSERT(y > fPrevY);
993 fPrevY = y;
994 row = this->flushRow(true);
995 row->fY = y;
996 row->fWidth = 0;
997 SkASSERT(row->fData);
998 SkASSERT(0 == row->fData->count());
999 fCurrRow = row;
1000 }
1001
1002 SkASSERT(row->fWidth <= x);
1003 SkASSERT(row->fWidth < fBounds.width());
1004
1005 SkTDArray<uint8_t>& data = *row->fData;
1006
1007 int gap = x - row->fWidth;
1008 if (gap) {
1009 AppendRun(data, 0, gap);
1010 row->fWidth += gap;
1011 SkASSERT(row->fWidth < fBounds.width());
1012 }
1013
1014 AppendRun(data, alpha, count);
1015 row->fWidth += count;
1016 SkASSERT(row->fWidth <= fBounds.width());
1017 }
1018
tomhudson@google.com49eac192011-12-27 13:59:20 +00001019 void addColumn(int x, int y, U8CPU alpha, int height) {
1020 SkASSERT(fBounds.contains(x, y + height - 1));
1021
1022 this->addRun(x, y, alpha, 1);
1023 this->flushRowH(fCurrRow);
1024 y -= fBounds.fTop;
1025 SkASSERT(y == fCurrRow->fY);
1026 fCurrRow->fY = y + height - 1;
1027 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001028
reed@google.com9154eb02011-10-31 16:07:28 +00001029 void addRectRun(int x, int y, int width, int height) {
1030 SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
1031 this->addRun(x, y, 0xFF, width);
1032
reed@google.coma89c77b2011-12-01 21:47:26 +00001033 // we assum the rect must be all we'll see for these scanlines
reed@google.com9154eb02011-10-31 16:07:28 +00001034 // so we ensure our row goes all the way to our right
1035 this->flushRowH(fCurrRow);
1036
1037 y -= fBounds.fTop;
1038 SkASSERT(y == fCurrRow->fY);
1039 fCurrRow->fY = y + height - 1;
1040 }
1041
tomhudson@google.com49eac192011-12-27 13:59:20 +00001042 void addAntiRectRun(int x, int y, int width, int height,
1043 SkAlpha leftAlpha, SkAlpha rightAlpha) {
liyuqian2add0ff2016-10-20 11:04:39 -07001044 // According to SkBlitter.cpp, no matter whether leftAlpha is 0 or positive,
1045 // we should always consider [x, x+1] as the left-most column and [x+1, x+1+width]
1046 // as the rect with full alpha.
1047 SkASSERT(fBounds.contains(x + width + (rightAlpha > 0 ? 1 : 0),
tomhudson@google.com49eac192011-12-27 13:59:20 +00001048 y + height - 1));
1049 SkASSERT(width >= 0);
1050
1051 // Conceptually we're always adding 3 runs, but we should
1052 // merge or omit them if possible.
1053 if (leftAlpha == 0xFF) {
1054 width++;
1055 } else if (leftAlpha > 0) {
1056 this->addRun(x++, y, leftAlpha, 1);
liyuqian2add0ff2016-10-20 11:04:39 -07001057 } else {
1058 // leftAlpha is 0, ignore the left column
1059 x++;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001060 }
1061 if (rightAlpha == 0xFF) {
1062 width++;
1063 }
1064 if (width > 0) {
1065 this->addRun(x, y, 0xFF, width);
1066 }
1067 if (rightAlpha > 0 && rightAlpha < 255) {
1068 this->addRun(x + width, y, rightAlpha, 1);
1069 }
1070
Mike Reed1b7cd332018-06-05 09:55:17 -04001071 // if we never called addRun, we might not have a fCurrRow yet
1072 if (fCurrRow) {
1073 // we assume the rect must be all we'll see for these scanlines
1074 // so we ensure our row goes all the way to our right
1075 this->flushRowH(fCurrRow);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001076
Mike Reed1b7cd332018-06-05 09:55:17 -04001077 y -= fBounds.fTop;
1078 SkASSERT(y == fCurrRow->fY);
1079 fCurrRow->fY = y + height - 1;
1080 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001081 }
1082
reed@google.com045e62d2011-10-24 12:19:46 +00001083 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +00001084 this->flushRow(false);
1085
1086 const Row* row = fRows.begin();
1087 const Row* stop = fRows.end();
1088
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001089 size_t dataSize = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001090 while (row < stop) {
1091 dataSize += row->fData->count();
1092 row += 1;
1093 }
1094
reed@google.com045e62d2011-10-24 12:19:46 +00001095 if (0 == dataSize) {
1096 return target->setEmpty();
1097 }
1098
reed@google.com209c4152011-10-26 15:03:48 +00001099 SkASSERT(fMinY >= fBounds.fTop);
1100 SkASSERT(fMinY < fBounds.fBottom);
1101 int adjustY = fMinY - fBounds.fTop;
1102 fBounds.fTop = fMinY;
1103
reed@google.come36707a2011-10-04 21:38:55 +00001104 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
1105 YOffset* yoffset = head->yoffsets();
1106 uint8_t* data = head->data();
1107 uint8_t* baseData = data;
1108
1109 row = fRows.begin();
reed@google.comc9041912011-10-27 16:58:46 +00001110 SkDEBUGCODE(int prevY = row->fY - 1;)
reed@google.come36707a2011-10-04 21:38:55 +00001111 while (row < stop) {
reed@google.comc9041912011-10-27 16:58:46 +00001112 SkASSERT(prevY < row->fY); // must be monotonic
1113 SkDEBUGCODE(prevY = row->fY);
1114
reed@google.com209c4152011-10-26 15:03:48 +00001115 yoffset->fY = row->fY - adjustY;
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001116 yoffset->fOffset = SkToU32(data - baseData);
reed@google.come36707a2011-10-04 21:38:55 +00001117 yoffset += 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001118
reed@google.come36707a2011-10-04 21:38:55 +00001119 size_t n = row->fData->count();
1120 memcpy(data, row->fData->begin(), n);
reed@google.comc9041912011-10-27 16:58:46 +00001121#ifdef SK_DEBUG
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001122 size_t bytesNeeded = compute_row_length(data, fBounds.width());
reed@google.comc9041912011-10-27 16:58:46 +00001123 SkASSERT(bytesNeeded == n);
1124#endif
reed@google.come36707a2011-10-04 21:38:55 +00001125 data += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001126
reed@google.come36707a2011-10-04 21:38:55 +00001127 row += 1;
1128 }
1129
reed@google.com045e62d2011-10-24 12:19:46 +00001130 target->freeRuns();
1131 target->fBounds = fBounds;
1132 target->fRunHead = head;
1133 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +00001134 }
1135
1136 void dump() {
1137 this->validate();
1138 int y;
1139 for (y = 0; y < fRows.count(); ++y) {
1140 const Row& row = fRows[y];
1141 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
1142 const SkTDArray<uint8_t>& data = *row.fData;
1143 int count = data.count();
1144 SkASSERT(!(count & 1));
1145 const uint8_t* ptr = data.begin();
1146 for (int x = 0; x < count; x += 2) {
1147 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
1148 ptr += 2;
1149 }
1150 SkDebugf("\n");
1151 }
reed@google.come36707a2011-10-04 21:38:55 +00001152 }
1153
1154 void validate() {
1155#ifdef SK_DEBUG
caryclark@google.com803eceb2012-06-06 12:09:34 +00001156 if (false) { // avoid bit rot, suppress warning
1157 test_count_left_right_zeros();
1158 }
reed@google.come36707a2011-10-04 21:38:55 +00001159 int prevY = -1;
1160 for (int i = 0; i < fRows.count(); ++i) {
1161 const Row& row = fRows[i];
1162 SkASSERT(prevY < row.fY);
1163 SkASSERT(fWidth == row.fWidth);
1164 int count = row.fData->count();
1165 const uint8_t* ptr = row.fData->begin();
1166 SkASSERT(!(count & 1));
1167 int w = 0;
1168 for (int x = 0; x < count; x += 2) {
reed@google.comd6040f62011-10-28 02:39:17 +00001169 int n = ptr[0];
1170 SkASSERT(n > 0);
1171 w += n;
reed@google.come36707a2011-10-04 21:38:55 +00001172 SkASSERT(w <= fWidth);
1173 ptr += 2;
1174 }
1175 SkASSERT(w == fWidth);
1176 prevY = row.fY;
1177 }
1178#endif
1179 }
1180
reed@google.com209c4152011-10-26 15:03:48 +00001181 // only called by BuilderBlitter
1182 void setMinY(int y) {
1183 fMinY = y;
1184 }
1185
reed@google.come36707a2011-10-04 21:38:55 +00001186private:
reed@google.com9154eb02011-10-31 16:07:28 +00001187 void flushRowH(Row* row) {
1188 // flush current row if needed
1189 if (row->fWidth < fWidth) {
1190 AppendRun(*row->fData, 0, fWidth - row->fWidth);
1191 row->fWidth = fWidth;
1192 }
1193 }
reed@google.com209c4152011-10-26 15:03:48 +00001194
reed@google.come36707a2011-10-04 21:38:55 +00001195 Row* flushRow(bool readyForAnother) {
halcanary96fcdcc2015-08-27 07:41:13 -07001196 Row* next = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001197 int count = fRows.count();
1198 if (count > 0) {
reed@google.com9154eb02011-10-31 16:07:28 +00001199 this->flushRowH(&fRows[count - 1]);
reed@google.come36707a2011-10-04 21:38:55 +00001200 }
1201 if (count > 1) {
1202 // are our last two runs the same?
1203 Row* prev = &fRows[count - 2];
1204 Row* curr = &fRows[count - 1];
1205 SkASSERT(prev->fWidth == fWidth);
1206 SkASSERT(curr->fWidth == fWidth);
1207 if (*prev->fData == *curr->fData) {
1208 prev->fY = curr->fY;
1209 if (readyForAnother) {
1210 curr->fData->rewind();
1211 next = curr;
1212 } else {
1213 delete curr->fData;
1214 fRows.removeShuffle(count - 1);
1215 }
1216 } else {
1217 if (readyForAnother) {
1218 next = fRows.append();
1219 next->fData = new SkTDArray<uint8_t>;
1220 }
1221 }
1222 } else {
1223 if (readyForAnother) {
1224 next = fRows.append();
1225 next->fData = new SkTDArray<uint8_t>;
1226 }
1227 }
1228 return next;
1229 }
1230
1231 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
1232 do {
1233 int n = count;
1234 if (n > 255) {
1235 n = 255;
1236 }
1237 uint8_t* ptr = data.append(2);
1238 ptr[0] = n;
1239 ptr[1] = alpha;
1240 count -= n;
1241 } while (count > 0);
1242 }
1243};
1244
1245class SkAAClip::BuilderBlitter : public SkBlitter {
reed@google.com80cdb9a2012-02-16 18:56:17 +00001246 int fLastY;
1247
1248 /*
1249 If we see a gap of 1 or more empty scanlines while building in Y-order,
1250 we inject an explicit empty scanline (alpha==0)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001251
reed@google.com80cdb9a2012-02-16 18:56:17 +00001252 See AAClipTest.cpp : test_path_with_hole()
1253 */
1254 void checkForYGap(int y) {
1255 SkASSERT(y >= fLastY);
1256 if (fLastY > -SK_MaxS32) {
1257 int gap = y - fLastY;
1258 if (gap > 1) {
1259 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
1260 }
1261 }
1262 fLastY = y;
1263 }
1264
reed@google.come36707a2011-10-04 21:38:55 +00001265public:
reed@google.com80cdb9a2012-02-16 18:56:17 +00001266
reed@google.come36707a2011-10-04 21:38:55 +00001267 BuilderBlitter(Builder* builder) {
1268 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001269 fLeft = builder->getBounds().fLeft;
1270 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001271 fMinY = SK_MaxS32;
reed@google.com80cdb9a2012-02-16 18:56:17 +00001272 fLastY = -SK_MaxS32; // sentinel
reed@google.com209c4152011-10-26 15:03:48 +00001273 }
1274
1275 void finish() {
1276 if (fMinY < SK_MaxS32) {
1277 fBuilder->setMinY(fMinY);
1278 }
reed@google.come36707a2011-10-04 21:38:55 +00001279 }
1280
tomhudson@google.com49eac192011-12-27 13:59:20 +00001281 /**
1282 Must evaluate clips in scan-line order, so don't want to allow blitV(),
1283 but an AAClip can be clipped down to a single pixel wide, so we
1284 must support it (given AntiRect semantics: minimum width is 2).
1285 Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
1286 any failure cases that misses may have minor artifacts.
1287 */
mtklein36352bf2015-03-25 18:17:31 -07001288 void blitV(int x, int y, int height, SkAlpha alpha) override {
liyuqian2add0ff2016-10-20 11:04:39 -07001289 if (height == 1) {
1290 // We're still in scan-line order if height is 1
1291 // This is useful for Analytic AA
1292 const SkAlpha alphas[2] = {alpha, 0};
1293 const int16_t runs[2] = {1, 0};
1294 this->blitAntiH(x, y, alphas, runs);
1295 } else {
1296 this->recordMinY(y);
1297 fBuilder->addColumn(x, y, alpha, height);
1298 fLastY = y + height - 1;
1299 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001300 }
reed@google.com045e62d2011-10-24 12:19:46 +00001301
mtklein36352bf2015-03-25 18:17:31 -07001302 void blitRect(int x, int y, int width, int height) override {
reed@google.com9154eb02011-10-31 16:07:28 +00001303 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001304 this->checkForYGap(y);
reed@google.com9154eb02011-10-31 16:07:28 +00001305 fBuilder->addRectRun(x, y, width, height);
reed@google.com302b8612012-02-16 19:30:13 +00001306 fLastY = y + height - 1;
reed@google.com562a2ac2011-10-31 14:14:18 +00001307 }
reed@google.com045e62d2011-10-24 12:19:46 +00001308
tomhudson@google.com49eac192011-12-27 13:59:20 +00001309 virtual void blitAntiRect(int x, int y, int width, int height,
mtklein36352bf2015-03-25 18:17:31 -07001310 SkAlpha leftAlpha, SkAlpha rightAlpha) override {
tomhudson@google.com49eac192011-12-27 13:59:20 +00001311 this->recordMinY(y);
reed@google.com302b8612012-02-16 19:30:13 +00001312 this->checkForYGap(y);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001313 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
reed@google.com302b8612012-02-16 19:30:13 +00001314 fLastY = y + height - 1;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001315 }
1316
mtklein36352bf2015-03-25 18:17:31 -07001317 void blitMask(const SkMask&, const SkIRect& clip) override
reed@google.come36707a2011-10-04 21:38:55 +00001318 { unexpected(); }
1319
reed41e010c2015-06-09 12:16:53 -07001320 const SkPixmap* justAnOpaqueColor(uint32_t*) override {
halcanary96fcdcc2015-08-27 07:41:13 -07001321 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001322 }
1323
mtklein36352bf2015-03-25 18:17:31 -07001324 void blitH(int x, int y, int width) override {
reed@google.com209c4152011-10-26 15:03:48 +00001325 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001326 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001327 fBuilder->addRun(x, y, 0xFF, width);
1328 }
1329
1330 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
mtklein36352bf2015-03-25 18:17:31 -07001331 const int16_t runs[]) override {
reed@google.com209c4152011-10-26 15:03:48 +00001332 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001333 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001334 for (;;) {
1335 int count = *runs;
1336 if (count <= 0) {
1337 return;
1338 }
reed@google.com17785642011-10-12 20:23:55 +00001339
1340 // The supersampler's buffer can be the width of the device, so
liyuqian1d3ab122016-11-08 13:55:15 -08001341 // we may have to trim the run to our bounds. Previously, we assert that
1342 // the extra spans are always alpha==0.
1343 // However, the analytic AA is too sensitive to precision errors
1344 // so it may have extra spans with very tiny alpha because after several
1345 // arithmatic operations, the edge may bleed the path boundary a little bit.
1346 // Therefore, instead of always asserting alpha==0, we assert alpha < 0x10.
reed@google.com17785642011-10-12 20:23:55 +00001347 int localX = x;
1348 int localCount = count;
1349 if (x < fLeft) {
liyuqian1d3ab122016-11-08 13:55:15 -08001350 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001351 int gap = fLeft - x;
1352 SkASSERT(gap <= count);
1353 localX += gap;
1354 localCount -= gap;
1355 }
1356 int right = x + count;
1357 if (right > fRight) {
liyuqian1d3ab122016-11-08 13:55:15 -08001358 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001359 localCount -= right - fRight;
1360 SkASSERT(localCount >= 0);
1361 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001362
reed@google.com17785642011-10-12 20:23:55 +00001363 if (localCount) {
1364 fBuilder->addRun(localX, y, *alpha, localCount);
1365 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001366 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001367 runs += count;
1368 alpha += count;
1369 x += count;
1370 }
1371 }
1372
1373private:
1374 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001375 int fLeft; // cache of builder's bounds' left edge
1376 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001377 int fMinY;
1378
1379 /*
1380 * We track this, in case the scan converter skipped some number of
1381 * scanlines at the (relative to the bounds it was given). This allows
1382 * the builder, during its finish, to trip its bounds down to the "real"
1383 * top.
1384 */
1385 void recordMinY(int y) {
1386 if (y < fMinY) {
1387 fMinY = y;
1388 }
1389 }
reed@google.come36707a2011-10-04 21:38:55 +00001390
1391 void unexpected() {
Ben Wagner7ca9a742017-08-17 14:05:04 -04001392 SK_ABORT("---- did not expect to get called here");
reed@google.come36707a2011-10-04 21:38:55 +00001393 }
1394};
1395
reed@google.comf3c1da12011-10-10 19:35:47 +00001396bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001397 AUTO_AACLIP_VALIDATE(*this);
1398
reed@google.com32287892011-10-05 16:27:44 +00001399 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001400 return this->setEmpty();
1401 }
1402
1403 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001404 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001405
reed@google.com32287892011-10-05 16:27:44 +00001406 SkRegion tmpClip;
halcanary96fcdcc2015-08-27 07:41:13 -07001407 if (nullptr == clip) {
reed@google.com32287892011-10-05 16:27:44 +00001408 tmpClip.setRect(ibounds);
1409 clip = &tmpClip;
1410 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001411
Yuqian Lica85fc32016-11-10 09:44:55 -05001412 // Since we assert that the BuilderBlitter will never blit outside the intersection
1413 // of clip and ibounds, we create this snugClip to be that intersection and send it
1414 // to the scan-converter.
1415 SkRegion snugClip(*clip);
1416
reed@google.com045e62d2011-10-24 12:19:46 +00001417 if (path.isInverseFillType()) {
1418 ibounds = clip->getBounds();
1419 } else {
reed@google.com32287892011-10-05 16:27:44 +00001420 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001421 return this->setEmpty();
1422 }
Yuqian Lica85fc32016-11-10 09:44:55 -05001423 snugClip.op(ibounds, SkRegion::kIntersect_Op);
reed@google.come36707a2011-10-04 21:38:55 +00001424 }
1425
1426 Builder builder(ibounds);
1427 BuilderBlitter blitter(&builder);
1428
reed@google.comf3c1da12011-10-10 19:35:47 +00001429 if (doAA) {
Yuqian Li7d99dad2017-07-26 13:47:26 -04001430 SkScan::AntiFillPath(path, snugClip, &blitter, true);
reed@google.comf3c1da12011-10-10 19:35:47 +00001431 } else {
Yuqian Lica85fc32016-11-10 09:44:55 -05001432 SkScan::FillPath(path, snugClip, &blitter);
reed@google.comf3c1da12011-10-10 19:35:47 +00001433 }
reed@google.come36707a2011-10-04 21:38:55 +00001434
reed@google.com209c4152011-10-26 15:03:48 +00001435 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001436 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001437}
1438
1439///////////////////////////////////////////////////////////////////////////////
1440
reed@google.com32287892011-10-05 16:27:44 +00001441typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1442 const uint8_t* rowA, const SkIRect& rectA,
1443 const uint8_t* rowB, const SkIRect& rectB);
1444
reed@google.com32287892011-10-05 16:27:44 +00001445typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1446
1447static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1448 // Multiply
1449 return SkMulDiv255Round(alphaA, alphaB);
1450}
1451
1452static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1453 // SrcOver
1454 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1455}
1456
1457static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1458 // SrcOut
1459 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1460}
1461
1462static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1463 // XOR
1464 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1465}
1466
1467static AlphaProc find_alpha_proc(SkRegion::Op op) {
1468 switch (op) {
1469 case SkRegion::kIntersect_Op:
1470 return sectAlphaProc;
1471 case SkRegion::kDifference_Op:
1472 return diffAlphaProc;
1473 case SkRegion::kUnion_Op:
1474 return unionAlphaProc;
1475 case SkRegion::kXOR_Op:
1476 return xorAlphaProc;
1477 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001478 SkDEBUGFAIL("unexpected region op");
reed@google.com32287892011-10-05 16:27:44 +00001479 return sectAlphaProc;
1480 }
1481}
1482
reed@google.com32287892011-10-05 16:27:44 +00001483class RowIter {
1484public:
1485 RowIter(const uint8_t* row, const SkIRect& bounds) {
1486 fRow = row;
1487 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001488 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001489 if (row) {
1490 fRight = bounds.fLeft + row[0];
1491 SkASSERT(fRight <= fBoundsRight);
1492 fAlpha = row[1];
1493 fDone = false;
1494 } else {
1495 fDone = true;
1496 fRight = kMaxInt32;
1497 fAlpha = 0;
1498 }
reed@google.com32287892011-10-05 16:27:44 +00001499 }
1500
1501 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001502 int left() const { return fLeft; }
1503 int right() const { return fRight; }
1504 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001505 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001506 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001507 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001508 if (fRight == fBoundsRight) {
1509 fDone = true;
1510 fRight = kMaxInt32;
1511 fAlpha = 0;
1512 } else {
1513 fRow += 2;
1514 fRight += fRow[0];
1515 fAlpha = fRow[1];
1516 SkASSERT(fRight <= fBoundsRight);
1517 }
reed@google.com32287892011-10-05 16:27:44 +00001518 }
1519 }
1520
1521private:
1522 const uint8_t* fRow;
1523 int fLeft;
1524 int fRight;
1525 int fBoundsRight;
1526 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001527 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001528};
1529
reed@google.com1c04bf92011-10-10 12:57:12 +00001530static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1531 if (rite == riteA) {
1532 iter.next();
1533 leftA = iter.left();
1534 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001535 }
1536}
1537
caryclark@google.com803eceb2012-06-06 12:09:34 +00001538#if 0 // UNUSED
reed@google.com1c04bf92011-10-10 12:57:12 +00001539static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1540 SkASSERT(min < max);
1541 SkASSERT(boundsMin < boundsMax);
1542 if (min >= boundsMax || max <= boundsMin) {
1543 return false;
1544 }
1545 if (min < boundsMin) {
1546 min = boundsMin;
1547 }
1548 if (max > boundsMax) {
1549 max = boundsMax;
1550 }
1551 return true;
1552}
caryclark@google.com803eceb2012-06-06 12:09:34 +00001553#endif
reed@google.com1c04bf92011-10-10 12:57:12 +00001554
reed@google.com32287892011-10-05 16:27:44 +00001555static void operatorX(SkAAClip::Builder& builder, int lastY,
1556 RowIter& iterA, RowIter& iterB,
1557 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001558 int leftA = iterA.left();
1559 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001560 int leftB = iterB.left();
1561 int riteB = iterB.right();
1562
reed@google.com1c04bf92011-10-10 12:57:12 +00001563 int prevRite = bounds.fLeft;
1564
1565 do {
reed@google.com32287892011-10-05 16:27:44 +00001566 U8CPU alphaA = 0;
1567 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001568 int left, rite;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001569
reed@google.com1c04bf92011-10-10 12:57:12 +00001570 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001571 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001572 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001573 if (riteA <= leftB) {
1574 rite = riteA;
1575 } else {
1576 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001577 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001578 } else if (leftB < leftA) {
1579 left = leftB;
1580 alphaB = iterB.alpha();
1581 if (riteB <= leftA) {
1582 rite = riteB;
1583 } else {
1584 rite = leftB = leftA;
1585 }
1586 } else {
1587 left = leftA; // or leftB, since leftA == leftB
1588 rite = leftA = leftB = SkMin32(riteA, riteB);
1589 alphaA = iterA.alpha();
1590 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001591 }
1592
1593 if (left >= bounds.fRight) {
1594 break;
1595 }
reed@google.com34f7e472011-10-13 15:11:59 +00001596 if (rite > bounds.fRight) {
1597 rite = bounds.fRight;
1598 }
1599
reed@google.com32287892011-10-05 16:27:44 +00001600 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001601 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001602 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001603 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001604 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001605
1606 adjust_row(iterA, leftA, riteA, rite);
1607 adjust_row(iterB, leftB, riteB, rite);
1608 } while (!iterA.done() || !iterB.done());
1609
1610 if (prevRite < bounds.fRight) {
1611 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001612 }
1613}
1614
reed@google.com1c04bf92011-10-10 12:57:12 +00001615static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1616 if (bot == botA) {
1617 iter.next();
1618 topA = botA;
1619 SkASSERT(botA == iter.top());
1620 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001621 }
1622}
1623
1624static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1625 const SkAAClip& B, SkRegion::Op op) {
1626 AlphaProc proc = find_alpha_proc(op);
1627 const SkIRect& bounds = builder.getBounds();
1628
1629 SkAAClip::Iter iterA(A);
1630 SkAAClip::Iter iterB(B);
1631
1632 SkASSERT(!iterA.done());
1633 int topA = iterA.top();
1634 int botA = iterA.bottom();
1635 SkASSERT(!iterB.done());
1636 int topB = iterB.top();
1637 int botB = iterB.bottom();
1638
reed@google.com1c04bf92011-10-10 12:57:12 +00001639 do {
halcanary96fcdcc2015-08-27 07:41:13 -07001640 const uint8_t* rowA = nullptr;
1641 const uint8_t* rowB = nullptr;
reed@google.com32287892011-10-05 16:27:44 +00001642 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001643
1644 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001645 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001646 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001647 if (botA <= topB) {
1648 bot = botA;
1649 } else {
1650 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001651 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001652
reed@google.com1c04bf92011-10-10 12:57:12 +00001653 } else if (topB < topA) {
1654 top = topB;
1655 rowB = iterB.data();
1656 if (botB <= topA) {
1657 bot = botB;
1658 } else {
1659 bot = topB = topA;
1660 }
1661 } else {
1662 top = topA; // or topB, since topA == topB
1663 bot = topA = topB = SkMin32(botA, botB);
1664 rowA = iterA.data();
1665 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001666 }
1667
1668 if (top >= bounds.fBottom) {
1669 break;
1670 }
reed@google.com34f7e472011-10-13 15:11:59 +00001671
1672 if (bot > bounds.fBottom) {
1673 bot = bounds.fBottom;
1674 }
1675 SkASSERT(top < bot);
1676
reed@google.com1c04bf92011-10-10 12:57:12 +00001677 if (!rowA && !rowB) {
1678 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1679 } else if (top >= bounds.fTop) {
1680 SkASSERT(bot <= bounds.fBottom);
1681 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1682 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001683 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001684 }
1685
reed@google.com1c04bf92011-10-10 12:57:12 +00001686 adjust_iter(iterA, topA, botA, bot);
1687 adjust_iter(iterB, topB, botB, bot);
1688 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001689}
1690
1691bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1692 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001693 AUTO_AACLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001694
reed@google.com32287892011-10-05 16:27:44 +00001695 if (SkRegion::kReplace_Op == op) {
1696 return this->set(clipBOrig);
1697 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001698
reed@google.com32287892011-10-05 16:27:44 +00001699 const SkAAClip* clipA = &clipAOrig;
1700 const SkAAClip* clipB = &clipBOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001701
reed@google.com32287892011-10-05 16:27:44 +00001702 if (SkRegion::kReverseDifference_Op == op) {
1703 SkTSwap(clipA, clipB);
1704 op = SkRegion::kDifference_Op;
1705 }
1706
1707 bool a_empty = clipA->isEmpty();
1708 bool b_empty = clipB->isEmpty();
1709
1710 SkIRect bounds;
1711 switch (op) {
1712 case SkRegion::kDifference_Op:
1713 if (a_empty) {
1714 return this->setEmpty();
1715 }
1716 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1717 return this->set(*clipA);
1718 }
1719 bounds = clipA->fBounds;
1720 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001721
reed@google.com32287892011-10-05 16:27:44 +00001722 case SkRegion::kIntersect_Op:
1723 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1724 clipB->fBounds)) {
1725 return this->setEmpty();
1726 }
1727 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001728
reed@google.com32287892011-10-05 16:27:44 +00001729 case SkRegion::kUnion_Op:
1730 case SkRegion::kXOR_Op:
1731 if (a_empty) {
1732 return this->set(*clipB);
1733 }
1734 if (b_empty) {
1735 return this->set(*clipA);
1736 }
1737 bounds = clipA->fBounds;
1738 bounds.join(clipB->fBounds);
1739 break;
1740
1741 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001742 SkDEBUGFAIL("unknown region op");
reed@google.com32287892011-10-05 16:27:44 +00001743 return !this->isEmpty();
1744 }
1745
reed@google.com32287892011-10-05 16:27:44 +00001746 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1747 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1748
1749 Builder builder(bounds);
1750 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001751
1752 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001753}
1754
reed@google.com045e62d2011-10-24 12:19:46 +00001755/*
1756 * It can be expensive to build a local aaclip before applying the op, so
1757 * we first see if we can restrict the bounds of new rect to our current
1758 * bounds, or note that the new rect subsumes our current clip.
1759 */
1760
1761bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1762 SkIRect rStorage;
1763 const SkIRect* r = &rOrig;
1764
1765 switch (op) {
1766 case SkRegion::kIntersect_Op:
1767 if (!rStorage.intersect(rOrig, fBounds)) {
1768 // no overlap, so we're empty
1769 return this->setEmpty();
1770 }
1771 if (rStorage == fBounds) {
1772 // we were wholly inside the rect, no change
1773 return !this->isEmpty();
1774 }
1775 if (this->quickContains(rStorage)) {
1776 // the intersection is wholly inside us, we're a rect
1777 return this->setRect(rStorage);
1778 }
1779 r = &rStorage; // use the intersected bounds
1780 break;
1781 case SkRegion::kDifference_Op:
1782 break;
1783 case SkRegion::kUnion_Op:
1784 if (rOrig.contains(fBounds)) {
1785 return this->setRect(rOrig);
1786 }
1787 break;
1788 default:
1789 break;
1790 }
1791
reed@google.com47ac84e2011-10-06 13:11:25 +00001792 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001793 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001794 return this->op(*this, clip, op);
1795}
1796
reed@google.com045e62d2011-10-24 12:19:46 +00001797bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1798 SkRect rStorage, boundsStorage;
1799 const SkRect* r = &rOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001800
reed@google.com045e62d2011-10-24 12:19:46 +00001801 boundsStorage.set(fBounds);
1802 switch (op) {
1803 case SkRegion::kIntersect_Op:
1804 case SkRegion::kDifference_Op:
1805 if (!rStorage.intersect(rOrig, boundsStorage)) {
reed@google.come56513d2012-06-25 20:06:33 +00001806 if (SkRegion::kIntersect_Op == op) {
1807 return this->setEmpty();
1808 } else { // kDifference
1809 return !this->isEmpty();
1810 }
reed@google.com045e62d2011-10-24 12:19:46 +00001811 }
1812 r = &rStorage; // use the intersected bounds
1813 break;
1814 case SkRegion::kUnion_Op:
1815 if (rOrig.contains(boundsStorage)) {
1816 return this->setRect(rOrig);
1817 }
1818 break;
1819 default:
1820 break;
1821 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001822
reed@google.com47ac84e2011-10-06 13:11:25 +00001823 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001824 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001825 return this->op(*this, clip, op);
1826}
1827
1828bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1829 return this->op(*this, clip, op);
1830}
1831
reed@google.come36707a2011-10-04 21:38:55 +00001832///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001833
1834bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -07001835 if (nullptr == dst) {
reed@google.com045e62d2011-10-24 12:19:46 +00001836 return !this->isEmpty();
1837 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001838
reed@google.com045e62d2011-10-24 12:19:46 +00001839 if (this->isEmpty()) {
1840 return dst->setEmpty();
1841 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001842
reed@google.com045e62d2011-10-24 12:19:46 +00001843 if (this != dst) {
1844 sk_atomic_inc(&fRunHead->fRefCnt);
tomhudson@google.com19224c32012-03-28 15:46:37 +00001845 dst->freeRuns();
reed@google.com045e62d2011-10-24 12:19:46 +00001846 dst->fRunHead = fRunHead;
1847 dst->fBounds = fBounds;
1848 }
1849 dst->fBounds.offset(dx, dy);
1850 return true;
1851}
1852
1853static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1854 const uint8_t* SK_RESTRICT row,
1855 int width) {
1856 while (width > 0) {
1857 int n = row[0];
1858 SkASSERT(width >= n);
1859 memset(mask, row[1], n);
1860 mask += n;
1861 row += 2;
1862 width -= n;
1863 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001864 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001865}
1866
1867void SkAAClip::copyToMask(SkMask* mask) const {
1868 mask->fFormat = SkMask::kA8_Format;
1869 if (this->isEmpty()) {
1870 mask->fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -07001871 mask->fImage = nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00001872 mask->fRowBytes = 0;
1873 return;
1874 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001875
reed@google.com045e62d2011-10-24 12:19:46 +00001876 mask->fBounds = fBounds;
1877 mask->fRowBytes = fBounds.width();
1878 size_t size = mask->computeImageSize();
1879 mask->fImage = SkMask::AllocImage(size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001880
reed@google.com045e62d2011-10-24 12:19:46 +00001881 Iter iter(*this);
1882 uint8_t* dst = mask->fImage;
1883 const int width = fBounds.width();
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001884
reed@google.com045e62d2011-10-24 12:19:46 +00001885 int y = fBounds.fTop;
1886 while (!iter.done()) {
1887 do {
1888 expand_row_to_mask(dst, iter.data(), width);
1889 dst += mask->fRowBytes;
1890 } while (++y < iter.bottom());
1891 iter.next();
1892 }
1893}
1894
1895///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001896///////////////////////////////////////////////////////////////////////////////
1897
1898static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1899 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1900 // we don't read our initial n from data, since the caller may have had to
1901 // clip it, hence the initialCount parameter.
1902 int n = initialCount;
1903 for (;;) {
1904 if (n > width) {
1905 n = width;
1906 }
1907 SkASSERT(n > 0);
1908 runs[0] = n;
1909 runs += n;
1910
1911 aa[0] = data[1];
1912 aa += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001913
reed@google.come36707a2011-10-04 21:38:55 +00001914 data += 2;
1915 width -= n;
1916 if (0 == width) {
1917 break;
1918 }
1919 // load the next count
1920 n = data[0];
1921 }
1922 runs[0] = 0; // sentinel
1923}
1924
1925SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001926 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001927}
1928
1929void SkAAClipBlitter::ensureRunsAndAA() {
halcanary96fcdcc2015-08-27 07:41:13 -07001930 if (nullptr == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001931 // add 1 so we can store the terminating run count of 0
1932 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001933 // we use this either for fRuns + fAA, or a scaline of a mask
1934 // which may be as deep as 32bits
1935 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1936 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001937 fAA = (SkAlpha*)(fRuns + count);
1938 }
1939}
1940
1941void SkAAClipBlitter::blitH(int x, int y, int width) {
1942 SkASSERT(width > 0);
1943 SkASSERT(fAAClipBounds.contains(x, y));
1944 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1945
reed@google.coma4c6e4d2012-06-20 14:29:50 +00001946 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00001947 int initialCount;
1948 row = fAAClip->findX(row, x, &initialCount);
1949
1950 if (initialCount >= width) {
1951 SkAlpha alpha = row[1];
1952 if (0 == alpha) {
1953 return;
1954 }
1955 if (0xFF == alpha) {
1956 fBlitter->blitH(x, y, width);
1957 return;
1958 }
1959 }
1960
1961 this->ensureRunsAndAA();
1962 expandToRuns(row, initialCount, width, fRuns, fAA);
1963
1964 fBlitter->blitAntiH(x, y, fAA, fRuns);
1965}
1966
1967static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1968 const SkAlpha* SK_RESTRICT srcAA,
1969 const int16_t* SK_RESTRICT srcRuns,
1970 SkAlpha* SK_RESTRICT dstAA,
1971 int16_t* SK_RESTRICT dstRuns,
1972 int width) {
1973 SkDEBUGCODE(int accumulated = 0;)
1974 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001975 // do we need this check?
1976 if (0 == srcN) {
1977 return;
1978 }
1979
reed@google.come36707a2011-10-04 21:38:55 +00001980 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001981 SkASSERT(rowN > 0);
1982 SkASSERT(srcN > 0);
1983
1984 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1985 int minN = SkMin32(srcN, rowN);
1986 dstRuns[0] = minN;
1987 dstRuns += minN;
1988 dstAA[0] = newAlpha;
1989 dstAA += minN;
1990
1991 if (0 == (srcN -= minN)) {
1992 srcN = srcRuns[0]; // refresh
1993 srcRuns += srcN;
1994 srcAA += srcN;
1995 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001996 if (0 == srcN) {
1997 break;
1998 }
reed@google.come36707a2011-10-04 21:38:55 +00001999 }
2000 if (0 == (rowN -= minN)) {
2001 row += 2;
2002 rowN = row[0]; // reload
2003 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002004
reed@google.come36707a2011-10-04 21:38:55 +00002005 SkDEBUGCODE(accumulated += minN;)
2006 SkASSERT(accumulated <= width);
2007 }
reed@google.com34f7e472011-10-13 15:11:59 +00002008 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00002009}
2010
2011void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
2012 const int16_t runs[]) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002013
2014 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00002015 int initialCount;
2016 row = fAAClip->findX(row, x, &initialCount);
2017
2018 this->ensureRunsAndAA();
2019
2020 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
2021 fBlitter->blitAntiH(x, y, fAA, fRuns);
2022}
2023
2024void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
2025 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
2026 fBlitter->blitV(x, y, height, alpha);
2027 return;
2028 }
2029
reed@google.com045e62d2011-10-24 12:19:46 +00002030 for (;;) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002031 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +00002032 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00002033 int dy = lastY - y + 1;
2034 if (dy > height) {
2035 dy = height;
2036 }
2037 height -= dy;
2038
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002039 row = fAAClip->findX(row, x);
reed@google.come36707a2011-10-04 21:38:55 +00002040 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
2041 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00002042 fBlitter->blitV(x, y, dy, newAlpha);
2043 }
2044 SkASSERT(height >= 0);
2045 if (height <= 0) {
2046 break;
reed@google.come36707a2011-10-04 21:38:55 +00002047 }
2048 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00002049 }
reed@google.come36707a2011-10-04 21:38:55 +00002050}
2051
2052void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
2053 if (fAAClip->quickContains(x, y, x + width, y + height)) {
2054 fBlitter->blitRect(x, y, width, height);
2055 return;
2056 }
2057
2058 while (--height >= 0) {
2059 this->blitH(x, y, width);
2060 y += 1;
2061 }
2062}
2063
reed@google.com045e62d2011-10-24 12:19:46 +00002064typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
2065 int initialRowCount, void* dst);
2066
2067static void small_memcpy(void* dst, const void* src, size_t n) {
2068 memcpy(dst, src, n);
2069}
2070
2071static void small_bzero(void* dst, size_t n) {
2072 sk_bzero(dst, n);
2073}
2074
2075static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
2076 return SkMulDiv255Round(value, alpha);
2077}
reedd54d3fc2014-11-13 14:39:58 -08002078
reed@google.com045e62d2011-10-24 12:19:46 +00002079static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
2080 unsigned r = SkGetPackedR16(value);
2081 unsigned g = SkGetPackedG16(value);
2082 unsigned b = SkGetPackedB16(value);
2083 return SkPackRGB16(SkMulDiv255Round(r, alpha),
caryclark@google.com803eceb2012-06-06 12:09:34 +00002084 SkMulDiv255Round(g, alpha),
2085 SkMulDiv255Round(b, alpha));
reed@google.com045e62d2011-10-24 12:19:46 +00002086}
reed@google.com045e62d2011-10-24 12:19:46 +00002087
herb94496162015-12-10 14:17:41 -08002088template <typename T>
2089void mergeT(const void* inSrc, int srcN, const uint8_t* SK_RESTRICT row, int rowN, void* inDst) {
2090 const T* SK_RESTRICT src = static_cast<const T*>(inSrc);
2091 T* SK_RESTRICT dst = static_cast<T*>(inDst);
reed@google.com045e62d2011-10-24 12:19:46 +00002092 for (;;) {
2093 SkASSERT(rowN > 0);
2094 SkASSERT(srcN > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002095
reed@google.com045e62d2011-10-24 12:19:46 +00002096 int n = SkMin32(rowN, srcN);
2097 unsigned rowA = row[1];
2098 if (0xFF == rowA) {
2099 small_memcpy(dst, src, n * sizeof(T));
2100 } else if (0 == rowA) {
2101 small_bzero(dst, n * sizeof(T));
2102 } else {
2103 for (int i = 0; i < n; ++i) {
2104 dst[i] = mergeOne(src[i], rowA);
2105 }
2106 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002107
reed@google.com045e62d2011-10-24 12:19:46 +00002108 if (0 == (srcN -= n)) {
2109 break;
2110 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002111
reed@google.com045e62d2011-10-24 12:19:46 +00002112 src += n;
2113 dst += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002114
reed@google.com045e62d2011-10-24 12:19:46 +00002115 SkASSERT(rowN == n);
2116 row += 2;
2117 rowN = row[0];
2118 }
2119}
2120
2121static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2122 switch (format) {
2123 case SkMask::kBW_Format:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002124 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002125 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002126 case SkMask::kA8_Format:
herb94496162015-12-10 14:17:41 -08002127 case SkMask::k3D_Format:
2128 return mergeT<uint8_t> ;
2129 case SkMask::kLCD16_Format:
2130 return mergeT<uint16_t>;
reed@google.com045e62d2011-10-24 12:19:46 +00002131 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002132 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002133 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002134 }
2135}
2136
2137static U8CPU bit2byte(int bitInAByte) {
2138 SkASSERT(bitInAByte <= 0xFF);
2139 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2140 // some value >= 8 to get a full FF value
2141 return -bitInAByte >> 8;
2142}
2143
2144static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2145 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2146 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2147
2148 const int width = srcMask.fBounds.width();
2149 const int height = srcMask.fBounds.height();
2150
2151 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2152 const size_t srcRB = srcMask.fRowBytes;
2153 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2154 const size_t dstRB = dstMask->fRowBytes;
2155
2156 const int wholeBytes = width >> 3;
2157 const int leftOverBits = width & 7;
2158
2159 for (int y = 0; y < height; ++y) {
2160 uint8_t* SK_RESTRICT d = dst;
2161 for (int i = 0; i < wholeBytes; ++i) {
2162 int srcByte = src[i];
2163 d[0] = bit2byte(srcByte & (1 << 7));
2164 d[1] = bit2byte(srcByte & (1 << 6));
2165 d[2] = bit2byte(srcByte & (1 << 5));
2166 d[3] = bit2byte(srcByte & (1 << 4));
2167 d[4] = bit2byte(srcByte & (1 << 3));
2168 d[5] = bit2byte(srcByte & (1 << 2));
2169 d[6] = bit2byte(srcByte & (1 << 1));
2170 d[7] = bit2byte(srcByte & (1 << 0));
2171 d += 8;
2172 }
2173 if (leftOverBits) {
2174 int srcByte = src[wholeBytes];
2175 for (int x = 0; x < leftOverBits; ++x) {
2176 *d++ = bit2byte(srcByte & 0x80);
2177 srcByte <<= 1;
2178 }
2179 }
2180 src += srcRB;
2181 dst += dstRB;
2182 }
2183}
2184
2185void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2186 SkASSERT(fAAClip->getBounds().contains(clip));
2187
2188 if (fAAClip->quickContains(clip)) {
2189 fBlitter->blitMask(origMask, clip);
2190 return;
2191 }
2192
2193 const SkMask* mask = &origMask;
2194
2195 // if we're BW, we need to upscale to A8 (ugh)
2196 SkMask grayMask;
reed@google.com045e62d2011-10-24 12:19:46 +00002197 if (SkMask::kBW_Format == origMask.fFormat) {
2198 grayMask.fFormat = SkMask::kA8_Format;
2199 grayMask.fBounds = origMask.fBounds;
2200 grayMask.fRowBytes = origMask.fBounds.width();
2201 size_t size = grayMask.computeImageSize();
2202 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2203 SkAutoMalloc::kReuse_OnShrink);
2204
2205 upscaleBW2A8(&grayMask, origMask);
2206 mask = &grayMask;
2207 }
2208
2209 this->ensureRunsAndAA();
2210
2211 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2212 // data into a temp block to support it better (ugh)
2213
2214 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2215 const size_t srcRB = mask->fRowBytes;
2216 const int width = clip.width();
2217 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2218
2219 SkMask rowMask;
2220 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2221 rowMask.fBounds.fLeft = clip.fLeft;
2222 rowMask.fBounds.fRight = clip.fRight;
2223 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2224 rowMask.fImage = (uint8_t*)fScanlineScratch;
2225
2226 int y = clip.fTop;
2227 const int stopY = y + clip.height();
2228
2229 do {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002230 int localStopY SK_INIT_TO_AVOID_WARNING;
reed@google.com045e62d2011-10-24 12:19:46 +00002231 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2232 // findRow returns last Y, not stop, so we add 1
2233 localStopY = SkMin32(localStopY + 1, stopY);
2234
2235 int initialCount;
2236 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2237 do {
2238 mergeProc(src, width, row, initialCount, rowMask.fImage);
2239 rowMask.fBounds.fTop = y;
2240 rowMask.fBounds.fBottom = y + 1;
2241 fBlitter->blitMask(rowMask, rowMask.fBounds);
2242 src = (const void*)((const char*)src + srcRB);
2243 } while (++y < localStopY);
2244 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002245}
2246
reed41e010c2015-06-09 12:16:53 -07002247const SkPixmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
halcanary96fcdcc2015-08-27 07:41:13 -07002248 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00002249}