blob: f0b341c5d06749e7ad89e79149081acf050ce7f3 [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
Ben Wagnerf08d1d02018-06-18 15:11:00 -040020#include <utility>
21
reed@google.com045e62d2011-10-24 12:19:46 +000022class AutoAAClipValidate {
23public:
24 AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
25 fClip.validate();
26 }
27 ~AutoAAClipValidate() {
28 fClip.validate();
29 }
30private:
31 const SkAAClip& fClip;
32};
33
34#ifdef SK_DEBUG
35 #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip)
36#else
37 #define AUTO_AACLIP_VALIDATE(clip)
38#endif
39
40///////////////////////////////////////////////////////////////////////////////
41
reed@google.com1c04bf92011-10-10 12:57:12 +000042#define kMaxInt32 0x7FFFFFFF
43
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000044#ifdef SK_DEBUG
reed@google.come36707a2011-10-04 21:38:55 +000045static inline bool x_in_rect(int x, const SkIRect& rect) {
46 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
47}
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +000048#endif
reed@google.come36707a2011-10-04 21:38:55 +000049
50static inline bool y_in_rect(int y, const SkIRect& rect) {
51 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
52}
53
54/*
55 * Data runs are packed [count, alpha]
56 */
57
58struct SkAAClip::YOffset {
59 int32_t fY;
60 uint32_t fOffset;
61};
62
63struct SkAAClip::RunHead {
64 int32_t fRefCnt;
65 int32_t fRowCount;
scroggo@google.com493c65f2013-02-05 18:49:00 +000066 size_t fDataSize;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000067
reed@google.come36707a2011-10-04 21:38:55 +000068 YOffset* yoffsets() {
69 return (YOffset*)((char*)this + sizeof(RunHead));
70 }
71 const YOffset* yoffsets() const {
72 return (const YOffset*)((const char*)this + sizeof(RunHead));
73 }
74 uint8_t* data() {
75 return (uint8_t*)(this->yoffsets() + fRowCount);
76 }
77 const uint8_t* data() const {
78 return (const uint8_t*)(this->yoffsets() + fRowCount);
79 }
80
81 static RunHead* Alloc(int rowCount, size_t dataSize) {
82 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
83 RunHead* head = (RunHead*)sk_malloc_throw(size);
84 head->fRefCnt = 1;
85 head->fRowCount = rowCount;
86 head->fDataSize = dataSize;
87 return head;
88 }
reed@google.com045e62d2011-10-24 12:19:46 +000089
90 static int ComputeRowSizeForWidth(int width) {
91 // 2 bytes per segment, where each segment can store up to 255 for count
92 int segments = 0;
93 while (width > 0) {
94 segments += 1;
95 int n = SkMin32(width, 255);
96 width -= n;
97 }
98 return segments * 2; // each segment is row[0] + row[1] (n + alpha)
99 }
100
101 static RunHead* AllocRect(const SkIRect& bounds) {
102 SkASSERT(!bounds.isEmpty());
103 int width = bounds.width();
104 size_t rowSize = ComputeRowSizeForWidth(width);
105 RunHead* head = RunHead::Alloc(1, rowSize);
106 YOffset* yoff = head->yoffsets();
107 yoff->fY = bounds.height() - 1;
108 yoff->fOffset = 0;
109 uint8_t* row = head->data();
110 while (width > 0) {
111 int n = SkMin32(width, 255);
112 row[0] = n;
113 row[1] = 0xFF;
114 width -= n;
115 row += 2;
116 }
117 return head;
118 }
reed@google.come36707a2011-10-04 21:38:55 +0000119};
120
reed@google.com32287892011-10-05 16:27:44 +0000121class SkAAClip::Iter {
122public:
123 Iter(const SkAAClip&);
124
125 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000126 int top() const { return fTop; }
127 int bottom() const { return fBottom; }
128 const uint8_t* data() const { return fData; }
reed@google.com32287892011-10-05 16:27:44 +0000129 void next();
130
131private:
132 const YOffset* fCurrYOff;
133 const YOffset* fStopYOff;
134 const uint8_t* fData;
135
136 int fTop, fBottom;
137 bool fDone;
138};
139
140SkAAClip::Iter::Iter(const SkAAClip& clip) {
141 if (clip.isEmpty()) {
142 fDone = true;
reed@google.com1c04bf92011-10-10 12:57:12 +0000143 fTop = fBottom = clip.fBounds.fBottom;
halcanary96fcdcc2015-08-27 07:41:13 -0700144 fData = nullptr;
145 fCurrYOff = nullptr;
146 fStopYOff = nullptr;
reed@google.com32287892011-10-05 16:27:44 +0000147 return;
148 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000149
reed@google.com32287892011-10-05 16:27:44 +0000150 const RunHead* head = clip.fRunHead;
151 fCurrYOff = head->yoffsets();
152 fStopYOff = fCurrYOff + head->fRowCount;
153 fData = head->data() + fCurrYOff->fOffset;
154
155 // setup first value
156 fTop = clip.fBounds.fTop;
157 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
158 fDone = false;
159}
160
161void SkAAClip::Iter::next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000162 if (!fDone) {
163 const YOffset* prev = fCurrYOff;
164 const YOffset* curr = prev + 1;
165 SkASSERT(curr <= fStopYOff);
reed@google.com32287892011-10-05 16:27:44 +0000166
reed@google.com32287892011-10-05 16:27:44 +0000167 fTop = fBottom;
reed@google.com1c04bf92011-10-10 12:57:12 +0000168 if (curr >= fStopYOff) {
169 fDone = true;
170 fBottom = kMaxInt32;
halcanary96fcdcc2015-08-27 07:41:13 -0700171 fData = nullptr;
reed@google.com1c04bf92011-10-10 12:57:12 +0000172 } else {
173 fBottom += curr->fY - prev->fY;
174 fData += curr->fOffset - prev->fOffset;
175 fCurrYOff = curr;
176 }
reed@google.com32287892011-10-05 16:27:44 +0000177 }
178}
179
reed@google.com045e62d2011-10-24 12:19:46 +0000180#ifdef SK_DEBUG
reed@google.comc9041912011-10-27 16:58:46 +0000181// assert we're exactly width-wide, and then return the number of bytes used
reed@google.com045e62d2011-10-24 12:19:46 +0000182static size_t compute_row_length(const uint8_t row[], int width) {
183 const uint8_t* origRow = row;
184 while (width > 0) {
185 int n = row[0];
reed@google.comc9041912011-10-27 16:58:46 +0000186 SkASSERT(n > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000187 SkASSERT(n <= width);
188 row += 2;
189 width -= n;
190 }
191 SkASSERT(0 == width);
192 return row - origRow;
193}
194
195void SkAAClip::validate() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700196 if (nullptr == fRunHead) {
reed@google.com045e62d2011-10-24 12:19:46 +0000197 SkASSERT(fBounds.isEmpty());
198 return;
199 }
reedd7ec12e2016-06-20 10:21:24 -0700200 SkASSERT(!fBounds.isEmpty());
reed@google.com045e62d2011-10-24 12:19:46 +0000201
202 const RunHead* head = fRunHead;
203 SkASSERT(head->fRefCnt > 0);
204 SkASSERT(head->fRowCount > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000205
206 const YOffset* yoff = head->yoffsets();
207 const YOffset* ystop = yoff + head->fRowCount;
reed@google.comc9041912011-10-27 16:58:46 +0000208 const int lastY = fBounds.height() - 1;
209
210 // Y and offset must be monotonic
211 int prevY = -1;
212 int32_t prevOffset = -1;
reed@google.com045e62d2011-10-24 12:19:46 +0000213 while (yoff < ystop) {
reed@google.comc9041912011-10-27 16:58:46 +0000214 SkASSERT(prevY < yoff->fY);
215 SkASSERT(yoff->fY <= lastY);
216 prevY = yoff->fY;
217 SkASSERT(prevOffset < (int32_t)yoff->fOffset);
218 prevOffset = yoff->fOffset;
219 const uint8_t* row = head->data() + yoff->fOffset;
reed@google.com045e62d2011-10-24 12:19:46 +0000220 size_t rowLength = compute_row_length(row, fBounds.width());
scroggo@google.com493c65f2013-02-05 18:49:00 +0000221 SkASSERT(yoff->fOffset + rowLength <= head->fDataSize);
reed@google.comc9041912011-10-27 16:58:46 +0000222 yoff += 1;
reed@google.com045e62d2011-10-24 12:19:46 +0000223 }
reed@google.com045e62d2011-10-24 12:19:46 +0000224 // check the last entry;
225 --yoff;
reed@google.comc9041912011-10-27 16:58:46 +0000226 SkASSERT(yoff->fY == lastY);
reed@google.com045e62d2011-10-24 12:19:46 +0000227}
humper6d42d9c2014-08-08 11:45:46 -0700228
229static void dump_one_row(const uint8_t* SK_RESTRICT row,
230 int width, int leading_num) {
231 if (leading_num) {
232 SkDebugf( "%03d ", leading_num );
233 }
234 while (width > 0) {
235 int n = row[0];
236 int val = row[1];
237 char out = '.';
238 if (val == 0xff) {
239 out = '*';
240 } else if (val > 0) {
241 out = '+';
242 }
243 for (int i = 0 ; i < n ; i++) {
244 SkDebugf( "%c", out );
245 }
246 row += 2;
247 width -= n;
248 }
249 SkDebugf( "\n" );
250}
251
252void SkAAClip::debug(bool compress_y) const {
253 Iter iter(*this);
254 const int width = fBounds.width();
255
256 int y = fBounds.fTop;
257 while (!iter.done()) {
258 if (compress_y) {
259 dump_one_row(iter.data(), width, iter.bottom() - iter.top() + 1);
260 } else {
261 do {
262 dump_one_row(iter.data(), width, 0);
263 } while (++y < iter.bottom());
264 }
265 iter.next();
266 }
267}
reed@google.com045e62d2011-10-24 12:19:46 +0000268#endif
269
270///////////////////////////////////////////////////////////////////////////////
271
robertphillips@google.com768fee82012-08-02 12:42:43 +0000272// Count the number of zeros on the left and right edges of the passed in
273// RLE row. If 'row' is all zeros return 'width' in both variables.
reed@google.comc9041912011-10-27 16:58:46 +0000274static void count_left_right_zeros(const uint8_t* row, int width,
275 int* leftZ, int* riteZ) {
276 int zeros = 0;
277 do {
278 if (row[1]) {
279 break;
280 }
281 int n = row[0];
282 SkASSERT(n > 0);
283 SkASSERT(n <= width);
284 zeros += n;
285 row += 2;
286 width -= n;
287 } while (width > 0);
288 *leftZ = zeros;
289
robertphillips@google.com768fee82012-08-02 12:42:43 +0000290 if (0 == width) {
291 // this line is completely empty return 'width' in both variables
292 *riteZ = *leftZ;
293 return;
294 }
295
reed@google.comc9041912011-10-27 16:58:46 +0000296 zeros = 0;
297 while (width > 0) {
298 int n = row[0];
299 SkASSERT(n > 0);
300 if (0 == row[1]) {
301 zeros += n;
302 } else {
303 zeros = 0;
304 }
305 row += 2;
306 width -= n;
307 }
308 *riteZ = zeros;
309}
310
311#ifdef SK_DEBUG
312static void test_count_left_right_zeros() {
313 static bool gOnce;
314 if (gOnce) {
315 return;
316 }
317 gOnce = true;
318
319 const uint8_t data0[] = { 0, 0, 10, 0xFF };
320 const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF };
321 const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF };
322 const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 };
323 const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 };
robertphillips@google.com768fee82012-08-02 12:42:43 +0000324 const uint8_t data5[] = { 10, 10, 10, 0 };
reed@google.comc9041912011-10-27 16:58:46 +0000325 const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
326
327 const uint8_t* array[] = {
328 data0, data1, data2, data3, data4, data5, data6
329 };
330
331 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
332 const uint8_t* data = array[i];
333 const int expectedL = *data++;
334 const int expectedR = *data++;
335 int L = 12345, R = 12345;
336 count_left_right_zeros(data, 10, &L, &R);
337 SkASSERT(expectedL == L);
338 SkASSERT(expectedR == R);
339 }
340}
341#endif
342
343// modify row in place, trimming off (zeros) from the left and right sides.
344// return the number of bytes that were completely eliminated from the left
345static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
346 int trim = 0;
347 while (leftZ > 0) {
348 SkASSERT(0 == row[1]);
349 int n = row[0];
350 SkASSERT(n > 0);
351 SkASSERT(n <= width);
352 width -= n;
353 row += 2;
354 if (n > leftZ) {
355 row[-2] = n - leftZ;
356 break;
357 }
358 trim += 2;
359 leftZ -= n;
360 SkASSERT(leftZ >= 0);
361 }
362
363 if (riteZ) {
364 // walk row to the end, and then we'll back up to trim riteZ
365 while (width > 0) {
366 int n = row[0];
367 SkASSERT(n <= width);
368 width -= n;
369 row += 2;
370 }
371 // now skip whole runs of zeros
372 do {
373 row -= 2;
374 SkASSERT(0 == row[1]);
375 int n = row[0];
376 SkASSERT(n > 0);
377 if (n > riteZ) {
378 row[0] = n - riteZ;
379 break;
380 }
381 riteZ -= n;
382 SkASSERT(riteZ >= 0);
383 } while (riteZ > 0);
384 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000385
reed@google.comc9041912011-10-27 16:58:46 +0000386 return trim;
387}
388
389#ifdef SK_DEBUG
390// assert that this row is exactly this width
reed@google.comc5507bf2011-10-27 21:15:36 +0000391static void assert_row_width(const uint8_t* row, int width) {
reed@google.comc9041912011-10-27 16:58:46 +0000392 while (width > 0) {
393 int n = row[0];
394 SkASSERT(n > 0);
395 SkASSERT(n <= width);
396 width -= n;
397 row += 2;
398 }
399 SkASSERT(0 == width);
400}
401
402static void test_trim_row_left_right() {
403 static bool gOnce;
404 if (gOnce) {
405 return;
406 }
407 gOnce = true;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000408
reed@google.comc9041912011-10-27 16:58:46 +0000409 uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF };
410 uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF };
411 uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
412 uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
413 uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
414 uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
415 uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
416 uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
417 uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
418 uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
419 uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000420
reed@google.comc9041912011-10-27 16:58:46 +0000421 uint8_t* array[] = {
422 data0, data1, data2, data3, data4,
423 data5, data6, data7, data8, data9,
424 data10
425 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000426
reed@google.comc9041912011-10-27 16:58:46 +0000427 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
428 uint8_t* data = array[i];
429 const int trimL = *data++;
430 const int trimR = *data++;
431 const int expectedSkip = *data++;
432 const int origWidth = *data++;
433 assert_row_width(data, origWidth);
434 int skip = trim_row_left_right(data, origWidth, trimL, trimR);
435 SkASSERT(expectedSkip == skip);
436 int expectedWidth = origWidth - trimL - trimR;
437 assert_row_width(data + skip, expectedWidth);
438 }
439}
440#endif
441
442bool SkAAClip::trimLeftRight() {
443 SkDEBUGCODE(test_trim_row_left_right();)
444
445 if (this->isEmpty()) {
446 return false;
447 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000448
reed@google.comc9041912011-10-27 16:58:46 +0000449 AUTO_AACLIP_VALIDATE(*this);
450
451 const int width = fBounds.width();
452 RunHead* head = fRunHead;
453 YOffset* yoff = head->yoffsets();
454 YOffset* stop = yoff + head->fRowCount;
455 uint8_t* base = head->data();
456
robertphillips@google.com768fee82012-08-02 12:42:43 +0000457 // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum
458 // number of zeros on the left and right of the clip. This information
459 // can be used to shrink the bounding box.
reed@google.comc9041912011-10-27 16:58:46 +0000460 int leftZeros = width;
461 int riteZeros = width;
462 while (yoff < stop) {
463 int L, R;
464 count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000465 SkASSERT(L + R < width || (L == width && R == width));
reed@google.comc9041912011-10-27 16:58:46 +0000466 if (L < leftZeros) {
467 leftZeros = L;
468 }
469 if (R < riteZeros) {
470 riteZeros = R;
471 }
472 if (0 == (leftZeros | riteZeros)) {
473 // no trimming to do
474 return true;
475 }
476 yoff += 1;
477 }
478
479 SkASSERT(leftZeros || riteZeros);
robertphillips@google.com768fee82012-08-02 12:42:43 +0000480 if (width == leftZeros) {
481 SkASSERT(width == riteZeros);
reed@google.comc9041912011-10-27 16:58:46 +0000482 return this->setEmpty();
483 }
484
485 this->validate();
486
487 fBounds.fLeft += leftZeros;
488 fBounds.fRight -= riteZeros;
489 SkASSERT(!fBounds.isEmpty());
490
491 // For now we don't realloc the storage (for time), we just shrink in place
492 // This means we don't have to do any memmoves either, since we can just
493 // play tricks with the yoff->fOffset for each row
494 yoff = head->yoffsets();
495 while (yoff < stop) {
496 uint8_t* row = base + yoff->fOffset;
497 SkDEBUGCODE((void)compute_row_length(row, width);)
498 yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
499 SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
500 yoff += 1;
501 }
502 return true;
503}
504
505static bool row_is_all_zeros(const uint8_t* row, int width) {
506 SkASSERT(width > 0);
507 do {
508 if (row[1]) {
509 return false;
510 }
511 int n = row[0];
512 SkASSERT(n <= width);
513 width -= n;
514 row += 2;
515 } while (width > 0);
516 SkASSERT(0 == width);
517 return true;
518}
519
520bool SkAAClip::trimTopBottom() {
521 if (this->isEmpty()) {
522 return false;
523 }
524
reed@google.comd6040f62011-10-28 02:39:17 +0000525 this->validate();
526
reed@google.comc9041912011-10-27 16:58:46 +0000527 const int width = fBounds.width();
528 RunHead* head = fRunHead;
529 YOffset* yoff = head->yoffsets();
530 YOffset* stop = yoff + head->fRowCount;
531 const uint8_t* base = head->data();
532
533 // Look to trim away empty rows from the top.
534 //
535 int skip = 0;
536 while (yoff < stop) {
537 const uint8_t* data = base + yoff->fOffset;
538 if (!row_is_all_zeros(data, width)) {
539 break;
540 }
541 skip += 1;
542 yoff += 1;
543 }
544 SkASSERT(skip <= head->fRowCount);
545 if (skip == head->fRowCount) {
546 return this->setEmpty();
547 }
548 if (skip > 0) {
549 // adjust fRowCount and fBounds.fTop, and slide all the data up
550 // as we remove [skip] number of YOffset entries
551 yoff = head->yoffsets();
552 int dy = yoff[skip - 1].fY + 1;
553 for (int i = skip; i < head->fRowCount; ++i) {
554 SkASSERT(yoff[i].fY >= dy);
555 yoff[i].fY -= dy;
556 }
557 YOffset* dst = head->yoffsets();
558 size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
559 memmove(dst, dst + skip, size - skip * sizeof(YOffset));
560
561 fBounds.fTop += dy;
562 SkASSERT(!fBounds.isEmpty());
563 head->fRowCount -= skip;
564 SkASSERT(head->fRowCount > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000565
reed@google.comd6040f62011-10-28 02:39:17 +0000566 this->validate();
567 // need to reset this after the memmove
568 base = head->data();
reed@google.comc9041912011-10-27 16:58:46 +0000569 }
570
571 // Look to trim away empty rows from the bottom.
572 // We know that we have at least one non-zero row, so we can just walk
573 // backwards without checking for running past the start.
574 //
575 stop = yoff = head->yoffsets() + head->fRowCount;
576 do {
577 yoff -= 1;
578 } while (row_is_all_zeros(base + yoff->fOffset, width));
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +0000579 skip = SkToInt(stop - yoff - 1);
reed@google.comc9041912011-10-27 16:58:46 +0000580 SkASSERT(skip >= 0 && skip < head->fRowCount);
581 if (skip > 0) {
582 // removing from the bottom is easier than from the top, as we don't
583 // have to adjust any of the Y values, we just have to trim the array
584 memmove(stop - skip, stop, head->fDataSize);
585
586 fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
587 SkASSERT(!fBounds.isEmpty());
588 head->fRowCount -= skip;
589 SkASSERT(head->fRowCount > 0);
590 }
reed@google.comd6040f62011-10-28 02:39:17 +0000591 this->validate();
reed@google.comc9041912011-10-27 16:58:46 +0000592
593 return true;
594}
595
reed@google.com045e62d2011-10-24 12:19:46 +0000596// can't validate before we're done, since trimming is part of the process of
597// making us valid after the Builder. Since we build from top to bottom, its
598// possible our fBounds.fBottom is bigger than our last scanline of data, so
599// we trim fBounds.fBottom back up.
600//
reed@google.com045e62d2011-10-24 12:19:46 +0000601// TODO: check for duplicates in X and Y to further compress our data
602//
603bool SkAAClip::trimBounds() {
604 if (this->isEmpty()) {
605 return false;
606 }
607
608 const RunHead* head = fRunHead;
609 const YOffset* yoff = head->yoffsets();
610
611 SkASSERT(head->fRowCount > 0);
612 const YOffset& lastY = yoff[head->fRowCount - 1];
613 SkASSERT(lastY.fY + 1 <= fBounds.height());
614 fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
615 SkASSERT(lastY.fY + 1 == fBounds.height());
reed@google.comc9041912011-10-27 16:58:46 +0000616 SkASSERT(!fBounds.isEmpty());
617
618 return this->trimTopBottom() && this->trimLeftRight();
reed@google.com045e62d2011-10-24 12:19:46 +0000619}
620
reed@google.come36707a2011-10-04 21:38:55 +0000621///////////////////////////////////////////////////////////////////////////////
622
623void SkAAClip::freeRuns() {
reed@google.com47ac84e2011-10-06 13:11:25 +0000624 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000625 SkASSERT(fRunHead->fRefCnt >= 1);
626 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
627 sk_free(fRunHead);
628 }
629 }
630}
631
632SkAAClip::SkAAClip() {
633 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700634 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000635}
636
637SkAAClip::SkAAClip(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000638 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
halcanary96fcdcc2015-08-27 07:41:13 -0700639 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000640 *this = src;
641}
642
643SkAAClip::~SkAAClip() {
644 this->freeRuns();
645}
646
647SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000648 AUTO_AACLIP_VALIDATE(*this);
649 src.validate();
650
reed@google.come36707a2011-10-04 21:38:55 +0000651 if (this != &src) {
652 this->freeRuns();
653 fBounds = src.fBounds;
654 fRunHead = src.fRunHead;
reed@google.com47ac84e2011-10-06 13:11:25 +0000655 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000656 sk_atomic_inc(&fRunHead->fRefCnt);
657 }
658 }
659 return *this;
660}
661
662bool operator==(const SkAAClip& a, const SkAAClip& b) {
reed@google.com045e62d2011-10-24 12:19:46 +0000663 a.validate();
664 b.validate();
665
reed@google.come36707a2011-10-04 21:38:55 +0000666 if (&a == &b) {
667 return true;
668 }
669 if (a.fBounds != b.fBounds) {
670 return false;
671 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000672
reed@google.come36707a2011-10-04 21:38:55 +0000673 const SkAAClip::RunHead* ah = a.fRunHead;
674 const SkAAClip::RunHead* bh = b.fRunHead;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000675
reed@google.come36707a2011-10-04 21:38:55 +0000676 // this catches empties and rects being equal
677 if (ah == bh) {
678 return true;
679 }
680
681 // now we insist that both are complex (but different ptrs)
reed@google.com47ac84e2011-10-06 13:11:25 +0000682 if (!a.fRunHead || !b.fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000683 return false;
684 }
685
686 return ah->fRowCount == bh->fRowCount &&
687 ah->fDataSize == bh->fDataSize &&
688 !memcmp(ah->data(), bh->data(), ah->fDataSize);
689}
690
691void SkAAClip::swap(SkAAClip& other) {
reed@google.com045e62d2011-10-24 12:19:46 +0000692 AUTO_AACLIP_VALIDATE(*this);
693 other.validate();
694
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400695 using std::swap;
696 swap(fBounds, other.fBounds);
697 swap(fRunHead, other.fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000698}
699
reed@google.com32287892011-10-05 16:27:44 +0000700bool SkAAClip::set(const SkAAClip& src) {
701 *this = src;
702 return !this->isEmpty();
703}
704
reed@google.come36707a2011-10-04 21:38:55 +0000705bool SkAAClip::setEmpty() {
706 this->freeRuns();
707 fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -0700708 fRunHead = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000709 return false;
710}
711
712bool SkAAClip::setRect(const SkIRect& bounds) {
Mike Reeda766ca92018-01-09 11:31:53 -0500713 if (bounds.isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000714 return this->setEmpty();
715 }
reed@google.com47ac84e2011-10-06 13:11:25 +0000716
reed@google.com045e62d2011-10-24 12:19:46 +0000717 AUTO_AACLIP_VALIDATE(*this);
reed@google.com47ac84e2011-10-06 13:11:25 +0000718
reed@google.com045e62d2011-10-24 12:19:46 +0000719#if 0
reed@google.com47ac84e2011-10-06 13:11:25 +0000720 SkRect r;
721 r.set(bounds);
722 SkPath path;
723 path.addRect(r);
724 return this->setPath(path);
reed@google.com045e62d2011-10-24 12:19:46 +0000725#else
726 this->freeRuns();
727 fBounds = bounds;
728 fRunHead = RunHead::AllocRect(bounds);
729 SkASSERT(!this->isEmpty());
730 return true;
731#endif
reed@google.come36707a2011-10-04 21:38:55 +0000732}
733
reed202ab2a2014-08-07 11:48:10 -0700734bool SkAAClip::isRect() const {
735 if (this->isEmpty()) {
736 return false;
737 }
738
739 const RunHead* head = fRunHead;
740 if (head->fRowCount != 1) {
741 return false;
742 }
743 const YOffset* yoff = head->yoffsets();
744 if (yoff->fY != fBounds.fBottom - 1) {
745 return false;
746 }
747
748 const uint8_t* row = head->data() + yoff->fOffset;
749 int width = fBounds.width();
750 do {
751 if (row[1] != 0xFF) {
752 return false;
753 }
754 int n = row[0];
755 SkASSERT(n <= width);
756 width -= n;
757 row += 2;
758 } while (width > 0);
759 return true;
760}
761
reed@google.comf3c1da12011-10-10 19:35:47 +0000762bool SkAAClip::setRect(const SkRect& r, bool doAA) {
reed@google.come36707a2011-10-04 21:38:55 +0000763 if (r.isEmpty()) {
764 return this->setEmpty();
765 }
766
reed@google.com045e62d2011-10-24 12:19:46 +0000767 AUTO_AACLIP_VALIDATE(*this);
768
769 // TODO: special case this
770
reed@google.come36707a2011-10-04 21:38:55 +0000771 SkPath path;
772 path.addRect(r);
halcanary96fcdcc2015-08-27 07:41:13 -0700773 return this->setPath(path, nullptr, doAA);
reed@google.comf3c1da12011-10-10 19:35:47 +0000774}
775
reed@google.coma069c8f2011-11-28 19:54:56 +0000776static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
777 SkASSERT(count >= 0);
778 while (count > 0) {
779 int n = count;
780 if (n > 255) {
781 n = 255;
782 }
783 uint8_t* data = array.append(2);
784 data[0] = n;
785 data[1] = value;
786 count -= n;
787 }
788}
789
reed@google.comf3c1da12011-10-10 19:35:47 +0000790bool SkAAClip::setRegion(const SkRegion& rgn) {
791 if (rgn.isEmpty()) {
792 return this->setEmpty();
793 }
794 if (rgn.isRect()) {
795 return this->setRect(rgn.getBounds());
796 }
reed@google.coma069c8f2011-11-28 19:54:56 +0000797
798#if 0
reed@google.comf3c1da12011-10-10 19:35:47 +0000799 SkAAClip clip;
800 SkRegion::Iterator iter(rgn);
801 for (; !iter.done(); iter.next()) {
802 clip.op(iter.rect(), SkRegion::kUnion_Op);
803 }
804 this->swap(clip);
reed@google.com3771a032011-10-11 17:18:04 +0000805 return !this->isEmpty();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000806#else
reed@google.coma069c8f2011-11-28 19:54:56 +0000807 const SkIRect& bounds = rgn.getBounds();
808 const int offsetX = bounds.fLeft;
809 const int offsetY = bounds.fTop;
810
811 SkTDArray<YOffset> yArray;
812 SkTDArray<uint8_t> xArray;
813
814 yArray.setReserve(SkMin32(bounds.height(), 1024));
Mike Reede0673952017-10-04 16:46:42 -0400815 xArray.setReserve(SkMin32(bounds.width(), 512) * 128);
reed@google.coma069c8f2011-11-28 19:54:56 +0000816
817 SkRegion::Iterator iter(rgn);
818 int prevRight = 0;
819 int prevBot = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700820 YOffset* currY = nullptr;
reed@google.coma069c8f2011-11-28 19:54:56 +0000821
822 for (; !iter.done(); iter.next()) {
823 const SkIRect& r = iter.rect();
824 SkASSERT(bounds.contains(r));
825
826 int bot = r.fBottom - offsetY;
827 SkASSERT(bot >= prevBot);
828 if (bot > prevBot) {
829 if (currY) {
830 // flush current row
831 append_run(xArray, 0, bounds.width() - prevRight);
832 }
833 // did we introduce an empty-gap from the prev row?
834 int top = r.fTop - offsetY;
835 if (top > prevBot) {
836 currY = yArray.append();
837 currY->fY = top - 1;
838 currY->fOffset = xArray.count();
839 append_run(xArray, 0, bounds.width());
840 }
841 // create a new record for this Y value
842 currY = yArray.append();
843 currY->fY = bot - 1;
844 currY->fOffset = xArray.count();
845 prevRight = 0;
846 prevBot = bot;
847 }
848
849 int x = r.fLeft - offsetX;
850 append_run(xArray, 0, x - prevRight);
851
852 int w = r.fRight - r.fLeft;
853 append_run(xArray, 0xFF, w);
854 prevRight = x + w;
855 SkASSERT(prevRight <= bounds.width());
856 }
857 // flush last row
858 append_run(xArray, 0, bounds.width() - prevRight);
859
860 // now pack everything into a RunHead
861 RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
862 memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
863 memcpy(head->data(), xArray.begin(), xArray.bytes());
864
865 this->setEmpty();
866 fBounds = bounds;
867 fRunHead = head;
868 this->validate();
869 return true;
870#endif
reed@google.come36707a2011-10-04 21:38:55 +0000871}
872
873///////////////////////////////////////////////////////////////////////////////
874
875const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000876 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000877
878 if (!y_in_rect(y, fBounds)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700879 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +0000880 }
881 y -= fBounds.y(); // our yoffs values are relative to the top
882
883 const YOffset* yoff = fRunHead->yoffsets();
884 while (yoff->fY < y) {
885 yoff += 1;
886 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
887 }
888
889 if (lastYForRow) {
reed@google.com045e62d2011-10-24 12:19:46 +0000890 *lastYForRow = fBounds.y() + yoff->fY;
reed@google.come36707a2011-10-04 21:38:55 +0000891 }
892 return fRunHead->data() + yoff->fOffset;
893}
894
895const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
896 SkASSERT(x_in_rect(x, fBounds));
897 x -= fBounds.x();
898
899 // first skip up to X
900 for (;;) {
901 int n = data[0];
902 if (x < n) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000903 if (initialCount) {
904 *initialCount = n - x;
905 }
reed@google.come36707a2011-10-04 21:38:55 +0000906 break;
907 }
908 data += 2;
909 x -= n;
910 }
911 return data;
912}
913
914bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
915 if (this->isEmpty()) {
916 return false;
917 }
918 if (!fBounds.contains(left, top, right, bottom)) {
919 return false;
920 }
reed@google.com32287892011-10-05 16:27:44 +0000921#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000922 if (this->isRect()) {
923 return true;
924 }
reed@google.com32287892011-10-05 16:27:44 +0000925#endif
reed@google.come36707a2011-10-04 21:38:55 +0000926
reed@google.coma4c6e4d2012-06-20 14:29:50 +0000927 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +0000928 const uint8_t* row = this->findRow(top, &lastY);
929 if (lastY < bottom) {
930 return false;
931 }
932 // now just need to check in X
reed@google.com045e62d2011-10-24 12:19:46 +0000933 int count;
934 row = this->findX(row, left, &count);
935#if 0
936 return count >= (right - left) && 0xFF == row[1];
937#else
938 int rectWidth = right - left;
939 while (0xFF == row[1]) {
940 if (count >= rectWidth) {
941 return true;
942 }
943 rectWidth -= count;
944 row += 2;
945 count = row[0];
946 }
947 return false;
948#endif
reed@google.come36707a2011-10-04 21:38:55 +0000949}
950
951///////////////////////////////////////////////////////////////////////////////
952
953class SkAAClip::Builder {
954 SkIRect fBounds;
955 struct Row {
956 int fY;
957 int fWidth;
958 SkTDArray<uint8_t>* fData;
959 };
960 SkTDArray<Row> fRows;
961 Row* fCurrRow;
962 int fPrevY;
963 int fWidth;
reed@google.com209c4152011-10-26 15:03:48 +0000964 int fMinY;
reed@google.come36707a2011-10-04 21:38:55 +0000965
966public:
967 Builder(const SkIRect& bounds) : fBounds(bounds) {
968 fPrevY = -1;
969 fWidth = bounds.width();
halcanary96fcdcc2015-08-27 07:41:13 -0700970 fCurrRow = nullptr;
reed@google.com209c4152011-10-26 15:03:48 +0000971 fMinY = bounds.fTop;
reed@google.come36707a2011-10-04 21:38:55 +0000972 }
973
974 ~Builder() {
975 Row* row = fRows.begin();
976 Row* stop = fRows.end();
977 while (row < stop) {
978 delete row->fData;
979 row += 1;
980 }
981 }
982
reed@google.com32287892011-10-05 16:27:44 +0000983 const SkIRect& getBounds() const { return fBounds; }
984
reed@google.come36707a2011-10-04 21:38:55 +0000985 void addRun(int x, int y, U8CPU alpha, int count) {
986 SkASSERT(count > 0);
987 SkASSERT(fBounds.contains(x, y));
988 SkASSERT(fBounds.contains(x + count - 1, y));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000989
reed@google.come36707a2011-10-04 21:38:55 +0000990 x -= fBounds.left();
991 y -= fBounds.top();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000992
reed@google.come36707a2011-10-04 21:38:55 +0000993 Row* row = fCurrRow;
994 if (y != fPrevY) {
995 SkASSERT(y > fPrevY);
996 fPrevY = y;
997 row = this->flushRow(true);
998 row->fY = y;
999 row->fWidth = 0;
1000 SkASSERT(row->fData);
1001 SkASSERT(0 == row->fData->count());
1002 fCurrRow = row;
1003 }
1004
1005 SkASSERT(row->fWidth <= x);
1006 SkASSERT(row->fWidth < fBounds.width());
1007
1008 SkTDArray<uint8_t>& data = *row->fData;
1009
1010 int gap = x - row->fWidth;
1011 if (gap) {
1012 AppendRun(data, 0, gap);
1013 row->fWidth += gap;
1014 SkASSERT(row->fWidth < fBounds.width());
1015 }
1016
1017 AppendRun(data, alpha, count);
1018 row->fWidth += count;
1019 SkASSERT(row->fWidth <= fBounds.width());
1020 }
1021
tomhudson@google.com49eac192011-12-27 13:59:20 +00001022 void addColumn(int x, int y, U8CPU alpha, int height) {
1023 SkASSERT(fBounds.contains(x, y + height - 1));
1024
1025 this->addRun(x, y, alpha, 1);
1026 this->flushRowH(fCurrRow);
1027 y -= fBounds.fTop;
1028 SkASSERT(y == fCurrRow->fY);
1029 fCurrRow->fY = y + height - 1;
1030 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001031
reed@google.com9154eb02011-10-31 16:07:28 +00001032 void addRectRun(int x, int y, int width, int height) {
1033 SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
1034 this->addRun(x, y, 0xFF, width);
1035
reed@google.coma89c77b2011-12-01 21:47:26 +00001036 // we assum the rect must be all we'll see for these scanlines
reed@google.com9154eb02011-10-31 16:07:28 +00001037 // so we ensure our row goes all the way to our right
1038 this->flushRowH(fCurrRow);
1039
1040 y -= fBounds.fTop;
1041 SkASSERT(y == fCurrRow->fY);
1042 fCurrRow->fY = y + height - 1;
1043 }
1044
tomhudson@google.com49eac192011-12-27 13:59:20 +00001045 void addAntiRectRun(int x, int y, int width, int height,
1046 SkAlpha leftAlpha, SkAlpha rightAlpha) {
liyuqian2add0ff2016-10-20 11:04:39 -07001047 // According to SkBlitter.cpp, no matter whether leftAlpha is 0 or positive,
1048 // we should always consider [x, x+1] as the left-most column and [x+1, x+1+width]
1049 // as the rect with full alpha.
1050 SkASSERT(fBounds.contains(x + width + (rightAlpha > 0 ? 1 : 0),
tomhudson@google.com49eac192011-12-27 13:59:20 +00001051 y + height - 1));
1052 SkASSERT(width >= 0);
1053
1054 // Conceptually we're always adding 3 runs, but we should
1055 // merge or omit them if possible.
1056 if (leftAlpha == 0xFF) {
1057 width++;
1058 } else if (leftAlpha > 0) {
1059 this->addRun(x++, y, leftAlpha, 1);
liyuqian2add0ff2016-10-20 11:04:39 -07001060 } else {
1061 // leftAlpha is 0, ignore the left column
1062 x++;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001063 }
1064 if (rightAlpha == 0xFF) {
1065 width++;
1066 }
1067 if (width > 0) {
1068 this->addRun(x, y, 0xFF, width);
1069 }
1070 if (rightAlpha > 0 && rightAlpha < 255) {
1071 this->addRun(x + width, y, rightAlpha, 1);
1072 }
1073
Mike Reed1b7cd332018-06-05 09:55:17 -04001074 // if we never called addRun, we might not have a fCurrRow yet
1075 if (fCurrRow) {
1076 // we assume the rect must be all we'll see for these scanlines
1077 // so we ensure our row goes all the way to our right
1078 this->flushRowH(fCurrRow);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001079
Mike Reed1b7cd332018-06-05 09:55:17 -04001080 y -= fBounds.fTop;
1081 SkASSERT(y == fCurrRow->fY);
1082 fCurrRow->fY = y + height - 1;
1083 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001084 }
1085
reed@google.com045e62d2011-10-24 12:19:46 +00001086 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +00001087 this->flushRow(false);
1088
1089 const Row* row = fRows.begin();
1090 const Row* stop = fRows.end();
1091
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001092 size_t dataSize = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001093 while (row < stop) {
1094 dataSize += row->fData->count();
1095 row += 1;
1096 }
1097
reed@google.com045e62d2011-10-24 12:19:46 +00001098 if (0 == dataSize) {
1099 return target->setEmpty();
1100 }
1101
reed@google.com209c4152011-10-26 15:03:48 +00001102 SkASSERT(fMinY >= fBounds.fTop);
1103 SkASSERT(fMinY < fBounds.fBottom);
1104 int adjustY = fMinY - fBounds.fTop;
1105 fBounds.fTop = fMinY;
1106
reed@google.come36707a2011-10-04 21:38:55 +00001107 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
1108 YOffset* yoffset = head->yoffsets();
1109 uint8_t* data = head->data();
1110 uint8_t* baseData = data;
1111
1112 row = fRows.begin();
reed@google.comc9041912011-10-27 16:58:46 +00001113 SkDEBUGCODE(int prevY = row->fY - 1;)
reed@google.come36707a2011-10-04 21:38:55 +00001114 while (row < stop) {
reed@google.comc9041912011-10-27 16:58:46 +00001115 SkASSERT(prevY < row->fY); // must be monotonic
1116 SkDEBUGCODE(prevY = row->fY);
1117
reed@google.com209c4152011-10-26 15:03:48 +00001118 yoffset->fY = row->fY - adjustY;
commit-bot@chromium.orga8c7f772014-01-24 21:46:29 +00001119 yoffset->fOffset = SkToU32(data - baseData);
reed@google.come36707a2011-10-04 21:38:55 +00001120 yoffset += 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001121
reed@google.come36707a2011-10-04 21:38:55 +00001122 size_t n = row->fData->count();
1123 memcpy(data, row->fData->begin(), n);
reed@google.comc9041912011-10-27 16:58:46 +00001124#ifdef SK_DEBUG
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001125 size_t bytesNeeded = compute_row_length(data, fBounds.width());
reed@google.comc9041912011-10-27 16:58:46 +00001126 SkASSERT(bytesNeeded == n);
1127#endif
reed@google.come36707a2011-10-04 21:38:55 +00001128 data += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001129
reed@google.come36707a2011-10-04 21:38:55 +00001130 row += 1;
1131 }
1132
reed@google.com045e62d2011-10-24 12:19:46 +00001133 target->freeRuns();
1134 target->fBounds = fBounds;
1135 target->fRunHead = head;
1136 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +00001137 }
1138
1139 void dump() {
1140 this->validate();
1141 int y;
1142 for (y = 0; y < fRows.count(); ++y) {
1143 const Row& row = fRows[y];
1144 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
1145 const SkTDArray<uint8_t>& data = *row.fData;
1146 int count = data.count();
1147 SkASSERT(!(count & 1));
1148 const uint8_t* ptr = data.begin();
1149 for (int x = 0; x < count; x += 2) {
1150 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
1151 ptr += 2;
1152 }
1153 SkDebugf("\n");
1154 }
reed@google.come36707a2011-10-04 21:38:55 +00001155 }
1156
1157 void validate() {
1158#ifdef SK_DEBUG
caryclark@google.com803eceb2012-06-06 12:09:34 +00001159 if (false) { // avoid bit rot, suppress warning
1160 test_count_left_right_zeros();
1161 }
reed@google.come36707a2011-10-04 21:38:55 +00001162 int prevY = -1;
1163 for (int i = 0; i < fRows.count(); ++i) {
1164 const Row& row = fRows[i];
1165 SkASSERT(prevY < row.fY);
1166 SkASSERT(fWidth == row.fWidth);
1167 int count = row.fData->count();
1168 const uint8_t* ptr = row.fData->begin();
1169 SkASSERT(!(count & 1));
1170 int w = 0;
1171 for (int x = 0; x < count; x += 2) {
reed@google.comd6040f62011-10-28 02:39:17 +00001172 int n = ptr[0];
1173 SkASSERT(n > 0);
1174 w += n;
reed@google.come36707a2011-10-04 21:38:55 +00001175 SkASSERT(w <= fWidth);
1176 ptr += 2;
1177 }
1178 SkASSERT(w == fWidth);
1179 prevY = row.fY;
1180 }
1181#endif
1182 }
1183
reed@google.com209c4152011-10-26 15:03:48 +00001184 // only called by BuilderBlitter
1185 void setMinY(int y) {
1186 fMinY = y;
1187 }
1188
reed@google.come36707a2011-10-04 21:38:55 +00001189private:
reed@google.com9154eb02011-10-31 16:07:28 +00001190 void flushRowH(Row* row) {
1191 // flush current row if needed
1192 if (row->fWidth < fWidth) {
1193 AppendRun(*row->fData, 0, fWidth - row->fWidth);
1194 row->fWidth = fWidth;
1195 }
1196 }
reed@google.com209c4152011-10-26 15:03:48 +00001197
reed@google.come36707a2011-10-04 21:38:55 +00001198 Row* flushRow(bool readyForAnother) {
halcanary96fcdcc2015-08-27 07:41:13 -07001199 Row* next = nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001200 int count = fRows.count();
1201 if (count > 0) {
reed@google.com9154eb02011-10-31 16:07:28 +00001202 this->flushRowH(&fRows[count - 1]);
reed@google.come36707a2011-10-04 21:38:55 +00001203 }
1204 if (count > 1) {
1205 // are our last two runs the same?
1206 Row* prev = &fRows[count - 2];
1207 Row* curr = &fRows[count - 1];
1208 SkASSERT(prev->fWidth == fWidth);
1209 SkASSERT(curr->fWidth == fWidth);
1210 if (*prev->fData == *curr->fData) {
1211 prev->fY = curr->fY;
1212 if (readyForAnother) {
1213 curr->fData->rewind();
1214 next = curr;
1215 } else {
1216 delete curr->fData;
1217 fRows.removeShuffle(count - 1);
1218 }
1219 } else {
1220 if (readyForAnother) {
1221 next = fRows.append();
1222 next->fData = new SkTDArray<uint8_t>;
1223 }
1224 }
1225 } else {
1226 if (readyForAnother) {
1227 next = fRows.append();
1228 next->fData = new SkTDArray<uint8_t>;
1229 }
1230 }
1231 return next;
1232 }
1233
1234 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
1235 do {
1236 int n = count;
1237 if (n > 255) {
1238 n = 255;
1239 }
1240 uint8_t* ptr = data.append(2);
1241 ptr[0] = n;
1242 ptr[1] = alpha;
1243 count -= n;
1244 } while (count > 0);
1245 }
1246};
1247
1248class SkAAClip::BuilderBlitter : public SkBlitter {
reed@google.com80cdb9a2012-02-16 18:56:17 +00001249 int fLastY;
1250
1251 /*
1252 If we see a gap of 1 or more empty scanlines while building in Y-order,
1253 we inject an explicit empty scanline (alpha==0)
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001254
reed@google.com80cdb9a2012-02-16 18:56:17 +00001255 See AAClipTest.cpp : test_path_with_hole()
1256 */
1257 void checkForYGap(int y) {
1258 SkASSERT(y >= fLastY);
1259 if (fLastY > -SK_MaxS32) {
1260 int gap = y - fLastY;
1261 if (gap > 1) {
1262 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
1263 }
1264 }
1265 fLastY = y;
1266 }
1267
reed@google.come36707a2011-10-04 21:38:55 +00001268public:
reed@google.com80cdb9a2012-02-16 18:56:17 +00001269
reed@google.come36707a2011-10-04 21:38:55 +00001270 BuilderBlitter(Builder* builder) {
1271 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001272 fLeft = builder->getBounds().fLeft;
1273 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001274 fMinY = SK_MaxS32;
reed@google.com80cdb9a2012-02-16 18:56:17 +00001275 fLastY = -SK_MaxS32; // sentinel
reed@google.com209c4152011-10-26 15:03:48 +00001276 }
1277
1278 void finish() {
1279 if (fMinY < SK_MaxS32) {
1280 fBuilder->setMinY(fMinY);
1281 }
reed@google.come36707a2011-10-04 21:38:55 +00001282 }
1283
tomhudson@google.com49eac192011-12-27 13:59:20 +00001284 /**
1285 Must evaluate clips in scan-line order, so don't want to allow blitV(),
1286 but an AAClip can be clipped down to a single pixel wide, so we
1287 must support it (given AntiRect semantics: minimum width is 2).
1288 Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
1289 any failure cases that misses may have minor artifacts.
1290 */
mtklein36352bf2015-03-25 18:17:31 -07001291 void blitV(int x, int y, int height, SkAlpha alpha) override {
liyuqian2add0ff2016-10-20 11:04:39 -07001292 if (height == 1) {
1293 // We're still in scan-line order if height is 1
1294 // This is useful for Analytic AA
1295 const SkAlpha alphas[2] = {alpha, 0};
1296 const int16_t runs[2] = {1, 0};
1297 this->blitAntiH(x, y, alphas, runs);
1298 } else {
1299 this->recordMinY(y);
1300 fBuilder->addColumn(x, y, alpha, height);
1301 fLastY = y + height - 1;
1302 }
tomhudson@google.com49eac192011-12-27 13:59:20 +00001303 }
reed@google.com045e62d2011-10-24 12:19:46 +00001304
mtklein36352bf2015-03-25 18:17:31 -07001305 void blitRect(int x, int y, int width, int height) override {
reed@google.com9154eb02011-10-31 16:07:28 +00001306 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001307 this->checkForYGap(y);
reed@google.com9154eb02011-10-31 16:07:28 +00001308 fBuilder->addRectRun(x, y, width, height);
reed@google.com302b8612012-02-16 19:30:13 +00001309 fLastY = y + height - 1;
reed@google.com562a2ac2011-10-31 14:14:18 +00001310 }
reed@google.com045e62d2011-10-24 12:19:46 +00001311
tomhudson@google.com49eac192011-12-27 13:59:20 +00001312 virtual void blitAntiRect(int x, int y, int width, int height,
mtklein36352bf2015-03-25 18:17:31 -07001313 SkAlpha leftAlpha, SkAlpha rightAlpha) override {
tomhudson@google.com49eac192011-12-27 13:59:20 +00001314 this->recordMinY(y);
reed@google.com302b8612012-02-16 19:30:13 +00001315 this->checkForYGap(y);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001316 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
reed@google.com302b8612012-02-16 19:30:13 +00001317 fLastY = y + height - 1;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001318 }
1319
mtklein36352bf2015-03-25 18:17:31 -07001320 void blitMask(const SkMask&, const SkIRect& clip) override
reed@google.come36707a2011-10-04 21:38:55 +00001321 { unexpected(); }
1322
reed41e010c2015-06-09 12:16:53 -07001323 const SkPixmap* justAnOpaqueColor(uint32_t*) override {
halcanary96fcdcc2015-08-27 07:41:13 -07001324 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00001325 }
1326
mtklein36352bf2015-03-25 18:17:31 -07001327 void blitH(int x, int y, int width) override {
reed@google.com209c4152011-10-26 15:03:48 +00001328 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001329 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001330 fBuilder->addRun(x, y, 0xFF, width);
1331 }
1332
1333 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
mtklein36352bf2015-03-25 18:17:31 -07001334 const int16_t runs[]) override {
reed@google.com209c4152011-10-26 15:03:48 +00001335 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001336 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001337 for (;;) {
1338 int count = *runs;
1339 if (count <= 0) {
1340 return;
1341 }
reed@google.com17785642011-10-12 20:23:55 +00001342
1343 // The supersampler's buffer can be the width of the device, so
liyuqian1d3ab122016-11-08 13:55:15 -08001344 // we may have to trim the run to our bounds. Previously, we assert that
1345 // the extra spans are always alpha==0.
1346 // However, the analytic AA is too sensitive to precision errors
1347 // so it may have extra spans with very tiny alpha because after several
1348 // arithmatic operations, the edge may bleed the path boundary a little bit.
1349 // Therefore, instead of always asserting alpha==0, we assert alpha < 0x10.
reed@google.com17785642011-10-12 20:23:55 +00001350 int localX = x;
1351 int localCount = count;
1352 if (x < fLeft) {
liyuqian1d3ab122016-11-08 13:55:15 -08001353 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001354 int gap = fLeft - x;
1355 SkASSERT(gap <= count);
1356 localX += gap;
1357 localCount -= gap;
1358 }
1359 int right = x + count;
1360 if (right > fRight) {
liyuqian1d3ab122016-11-08 13:55:15 -08001361 SkASSERT(0x10 > *alpha);
reed@google.com17785642011-10-12 20:23:55 +00001362 localCount -= right - fRight;
1363 SkASSERT(localCount >= 0);
1364 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001365
reed@google.com17785642011-10-12 20:23:55 +00001366 if (localCount) {
1367 fBuilder->addRun(localX, y, *alpha, localCount);
1368 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001369 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001370 runs += count;
1371 alpha += count;
1372 x += count;
1373 }
1374 }
1375
1376private:
1377 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001378 int fLeft; // cache of builder's bounds' left edge
1379 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001380 int fMinY;
1381
1382 /*
1383 * We track this, in case the scan converter skipped some number of
1384 * scanlines at the (relative to the bounds it was given). This allows
1385 * the builder, during its finish, to trip its bounds down to the "real"
1386 * top.
1387 */
1388 void recordMinY(int y) {
1389 if (y < fMinY) {
1390 fMinY = y;
1391 }
1392 }
reed@google.come36707a2011-10-04 21:38:55 +00001393
1394 void unexpected() {
Ben Wagner7ca9a742017-08-17 14:05:04 -04001395 SK_ABORT("---- did not expect to get called here");
reed@google.come36707a2011-10-04 21:38:55 +00001396 }
1397};
1398
reed@google.comf3c1da12011-10-10 19:35:47 +00001399bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001400 AUTO_AACLIP_VALIDATE(*this);
1401
reed@google.com32287892011-10-05 16:27:44 +00001402 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001403 return this->setEmpty();
1404 }
1405
1406 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001407 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001408
reed@google.com32287892011-10-05 16:27:44 +00001409 SkRegion tmpClip;
halcanary96fcdcc2015-08-27 07:41:13 -07001410 if (nullptr == clip) {
reed@google.com32287892011-10-05 16:27:44 +00001411 tmpClip.setRect(ibounds);
1412 clip = &tmpClip;
1413 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001414
Yuqian Lica85fc32016-11-10 09:44:55 -05001415 // Since we assert that the BuilderBlitter will never blit outside the intersection
1416 // of clip and ibounds, we create this snugClip to be that intersection and send it
1417 // to the scan-converter.
1418 SkRegion snugClip(*clip);
1419
reed@google.com045e62d2011-10-24 12:19:46 +00001420 if (path.isInverseFillType()) {
1421 ibounds = clip->getBounds();
1422 } else {
reed@google.com32287892011-10-05 16:27:44 +00001423 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001424 return this->setEmpty();
1425 }
Yuqian Lica85fc32016-11-10 09:44:55 -05001426 snugClip.op(ibounds, SkRegion::kIntersect_Op);
reed@google.come36707a2011-10-04 21:38:55 +00001427 }
1428
1429 Builder builder(ibounds);
1430 BuilderBlitter blitter(&builder);
1431
reed@google.comf3c1da12011-10-10 19:35:47 +00001432 if (doAA) {
Yuqian Li7d99dad2017-07-26 13:47:26 -04001433 SkScan::AntiFillPath(path, snugClip, &blitter, true);
reed@google.comf3c1da12011-10-10 19:35:47 +00001434 } else {
Yuqian Lica85fc32016-11-10 09:44:55 -05001435 SkScan::FillPath(path, snugClip, &blitter);
reed@google.comf3c1da12011-10-10 19:35:47 +00001436 }
reed@google.come36707a2011-10-04 21:38:55 +00001437
reed@google.com209c4152011-10-26 15:03:48 +00001438 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001439 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001440}
1441
1442///////////////////////////////////////////////////////////////////////////////
1443
reed@google.com32287892011-10-05 16:27:44 +00001444typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1445 const uint8_t* rowA, const SkIRect& rectA,
1446 const uint8_t* rowB, const SkIRect& rectB);
1447
reed@google.com32287892011-10-05 16:27:44 +00001448typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1449
1450static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1451 // Multiply
1452 return SkMulDiv255Round(alphaA, alphaB);
1453}
1454
1455static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1456 // SrcOver
1457 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1458}
1459
1460static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1461 // SrcOut
1462 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1463}
1464
1465static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1466 // XOR
1467 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1468}
1469
1470static AlphaProc find_alpha_proc(SkRegion::Op op) {
1471 switch (op) {
1472 case SkRegion::kIntersect_Op:
1473 return sectAlphaProc;
1474 case SkRegion::kDifference_Op:
1475 return diffAlphaProc;
1476 case SkRegion::kUnion_Op:
1477 return unionAlphaProc;
1478 case SkRegion::kXOR_Op:
1479 return xorAlphaProc;
1480 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001481 SkDEBUGFAIL("unexpected region op");
reed@google.com32287892011-10-05 16:27:44 +00001482 return sectAlphaProc;
1483 }
1484}
1485
reed@google.com32287892011-10-05 16:27:44 +00001486class RowIter {
1487public:
1488 RowIter(const uint8_t* row, const SkIRect& bounds) {
1489 fRow = row;
1490 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001491 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001492 if (row) {
1493 fRight = bounds.fLeft + row[0];
1494 SkASSERT(fRight <= fBoundsRight);
1495 fAlpha = row[1];
1496 fDone = false;
1497 } else {
1498 fDone = true;
1499 fRight = kMaxInt32;
1500 fAlpha = 0;
1501 }
reed@google.com32287892011-10-05 16:27:44 +00001502 }
1503
1504 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001505 int left() const { return fLeft; }
1506 int right() const { return fRight; }
1507 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001508 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001509 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001510 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001511 if (fRight == fBoundsRight) {
1512 fDone = true;
1513 fRight = kMaxInt32;
1514 fAlpha = 0;
1515 } else {
1516 fRow += 2;
1517 fRight += fRow[0];
1518 fAlpha = fRow[1];
1519 SkASSERT(fRight <= fBoundsRight);
1520 }
reed@google.com32287892011-10-05 16:27:44 +00001521 }
1522 }
1523
1524private:
1525 const uint8_t* fRow;
1526 int fLeft;
1527 int fRight;
1528 int fBoundsRight;
1529 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001530 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001531};
1532
reed@google.com1c04bf92011-10-10 12:57:12 +00001533static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1534 if (rite == riteA) {
1535 iter.next();
1536 leftA = iter.left();
1537 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001538 }
1539}
1540
caryclark@google.com803eceb2012-06-06 12:09:34 +00001541#if 0 // UNUSED
reed@google.com1c04bf92011-10-10 12:57:12 +00001542static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1543 SkASSERT(min < max);
1544 SkASSERT(boundsMin < boundsMax);
1545 if (min >= boundsMax || max <= boundsMin) {
1546 return false;
1547 }
1548 if (min < boundsMin) {
1549 min = boundsMin;
1550 }
1551 if (max > boundsMax) {
1552 max = boundsMax;
1553 }
1554 return true;
1555}
caryclark@google.com803eceb2012-06-06 12:09:34 +00001556#endif
reed@google.com1c04bf92011-10-10 12:57:12 +00001557
reed@google.com32287892011-10-05 16:27:44 +00001558static void operatorX(SkAAClip::Builder& builder, int lastY,
1559 RowIter& iterA, RowIter& iterB,
1560 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001561 int leftA = iterA.left();
1562 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001563 int leftB = iterB.left();
1564 int riteB = iterB.right();
1565
reed@google.com1c04bf92011-10-10 12:57:12 +00001566 int prevRite = bounds.fLeft;
1567
1568 do {
reed@google.com32287892011-10-05 16:27:44 +00001569 U8CPU alphaA = 0;
1570 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001571 int left, rite;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001572
reed@google.com1c04bf92011-10-10 12:57:12 +00001573 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001574 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001575 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001576 if (riteA <= leftB) {
1577 rite = riteA;
1578 } else {
1579 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001580 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001581 } else if (leftB < leftA) {
1582 left = leftB;
1583 alphaB = iterB.alpha();
1584 if (riteB <= leftA) {
1585 rite = riteB;
1586 } else {
1587 rite = leftB = leftA;
1588 }
1589 } else {
1590 left = leftA; // or leftB, since leftA == leftB
1591 rite = leftA = leftB = SkMin32(riteA, riteB);
1592 alphaA = iterA.alpha();
1593 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001594 }
1595
1596 if (left >= bounds.fRight) {
1597 break;
1598 }
reed@google.com34f7e472011-10-13 15:11:59 +00001599 if (rite > bounds.fRight) {
1600 rite = bounds.fRight;
1601 }
1602
reed@google.com32287892011-10-05 16:27:44 +00001603 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001604 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001605 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001606 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001607 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001608
1609 adjust_row(iterA, leftA, riteA, rite);
1610 adjust_row(iterB, leftB, riteB, rite);
1611 } while (!iterA.done() || !iterB.done());
1612
1613 if (prevRite < bounds.fRight) {
1614 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001615 }
1616}
1617
reed@google.com1c04bf92011-10-10 12:57:12 +00001618static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1619 if (bot == botA) {
1620 iter.next();
1621 topA = botA;
1622 SkASSERT(botA == iter.top());
1623 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001624 }
1625}
1626
1627static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1628 const SkAAClip& B, SkRegion::Op op) {
1629 AlphaProc proc = find_alpha_proc(op);
1630 const SkIRect& bounds = builder.getBounds();
1631
1632 SkAAClip::Iter iterA(A);
1633 SkAAClip::Iter iterB(B);
1634
1635 SkASSERT(!iterA.done());
1636 int topA = iterA.top();
1637 int botA = iterA.bottom();
1638 SkASSERT(!iterB.done());
1639 int topB = iterB.top();
1640 int botB = iterB.bottom();
1641
reed@google.com1c04bf92011-10-10 12:57:12 +00001642 do {
halcanary96fcdcc2015-08-27 07:41:13 -07001643 const uint8_t* rowA = nullptr;
1644 const uint8_t* rowB = nullptr;
reed@google.com32287892011-10-05 16:27:44 +00001645 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001646
1647 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001648 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001649 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001650 if (botA <= topB) {
1651 bot = botA;
1652 } else {
1653 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001654 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001655
reed@google.com1c04bf92011-10-10 12:57:12 +00001656 } else if (topB < topA) {
1657 top = topB;
1658 rowB = iterB.data();
1659 if (botB <= topA) {
1660 bot = botB;
1661 } else {
1662 bot = topB = topA;
1663 }
1664 } else {
1665 top = topA; // or topB, since topA == topB
1666 bot = topA = topB = SkMin32(botA, botB);
1667 rowA = iterA.data();
1668 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001669 }
1670
1671 if (top >= bounds.fBottom) {
1672 break;
1673 }
reed@google.com34f7e472011-10-13 15:11:59 +00001674
1675 if (bot > bounds.fBottom) {
1676 bot = bounds.fBottom;
1677 }
1678 SkASSERT(top < bot);
1679
reed@google.com1c04bf92011-10-10 12:57:12 +00001680 if (!rowA && !rowB) {
1681 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1682 } else if (top >= bounds.fTop) {
1683 SkASSERT(bot <= bounds.fBottom);
1684 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1685 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001686 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001687 }
1688
reed@google.com1c04bf92011-10-10 12:57:12 +00001689 adjust_iter(iterA, topA, botA, bot);
1690 adjust_iter(iterB, topB, botB, bot);
1691 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001692}
1693
1694bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1695 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001696 AUTO_AACLIP_VALIDATE(*this);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001697
reed@google.com32287892011-10-05 16:27:44 +00001698 if (SkRegion::kReplace_Op == op) {
1699 return this->set(clipBOrig);
1700 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001701
reed@google.com32287892011-10-05 16:27:44 +00001702 const SkAAClip* clipA = &clipAOrig;
1703 const SkAAClip* clipB = &clipBOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001704
reed@google.com32287892011-10-05 16:27:44 +00001705 if (SkRegion::kReverseDifference_Op == op) {
Ben Wagnerf08d1d02018-06-18 15:11:00 -04001706 using std::swap;
1707 swap(clipA, clipB);
reed@google.com32287892011-10-05 16:27:44 +00001708 op = SkRegion::kDifference_Op;
1709 }
1710
1711 bool a_empty = clipA->isEmpty();
1712 bool b_empty = clipB->isEmpty();
1713
1714 SkIRect bounds;
1715 switch (op) {
1716 case SkRegion::kDifference_Op:
1717 if (a_empty) {
1718 return this->setEmpty();
1719 }
1720 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1721 return this->set(*clipA);
1722 }
1723 bounds = clipA->fBounds;
1724 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001725
reed@google.com32287892011-10-05 16:27:44 +00001726 case SkRegion::kIntersect_Op:
1727 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1728 clipB->fBounds)) {
1729 return this->setEmpty();
1730 }
1731 break;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001732
reed@google.com32287892011-10-05 16:27:44 +00001733 case SkRegion::kUnion_Op:
1734 case SkRegion::kXOR_Op:
1735 if (a_empty) {
1736 return this->set(*clipB);
1737 }
1738 if (b_empty) {
1739 return this->set(*clipA);
1740 }
1741 bounds = clipA->fBounds;
1742 bounds.join(clipB->fBounds);
1743 break;
1744
1745 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001746 SkDEBUGFAIL("unknown region op");
reed@google.com32287892011-10-05 16:27:44 +00001747 return !this->isEmpty();
1748 }
1749
reed@google.com32287892011-10-05 16:27:44 +00001750 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1751 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1752
1753 Builder builder(bounds);
1754 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001755
1756 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001757}
1758
reed@google.com045e62d2011-10-24 12:19:46 +00001759/*
1760 * It can be expensive to build a local aaclip before applying the op, so
1761 * we first see if we can restrict the bounds of new rect to our current
1762 * bounds, or note that the new rect subsumes our current clip.
1763 */
1764
1765bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1766 SkIRect rStorage;
1767 const SkIRect* r = &rOrig;
1768
1769 switch (op) {
1770 case SkRegion::kIntersect_Op:
1771 if (!rStorage.intersect(rOrig, fBounds)) {
1772 // no overlap, so we're empty
1773 return this->setEmpty();
1774 }
1775 if (rStorage == fBounds) {
1776 // we were wholly inside the rect, no change
1777 return !this->isEmpty();
1778 }
1779 if (this->quickContains(rStorage)) {
1780 // the intersection is wholly inside us, we're a rect
1781 return this->setRect(rStorage);
1782 }
1783 r = &rStorage; // use the intersected bounds
1784 break;
1785 case SkRegion::kDifference_Op:
1786 break;
1787 case SkRegion::kUnion_Op:
1788 if (rOrig.contains(fBounds)) {
1789 return this->setRect(rOrig);
1790 }
1791 break;
1792 default:
1793 break;
1794 }
1795
reed@google.com47ac84e2011-10-06 13:11:25 +00001796 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001797 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001798 return this->op(*this, clip, op);
1799}
1800
reed@google.com045e62d2011-10-24 12:19:46 +00001801bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1802 SkRect rStorage, boundsStorage;
1803 const SkRect* r = &rOrig;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001804
reed@google.com045e62d2011-10-24 12:19:46 +00001805 boundsStorage.set(fBounds);
1806 switch (op) {
1807 case SkRegion::kIntersect_Op:
1808 case SkRegion::kDifference_Op:
1809 if (!rStorage.intersect(rOrig, boundsStorage)) {
reed@google.come56513d2012-06-25 20:06:33 +00001810 if (SkRegion::kIntersect_Op == op) {
1811 return this->setEmpty();
1812 } else { // kDifference
1813 return !this->isEmpty();
1814 }
reed@google.com045e62d2011-10-24 12:19:46 +00001815 }
1816 r = &rStorage; // use the intersected bounds
1817 break;
1818 case SkRegion::kUnion_Op:
1819 if (rOrig.contains(boundsStorage)) {
1820 return this->setRect(rOrig);
1821 }
1822 break;
1823 default:
1824 break;
1825 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001826
reed@google.com47ac84e2011-10-06 13:11:25 +00001827 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001828 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001829 return this->op(*this, clip, op);
1830}
1831
1832bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1833 return this->op(*this, clip, op);
1834}
1835
reed@google.come36707a2011-10-04 21:38:55 +00001836///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001837
1838bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
halcanary96fcdcc2015-08-27 07:41:13 -07001839 if (nullptr == dst) {
reed@google.com045e62d2011-10-24 12:19:46 +00001840 return !this->isEmpty();
1841 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001842
reed@google.com045e62d2011-10-24 12:19:46 +00001843 if (this->isEmpty()) {
1844 return dst->setEmpty();
1845 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001846
reed@google.com045e62d2011-10-24 12:19:46 +00001847 if (this != dst) {
1848 sk_atomic_inc(&fRunHead->fRefCnt);
tomhudson@google.com19224c32012-03-28 15:46:37 +00001849 dst->freeRuns();
reed@google.com045e62d2011-10-24 12:19:46 +00001850 dst->fRunHead = fRunHead;
1851 dst->fBounds = fBounds;
1852 }
1853 dst->fBounds.offset(dx, dy);
1854 return true;
1855}
1856
1857static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1858 const uint8_t* SK_RESTRICT row,
1859 int width) {
1860 while (width > 0) {
1861 int n = row[0];
1862 SkASSERT(width >= n);
1863 memset(mask, row[1], n);
1864 mask += n;
1865 row += 2;
1866 width -= n;
1867 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001868 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001869}
1870
1871void SkAAClip::copyToMask(SkMask* mask) const {
1872 mask->fFormat = SkMask::kA8_Format;
1873 if (this->isEmpty()) {
1874 mask->fBounds.setEmpty();
halcanary96fcdcc2015-08-27 07:41:13 -07001875 mask->fImage = nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00001876 mask->fRowBytes = 0;
1877 return;
1878 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001879
reed@google.com045e62d2011-10-24 12:19:46 +00001880 mask->fBounds = fBounds;
1881 mask->fRowBytes = fBounds.width();
1882 size_t size = mask->computeImageSize();
1883 mask->fImage = SkMask::AllocImage(size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001884
reed@google.com045e62d2011-10-24 12:19:46 +00001885 Iter iter(*this);
1886 uint8_t* dst = mask->fImage;
1887 const int width = fBounds.width();
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001888
reed@google.com045e62d2011-10-24 12:19:46 +00001889 int y = fBounds.fTop;
1890 while (!iter.done()) {
1891 do {
1892 expand_row_to_mask(dst, iter.data(), width);
1893 dst += mask->fRowBytes;
1894 } while (++y < iter.bottom());
1895 iter.next();
1896 }
1897}
1898
1899///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001900///////////////////////////////////////////////////////////////////////////////
1901
1902static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1903 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1904 // we don't read our initial n from data, since the caller may have had to
1905 // clip it, hence the initialCount parameter.
1906 int n = initialCount;
1907 for (;;) {
1908 if (n > width) {
1909 n = width;
1910 }
1911 SkASSERT(n > 0);
1912 runs[0] = n;
1913 runs += n;
1914
1915 aa[0] = data[1];
1916 aa += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001917
reed@google.come36707a2011-10-04 21:38:55 +00001918 data += 2;
1919 width -= n;
1920 if (0 == width) {
1921 break;
1922 }
1923 // load the next count
1924 n = data[0];
1925 }
1926 runs[0] = 0; // sentinel
1927}
1928
1929SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001930 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001931}
1932
1933void SkAAClipBlitter::ensureRunsAndAA() {
halcanary96fcdcc2015-08-27 07:41:13 -07001934 if (nullptr == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001935 // add 1 so we can store the terminating run count of 0
1936 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001937 // we use this either for fRuns + fAA, or a scaline of a mask
1938 // which may be as deep as 32bits
1939 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1940 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001941 fAA = (SkAlpha*)(fRuns + count);
1942 }
1943}
1944
1945void SkAAClipBlitter::blitH(int x, int y, int width) {
1946 SkASSERT(width > 0);
1947 SkASSERT(fAAClipBounds.contains(x, y));
1948 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1949
reed@google.coma4c6e4d2012-06-20 14:29:50 +00001950 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00001951 int initialCount;
1952 row = fAAClip->findX(row, x, &initialCount);
1953
1954 if (initialCount >= width) {
1955 SkAlpha alpha = row[1];
1956 if (0 == alpha) {
1957 return;
1958 }
1959 if (0xFF == alpha) {
1960 fBlitter->blitH(x, y, width);
1961 return;
1962 }
1963 }
1964
1965 this->ensureRunsAndAA();
1966 expandToRuns(row, initialCount, width, fRuns, fAA);
1967
1968 fBlitter->blitAntiH(x, y, fAA, fRuns);
1969}
1970
1971static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1972 const SkAlpha* SK_RESTRICT srcAA,
1973 const int16_t* SK_RESTRICT srcRuns,
1974 SkAlpha* SK_RESTRICT dstAA,
1975 int16_t* SK_RESTRICT dstRuns,
1976 int width) {
1977 SkDEBUGCODE(int accumulated = 0;)
1978 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001979 // do we need this check?
1980 if (0 == srcN) {
1981 return;
1982 }
1983
reed@google.come36707a2011-10-04 21:38:55 +00001984 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001985 SkASSERT(rowN > 0);
1986 SkASSERT(srcN > 0);
1987
1988 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1989 int minN = SkMin32(srcN, rowN);
1990 dstRuns[0] = minN;
1991 dstRuns += minN;
1992 dstAA[0] = newAlpha;
1993 dstAA += minN;
1994
1995 if (0 == (srcN -= minN)) {
1996 srcN = srcRuns[0]; // refresh
1997 srcRuns += srcN;
1998 srcAA += srcN;
1999 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00002000 if (0 == srcN) {
2001 break;
2002 }
reed@google.come36707a2011-10-04 21:38:55 +00002003 }
2004 if (0 == (rowN -= minN)) {
2005 row += 2;
2006 rowN = row[0]; // reload
2007 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002008
reed@google.come36707a2011-10-04 21:38:55 +00002009 SkDEBUGCODE(accumulated += minN;)
2010 SkASSERT(accumulated <= width);
2011 }
reed@google.com34f7e472011-10-13 15:11:59 +00002012 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00002013}
2014
2015void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
2016 const int16_t runs[]) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002017
2018 const uint8_t* row = fAAClip->findRow(y);
reed@google.come36707a2011-10-04 21:38:55 +00002019 int initialCount;
2020 row = fAAClip->findX(row, x, &initialCount);
2021
2022 this->ensureRunsAndAA();
2023
2024 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
2025 fBlitter->blitAntiH(x, y, fAA, fRuns);
2026}
2027
2028void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
2029 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
2030 fBlitter->blitV(x, y, height, alpha);
2031 return;
2032 }
2033
reed@google.com045e62d2011-10-24 12:19:46 +00002034 for (;;) {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002035 int lastY SK_INIT_TO_AVOID_WARNING;
reed@google.come36707a2011-10-04 21:38:55 +00002036 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00002037 int dy = lastY - y + 1;
2038 if (dy > height) {
2039 dy = height;
2040 }
2041 height -= dy;
2042
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002043 row = fAAClip->findX(row, x);
reed@google.come36707a2011-10-04 21:38:55 +00002044 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
2045 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00002046 fBlitter->blitV(x, y, dy, newAlpha);
2047 }
2048 SkASSERT(height >= 0);
2049 if (height <= 0) {
2050 break;
reed@google.come36707a2011-10-04 21:38:55 +00002051 }
2052 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00002053 }
reed@google.come36707a2011-10-04 21:38:55 +00002054}
2055
2056void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
2057 if (fAAClip->quickContains(x, y, x + width, y + height)) {
2058 fBlitter->blitRect(x, y, width, height);
2059 return;
2060 }
2061
2062 while (--height >= 0) {
2063 this->blitH(x, y, width);
2064 y += 1;
2065 }
2066}
2067
reed@google.com045e62d2011-10-24 12:19:46 +00002068typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
2069 int initialRowCount, void* dst);
2070
2071static void small_memcpy(void* dst, const void* src, size_t n) {
2072 memcpy(dst, src, n);
2073}
2074
2075static void small_bzero(void* dst, size_t n) {
2076 sk_bzero(dst, n);
2077}
2078
2079static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
2080 return SkMulDiv255Round(value, alpha);
2081}
reedd54d3fc2014-11-13 14:39:58 -08002082
reed@google.com045e62d2011-10-24 12:19:46 +00002083static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
2084 unsigned r = SkGetPackedR16(value);
2085 unsigned g = SkGetPackedG16(value);
2086 unsigned b = SkGetPackedB16(value);
2087 return SkPackRGB16(SkMulDiv255Round(r, alpha),
caryclark@google.com803eceb2012-06-06 12:09:34 +00002088 SkMulDiv255Round(g, alpha),
2089 SkMulDiv255Round(b, alpha));
reed@google.com045e62d2011-10-24 12:19:46 +00002090}
reed@google.com045e62d2011-10-24 12:19:46 +00002091
herb94496162015-12-10 14:17:41 -08002092template <typename T>
2093void mergeT(const void* inSrc, int srcN, const uint8_t* SK_RESTRICT row, int rowN, void* inDst) {
2094 const T* SK_RESTRICT src = static_cast<const T*>(inSrc);
2095 T* SK_RESTRICT dst = static_cast<T*>(inDst);
reed@google.com045e62d2011-10-24 12:19:46 +00002096 for (;;) {
2097 SkASSERT(rowN > 0);
2098 SkASSERT(srcN > 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002099
reed@google.com045e62d2011-10-24 12:19:46 +00002100 int n = SkMin32(rowN, srcN);
2101 unsigned rowA = row[1];
2102 if (0xFF == rowA) {
2103 small_memcpy(dst, src, n * sizeof(T));
2104 } else if (0 == rowA) {
2105 small_bzero(dst, n * sizeof(T));
2106 } else {
2107 for (int i = 0; i < n; ++i) {
2108 dst[i] = mergeOne(src[i], rowA);
2109 }
2110 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002111
reed@google.com045e62d2011-10-24 12:19:46 +00002112 if (0 == (srcN -= n)) {
2113 break;
2114 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002115
reed@google.com045e62d2011-10-24 12:19:46 +00002116 src += n;
2117 dst += n;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00002118
reed@google.com045e62d2011-10-24 12:19:46 +00002119 SkASSERT(rowN == n);
2120 row += 2;
2121 rowN = row[0];
2122 }
2123}
2124
2125static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2126 switch (format) {
2127 case SkMask::kBW_Format:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002128 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002129 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002130 case SkMask::kA8_Format:
herb94496162015-12-10 14:17:41 -08002131 case SkMask::k3D_Format:
2132 return mergeT<uint8_t> ;
2133 case SkMask::kLCD16_Format:
2134 return mergeT<uint16_t>;
reed@google.com045e62d2011-10-24 12:19:46 +00002135 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002136 SkDEBUGFAIL("unsupported");
halcanary96fcdcc2015-08-27 07:41:13 -07002137 return nullptr;
reed@google.com045e62d2011-10-24 12:19:46 +00002138 }
2139}
2140
2141static U8CPU bit2byte(int bitInAByte) {
2142 SkASSERT(bitInAByte <= 0xFF);
2143 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2144 // some value >= 8 to get a full FF value
2145 return -bitInAByte >> 8;
2146}
2147
2148static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2149 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2150 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2151
2152 const int width = srcMask.fBounds.width();
2153 const int height = srcMask.fBounds.height();
2154
2155 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2156 const size_t srcRB = srcMask.fRowBytes;
2157 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2158 const size_t dstRB = dstMask->fRowBytes;
2159
2160 const int wholeBytes = width >> 3;
2161 const int leftOverBits = width & 7;
2162
2163 for (int y = 0; y < height; ++y) {
2164 uint8_t* SK_RESTRICT d = dst;
2165 for (int i = 0; i < wholeBytes; ++i) {
2166 int srcByte = src[i];
2167 d[0] = bit2byte(srcByte & (1 << 7));
2168 d[1] = bit2byte(srcByte & (1 << 6));
2169 d[2] = bit2byte(srcByte & (1 << 5));
2170 d[3] = bit2byte(srcByte & (1 << 4));
2171 d[4] = bit2byte(srcByte & (1 << 3));
2172 d[5] = bit2byte(srcByte & (1 << 2));
2173 d[6] = bit2byte(srcByte & (1 << 1));
2174 d[7] = bit2byte(srcByte & (1 << 0));
2175 d += 8;
2176 }
2177 if (leftOverBits) {
2178 int srcByte = src[wholeBytes];
2179 for (int x = 0; x < leftOverBits; ++x) {
2180 *d++ = bit2byte(srcByte & 0x80);
2181 srcByte <<= 1;
2182 }
2183 }
2184 src += srcRB;
2185 dst += dstRB;
2186 }
2187}
2188
2189void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2190 SkASSERT(fAAClip->getBounds().contains(clip));
2191
2192 if (fAAClip->quickContains(clip)) {
2193 fBlitter->blitMask(origMask, clip);
2194 return;
2195 }
2196
2197 const SkMask* mask = &origMask;
2198
2199 // if we're BW, we need to upscale to A8 (ugh)
2200 SkMask grayMask;
reed@google.com045e62d2011-10-24 12:19:46 +00002201 if (SkMask::kBW_Format == origMask.fFormat) {
2202 grayMask.fFormat = SkMask::kA8_Format;
2203 grayMask.fBounds = origMask.fBounds;
2204 grayMask.fRowBytes = origMask.fBounds.width();
2205 size_t size = grayMask.computeImageSize();
2206 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2207 SkAutoMalloc::kReuse_OnShrink);
2208
2209 upscaleBW2A8(&grayMask, origMask);
2210 mask = &grayMask;
2211 }
2212
2213 this->ensureRunsAndAA();
2214
2215 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2216 // data into a temp block to support it better (ugh)
2217
2218 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2219 const size_t srcRB = mask->fRowBytes;
2220 const int width = clip.width();
2221 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2222
2223 SkMask rowMask;
2224 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2225 rowMask.fBounds.fLeft = clip.fLeft;
2226 rowMask.fBounds.fRight = clip.fRight;
2227 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2228 rowMask.fImage = (uint8_t*)fScanlineScratch;
2229
2230 int y = clip.fTop;
2231 const int stopY = y + clip.height();
2232
2233 do {
reed@google.coma4c6e4d2012-06-20 14:29:50 +00002234 int localStopY SK_INIT_TO_AVOID_WARNING;
reed@google.com045e62d2011-10-24 12:19:46 +00002235 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2236 // findRow returns last Y, not stop, so we add 1
2237 localStopY = SkMin32(localStopY + 1, stopY);
2238
2239 int initialCount;
2240 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2241 do {
2242 mergeProc(src, width, row, initialCount, rowMask.fImage);
2243 rowMask.fBounds.fTop = y;
2244 rowMask.fBounds.fBottom = y + 1;
2245 fBlitter->blitMask(rowMask, rowMask.fBounds);
2246 src = (const void*)((const char*)src + srcRB);
2247 } while (++y < localStopY);
2248 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002249}
2250
reed41e010c2015-06-09 12:16:53 -07002251const SkPixmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
halcanary96fcdcc2015-08-27 07:41:13 -07002252 return nullptr;
reed@google.come36707a2011-10-04 21:38:55 +00002253}