blob: fe0fb286dc3650e598c064e96a1682730c3f1ac9 [file] [log] [blame]
reed@google.come36707a2011-10-04 21:38:55 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "SkAAClip.h"
10#include "SkBlitter.h"
reed@google.com045e62d2011-10-24 12:19:46 +000011#include "SkColorPriv.h"
reed@google.come36707a2011-10-04 21:38:55 +000012#include "SkPath.h"
13#include "SkScan.h"
14#include "SkThread.h"
reed@google.com34f7e472011-10-13 15:11:59 +000015#include "SkUtils.h"
reed@google.come36707a2011-10-04 21:38:55 +000016
reed@google.com045e62d2011-10-24 12:19:46 +000017class AutoAAClipValidate {
18public:
19 AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) {
20 fClip.validate();
21 }
22 ~AutoAAClipValidate() {
23 fClip.validate();
24 }
25private:
26 const SkAAClip& fClip;
27};
28
29#ifdef SK_DEBUG
30 #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip)
31#else
32 #define AUTO_AACLIP_VALIDATE(clip)
33#endif
34
35///////////////////////////////////////////////////////////////////////////////
36
reed@google.com1c04bf92011-10-10 12:57:12 +000037#define kMaxInt32 0x7FFFFFFF
38
reed@google.come36707a2011-10-04 21:38:55 +000039static inline bool x_in_rect(int x, const SkIRect& rect) {
40 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
41}
42
43static inline bool y_in_rect(int y, const SkIRect& rect) {
44 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
45}
46
47/*
48 * Data runs are packed [count, alpha]
49 */
50
51struct SkAAClip::YOffset {
52 int32_t fY;
53 uint32_t fOffset;
54};
55
56struct SkAAClip::RunHead {
57 int32_t fRefCnt;
58 int32_t fRowCount;
59 int32_t fDataSize;
60
61 YOffset* yoffsets() {
62 return (YOffset*)((char*)this + sizeof(RunHead));
63 }
64 const YOffset* yoffsets() const {
65 return (const YOffset*)((const char*)this + sizeof(RunHead));
66 }
67 uint8_t* data() {
68 return (uint8_t*)(this->yoffsets() + fRowCount);
69 }
70 const uint8_t* data() const {
71 return (const uint8_t*)(this->yoffsets() + fRowCount);
72 }
73
74 static RunHead* Alloc(int rowCount, size_t dataSize) {
75 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
76 RunHead* head = (RunHead*)sk_malloc_throw(size);
77 head->fRefCnt = 1;
78 head->fRowCount = rowCount;
79 head->fDataSize = dataSize;
80 return head;
81 }
reed@google.com045e62d2011-10-24 12:19:46 +000082
83 static int ComputeRowSizeForWidth(int width) {
84 // 2 bytes per segment, where each segment can store up to 255 for count
85 int segments = 0;
86 while (width > 0) {
87 segments += 1;
88 int n = SkMin32(width, 255);
89 width -= n;
90 }
91 return segments * 2; // each segment is row[0] + row[1] (n + alpha)
92 }
93
94 static RunHead* AllocRect(const SkIRect& bounds) {
95 SkASSERT(!bounds.isEmpty());
96 int width = bounds.width();
97 size_t rowSize = ComputeRowSizeForWidth(width);
98 RunHead* head = RunHead::Alloc(1, rowSize);
99 YOffset* yoff = head->yoffsets();
100 yoff->fY = bounds.height() - 1;
101 yoff->fOffset = 0;
102 uint8_t* row = head->data();
103 while (width > 0) {
104 int n = SkMin32(width, 255);
105 row[0] = n;
106 row[1] = 0xFF;
107 width -= n;
108 row += 2;
109 }
110 return head;
111 }
reed@google.come36707a2011-10-04 21:38:55 +0000112};
113
reed@google.com32287892011-10-05 16:27:44 +0000114class SkAAClip::Iter {
115public:
116 Iter(const SkAAClip&);
117
118 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000119 int top() const { return fTop; }
120 int bottom() const { return fBottom; }
121 const uint8_t* data() const { return fData; }
reed@google.com32287892011-10-05 16:27:44 +0000122 void next();
123
124private:
125 const YOffset* fCurrYOff;
126 const YOffset* fStopYOff;
127 const uint8_t* fData;
128
129 int fTop, fBottom;
130 bool fDone;
131};
132
133SkAAClip::Iter::Iter(const SkAAClip& clip) {
134 if (clip.isEmpty()) {
135 fDone = true;
reed@google.com1c04bf92011-10-10 12:57:12 +0000136 fTop = fBottom = clip.fBounds.fBottom;
137 fData = NULL;
reed@google.com32287892011-10-05 16:27:44 +0000138 return;
139 }
140
141 const RunHead* head = clip.fRunHead;
142 fCurrYOff = head->yoffsets();
143 fStopYOff = fCurrYOff + head->fRowCount;
144 fData = head->data() + fCurrYOff->fOffset;
145
146 // setup first value
147 fTop = clip.fBounds.fTop;
148 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
149 fDone = false;
150}
151
152void SkAAClip::Iter::next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000153 if (!fDone) {
154 const YOffset* prev = fCurrYOff;
155 const YOffset* curr = prev + 1;
156 SkASSERT(curr <= fStopYOff);
reed@google.com32287892011-10-05 16:27:44 +0000157
reed@google.com32287892011-10-05 16:27:44 +0000158 fTop = fBottom;
reed@google.com1c04bf92011-10-10 12:57:12 +0000159 if (curr >= fStopYOff) {
160 fDone = true;
161 fBottom = kMaxInt32;
162 fData = NULL;
163 } else {
164 fBottom += curr->fY - prev->fY;
165 fData += curr->fOffset - prev->fOffset;
166 fCurrYOff = curr;
167 }
reed@google.com32287892011-10-05 16:27:44 +0000168 }
169}
170
reed@google.com045e62d2011-10-24 12:19:46 +0000171#ifdef SK_DEBUG
reed@google.comc9041912011-10-27 16:58:46 +0000172// assert we're exactly width-wide, and then return the number of bytes used
reed@google.com045e62d2011-10-24 12:19:46 +0000173static size_t compute_row_length(const uint8_t row[], int width) {
174 const uint8_t* origRow = row;
175 while (width > 0) {
176 int n = row[0];
reed@google.comc9041912011-10-27 16:58:46 +0000177 SkASSERT(n > 0);
reed@google.com045e62d2011-10-24 12:19:46 +0000178 SkASSERT(n <= width);
179 row += 2;
180 width -= n;
181 }
182 SkASSERT(0 == width);
183 return row - origRow;
184}
185
186void SkAAClip::validate() const {
187 if (NULL == fRunHead) {
188 SkASSERT(fBounds.isEmpty());
189 return;
190 }
191
192 const RunHead* head = fRunHead;
193 SkASSERT(head->fRefCnt > 0);
194 SkASSERT(head->fRowCount > 0);
195 SkASSERT(head->fDataSize > 0);
196
197 const YOffset* yoff = head->yoffsets();
198 const YOffset* ystop = yoff + head->fRowCount;
reed@google.comc9041912011-10-27 16:58:46 +0000199 const int lastY = fBounds.height() - 1;
200
201 // Y and offset must be monotonic
202 int prevY = -1;
203 int32_t prevOffset = -1;
reed@google.com045e62d2011-10-24 12:19:46 +0000204 while (yoff < ystop) {
reed@google.comc9041912011-10-27 16:58:46 +0000205 SkASSERT(prevY < yoff->fY);
206 SkASSERT(yoff->fY <= lastY);
207 prevY = yoff->fY;
208 SkASSERT(prevOffset < (int32_t)yoff->fOffset);
209 prevOffset = yoff->fOffset;
210 const uint8_t* row = head->data() + yoff->fOffset;
reed@google.com045e62d2011-10-24 12:19:46 +0000211 size_t rowLength = compute_row_length(row, fBounds.width());
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +0000212 SkASSERT(yoff->fOffset + rowLength <= (size_t) head->fDataSize);
reed@google.comc9041912011-10-27 16:58:46 +0000213 yoff += 1;
reed@google.com045e62d2011-10-24 12:19:46 +0000214 }
reed@google.com045e62d2011-10-24 12:19:46 +0000215 // check the last entry;
216 --yoff;
reed@google.comc9041912011-10-27 16:58:46 +0000217 SkASSERT(yoff->fY == lastY);
reed@google.com045e62d2011-10-24 12:19:46 +0000218}
219#endif
220
221///////////////////////////////////////////////////////////////////////////////
222
reed@google.comc9041912011-10-27 16:58:46 +0000223static void count_left_right_zeros(const uint8_t* row, int width,
224 int* leftZ, int* riteZ) {
225 int zeros = 0;
226 do {
227 if (row[1]) {
228 break;
229 }
230 int n = row[0];
231 SkASSERT(n > 0);
232 SkASSERT(n <= width);
233 zeros += n;
234 row += 2;
235 width -= n;
236 } while (width > 0);
237 *leftZ = zeros;
238
239 zeros = 0;
240 while (width > 0) {
241 int n = row[0];
242 SkASSERT(n > 0);
243 if (0 == row[1]) {
244 zeros += n;
245 } else {
246 zeros = 0;
247 }
248 row += 2;
249 width -= n;
250 }
251 *riteZ = zeros;
252}
253
254#ifdef SK_DEBUG
255static void test_count_left_right_zeros() {
256 static bool gOnce;
257 if (gOnce) {
258 return;
259 }
260 gOnce = true;
261
262 const uint8_t data0[] = { 0, 0, 10, 0xFF };
263 const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF };
264 const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF };
265 const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 };
266 const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 };
267 const uint8_t data5[] = { 10, 0, 10, 0 };
268 const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
269
270 const uint8_t* array[] = {
271 data0, data1, data2, data3, data4, data5, data6
272 };
273
274 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
275 const uint8_t* data = array[i];
276 const int expectedL = *data++;
277 const int expectedR = *data++;
278 int L = 12345, R = 12345;
279 count_left_right_zeros(data, 10, &L, &R);
280 SkASSERT(expectedL == L);
281 SkASSERT(expectedR == R);
282 }
283}
284#endif
285
286// modify row in place, trimming off (zeros) from the left and right sides.
287// return the number of bytes that were completely eliminated from the left
288static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) {
289 int trim = 0;
290 while (leftZ > 0) {
291 SkASSERT(0 == row[1]);
292 int n = row[0];
293 SkASSERT(n > 0);
294 SkASSERT(n <= width);
295 width -= n;
296 row += 2;
297 if (n > leftZ) {
298 row[-2] = n - leftZ;
299 break;
300 }
301 trim += 2;
302 leftZ -= n;
303 SkASSERT(leftZ >= 0);
304 }
305
306 if (riteZ) {
307 // walk row to the end, and then we'll back up to trim riteZ
308 while (width > 0) {
309 int n = row[0];
310 SkASSERT(n <= width);
311 width -= n;
312 row += 2;
313 }
314 // now skip whole runs of zeros
315 do {
316 row -= 2;
317 SkASSERT(0 == row[1]);
318 int n = row[0];
319 SkASSERT(n > 0);
320 if (n > riteZ) {
321 row[0] = n - riteZ;
322 break;
323 }
324 riteZ -= n;
325 SkASSERT(riteZ >= 0);
326 } while (riteZ > 0);
327 }
328
329 return trim;
330}
331
332#ifdef SK_DEBUG
333// assert that this row is exactly this width
reed@google.comc5507bf2011-10-27 21:15:36 +0000334static void assert_row_width(const uint8_t* row, int width) {
reed@google.comc9041912011-10-27 16:58:46 +0000335 while (width > 0) {
336 int n = row[0];
337 SkASSERT(n > 0);
338 SkASSERT(n <= width);
339 width -= n;
340 row += 2;
341 }
342 SkASSERT(0 == width);
343}
344
345static void test_trim_row_left_right() {
346 static bool gOnce;
347 if (gOnce) {
348 return;
349 }
350 gOnce = true;
351
352 uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF };
353 uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF };
354 uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
355 uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF };
356 uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
357 uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
358 uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
359 uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
360 uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 };
361 uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 };
362 uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF };
363
364 uint8_t* array[] = {
365 data0, data1, data2, data3, data4,
366 data5, data6, data7, data8, data9,
367 data10
368 };
369
370 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
371 uint8_t* data = array[i];
372 const int trimL = *data++;
373 const int trimR = *data++;
374 const int expectedSkip = *data++;
375 const int origWidth = *data++;
376 assert_row_width(data, origWidth);
377 int skip = trim_row_left_right(data, origWidth, trimL, trimR);
378 SkASSERT(expectedSkip == skip);
379 int expectedWidth = origWidth - trimL - trimR;
380 assert_row_width(data + skip, expectedWidth);
381 }
382}
383#endif
384
385bool SkAAClip::trimLeftRight() {
386 SkDEBUGCODE(test_trim_row_left_right();)
387
388 if (this->isEmpty()) {
389 return false;
390 }
391
392 AUTO_AACLIP_VALIDATE(*this);
393
394 const int width = fBounds.width();
395 RunHead* head = fRunHead;
396 YOffset* yoff = head->yoffsets();
397 YOffset* stop = yoff + head->fRowCount;
398 uint8_t* base = head->data();
399
400 int leftZeros = width;
401 int riteZeros = width;
402 while (yoff < stop) {
403 int L, R;
404 count_left_right_zeros(base + yoff->fOffset, width, &L, &R);
405 if (L < leftZeros) {
406 leftZeros = L;
407 }
408 if (R < riteZeros) {
409 riteZeros = R;
410 }
411 if (0 == (leftZeros | riteZeros)) {
412 // no trimming to do
413 return true;
414 }
415 yoff += 1;
416 }
417
418 SkASSERT(leftZeros || riteZeros);
419 if (width == (leftZeros + riteZeros)) {
420 return this->setEmpty();
421 }
422
423 this->validate();
424
425 fBounds.fLeft += leftZeros;
426 fBounds.fRight -= riteZeros;
427 SkASSERT(!fBounds.isEmpty());
428
429 // For now we don't realloc the storage (for time), we just shrink in place
430 // This means we don't have to do any memmoves either, since we can just
431 // play tricks with the yoff->fOffset for each row
432 yoff = head->yoffsets();
433 while (yoff < stop) {
434 uint8_t* row = base + yoff->fOffset;
435 SkDEBUGCODE((void)compute_row_length(row, width);)
436 yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros);
437 SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);)
438 yoff += 1;
439 }
440 return true;
441}
442
443static bool row_is_all_zeros(const uint8_t* row, int width) {
444 SkASSERT(width > 0);
445 do {
446 if (row[1]) {
447 return false;
448 }
449 int n = row[0];
450 SkASSERT(n <= width);
451 width -= n;
452 row += 2;
453 } while (width > 0);
454 SkASSERT(0 == width);
455 return true;
456}
457
458bool SkAAClip::trimTopBottom() {
459 if (this->isEmpty()) {
460 return false;
461 }
462
reed@google.comd6040f62011-10-28 02:39:17 +0000463 this->validate();
464
reed@google.comc9041912011-10-27 16:58:46 +0000465 const int width = fBounds.width();
466 RunHead* head = fRunHead;
467 YOffset* yoff = head->yoffsets();
468 YOffset* stop = yoff + head->fRowCount;
469 const uint8_t* base = head->data();
470
471 // Look to trim away empty rows from the top.
472 //
473 int skip = 0;
474 while (yoff < stop) {
475 const uint8_t* data = base + yoff->fOffset;
476 if (!row_is_all_zeros(data, width)) {
477 break;
478 }
479 skip += 1;
480 yoff += 1;
481 }
482 SkASSERT(skip <= head->fRowCount);
483 if (skip == head->fRowCount) {
484 return this->setEmpty();
485 }
486 if (skip > 0) {
487 // adjust fRowCount and fBounds.fTop, and slide all the data up
488 // as we remove [skip] number of YOffset entries
489 yoff = head->yoffsets();
490 int dy = yoff[skip - 1].fY + 1;
491 for (int i = skip; i < head->fRowCount; ++i) {
492 SkASSERT(yoff[i].fY >= dy);
493 yoff[i].fY -= dy;
494 }
495 YOffset* dst = head->yoffsets();
496 size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize;
497 memmove(dst, dst + skip, size - skip * sizeof(YOffset));
498
499 fBounds.fTop += dy;
500 SkASSERT(!fBounds.isEmpty());
501 head->fRowCount -= skip;
502 SkASSERT(head->fRowCount > 0);
reed@google.comd6040f62011-10-28 02:39:17 +0000503
504 this->validate();
505 // need to reset this after the memmove
506 base = head->data();
reed@google.comc9041912011-10-27 16:58:46 +0000507 }
508
509 // Look to trim away empty rows from the bottom.
510 // We know that we have at least one non-zero row, so we can just walk
511 // backwards without checking for running past the start.
512 //
513 stop = yoff = head->yoffsets() + head->fRowCount;
514 do {
515 yoff -= 1;
516 } while (row_is_all_zeros(base + yoff->fOffset, width));
517 skip = stop - yoff - 1;
518 SkASSERT(skip >= 0 && skip < head->fRowCount);
519 if (skip > 0) {
520 // removing from the bottom is easier than from the top, as we don't
521 // have to adjust any of the Y values, we just have to trim the array
522 memmove(stop - skip, stop, head->fDataSize);
523
524 fBounds.fBottom = fBounds.fTop + yoff->fY + 1;
525 SkASSERT(!fBounds.isEmpty());
526 head->fRowCount -= skip;
527 SkASSERT(head->fRowCount > 0);
528 }
reed@google.comd6040f62011-10-28 02:39:17 +0000529 this->validate();
reed@google.comc9041912011-10-27 16:58:46 +0000530
531 return true;
532}
533
reed@google.com045e62d2011-10-24 12:19:46 +0000534// can't validate before we're done, since trimming is part of the process of
535// making us valid after the Builder. Since we build from top to bottom, its
536// possible our fBounds.fBottom is bigger than our last scanline of data, so
537// we trim fBounds.fBottom back up.
538//
reed@google.com045e62d2011-10-24 12:19:46 +0000539// TODO: check for duplicates in X and Y to further compress our data
540//
541bool SkAAClip::trimBounds() {
542 if (this->isEmpty()) {
543 return false;
544 }
545
546 const RunHead* head = fRunHead;
547 const YOffset* yoff = head->yoffsets();
548
549 SkASSERT(head->fRowCount > 0);
550 const YOffset& lastY = yoff[head->fRowCount - 1];
551 SkASSERT(lastY.fY + 1 <= fBounds.height());
552 fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
553 SkASSERT(lastY.fY + 1 == fBounds.height());
reed@google.comc9041912011-10-27 16:58:46 +0000554 SkASSERT(!fBounds.isEmpty());
555
556 return this->trimTopBottom() && this->trimLeftRight();
reed@google.com045e62d2011-10-24 12:19:46 +0000557}
558
reed@google.come36707a2011-10-04 21:38:55 +0000559///////////////////////////////////////////////////////////////////////////////
560
561void SkAAClip::freeRuns() {
reed@google.com47ac84e2011-10-06 13:11:25 +0000562 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000563 SkASSERT(fRunHead->fRefCnt >= 1);
564 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
565 sk_free(fRunHead);
566 }
567 }
568}
569
570SkAAClip::SkAAClip() {
571 fBounds.setEmpty();
reed@google.com47ac84e2011-10-06 13:11:25 +0000572 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000573}
574
575SkAAClip::SkAAClip(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000576 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
reed@google.com47ac84e2011-10-06 13:11:25 +0000577 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000578 *this = src;
579}
580
581SkAAClip::~SkAAClip() {
582 this->freeRuns();
583}
584
585SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000586 AUTO_AACLIP_VALIDATE(*this);
587 src.validate();
588
reed@google.come36707a2011-10-04 21:38:55 +0000589 if (this != &src) {
590 this->freeRuns();
591 fBounds = src.fBounds;
592 fRunHead = src.fRunHead;
reed@google.com47ac84e2011-10-06 13:11:25 +0000593 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000594 sk_atomic_inc(&fRunHead->fRefCnt);
595 }
596 }
597 return *this;
598}
599
600bool operator==(const SkAAClip& a, const SkAAClip& b) {
reed@google.com045e62d2011-10-24 12:19:46 +0000601 a.validate();
602 b.validate();
603
reed@google.come36707a2011-10-04 21:38:55 +0000604 if (&a == &b) {
605 return true;
606 }
607 if (a.fBounds != b.fBounds) {
608 return false;
609 }
610
611 const SkAAClip::RunHead* ah = a.fRunHead;
612 const SkAAClip::RunHead* bh = b.fRunHead;
613
614 // this catches empties and rects being equal
615 if (ah == bh) {
616 return true;
617 }
618
619 // now we insist that both are complex (but different ptrs)
reed@google.com47ac84e2011-10-06 13:11:25 +0000620 if (!a.fRunHead || !b.fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000621 return false;
622 }
623
624 return ah->fRowCount == bh->fRowCount &&
625 ah->fDataSize == bh->fDataSize &&
626 !memcmp(ah->data(), bh->data(), ah->fDataSize);
627}
628
629void SkAAClip::swap(SkAAClip& other) {
reed@google.com045e62d2011-10-24 12:19:46 +0000630 AUTO_AACLIP_VALIDATE(*this);
631 other.validate();
632
reed@google.come36707a2011-10-04 21:38:55 +0000633 SkTSwap(fBounds, other.fBounds);
634 SkTSwap(fRunHead, other.fRunHead);
635}
636
reed@google.com32287892011-10-05 16:27:44 +0000637bool SkAAClip::set(const SkAAClip& src) {
638 *this = src;
639 return !this->isEmpty();
640}
641
reed@google.come36707a2011-10-04 21:38:55 +0000642bool SkAAClip::setEmpty() {
643 this->freeRuns();
644 fBounds.setEmpty();
reed@google.com47ac84e2011-10-06 13:11:25 +0000645 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000646 return false;
647}
648
649bool SkAAClip::setRect(const SkIRect& bounds) {
650 if (bounds.isEmpty()) {
651 return this->setEmpty();
652 }
reed@google.com47ac84e2011-10-06 13:11:25 +0000653
reed@google.com045e62d2011-10-24 12:19:46 +0000654 AUTO_AACLIP_VALIDATE(*this);
reed@google.com47ac84e2011-10-06 13:11:25 +0000655
reed@google.com045e62d2011-10-24 12:19:46 +0000656#if 0
reed@google.com47ac84e2011-10-06 13:11:25 +0000657 SkRect r;
658 r.set(bounds);
659 SkPath path;
660 path.addRect(r);
661 return this->setPath(path);
reed@google.com045e62d2011-10-24 12:19:46 +0000662#else
663 this->freeRuns();
664 fBounds = bounds;
665 fRunHead = RunHead::AllocRect(bounds);
666 SkASSERT(!this->isEmpty());
667 return true;
668#endif
reed@google.come36707a2011-10-04 21:38:55 +0000669}
670
reed@google.comf3c1da12011-10-10 19:35:47 +0000671bool SkAAClip::setRect(const SkRect& r, bool doAA) {
reed@google.come36707a2011-10-04 21:38:55 +0000672 if (r.isEmpty()) {
673 return this->setEmpty();
674 }
675
reed@google.com045e62d2011-10-24 12:19:46 +0000676 AUTO_AACLIP_VALIDATE(*this);
677
678 // TODO: special case this
679
reed@google.come36707a2011-10-04 21:38:55 +0000680 SkPath path;
681 path.addRect(r);
reed@google.comf3c1da12011-10-10 19:35:47 +0000682 return this->setPath(path, NULL, doAA);
683}
684
reed@google.coma069c8f2011-11-28 19:54:56 +0000685static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) {
686 SkASSERT(count >= 0);
687 while (count > 0) {
688 int n = count;
689 if (n > 255) {
690 n = 255;
691 }
692 uint8_t* data = array.append(2);
693 data[0] = n;
694 data[1] = value;
695 count -= n;
696 }
697}
698
reed@google.comf3c1da12011-10-10 19:35:47 +0000699bool SkAAClip::setRegion(const SkRegion& rgn) {
700 if (rgn.isEmpty()) {
701 return this->setEmpty();
702 }
703 if (rgn.isRect()) {
704 return this->setRect(rgn.getBounds());
705 }
reed@google.coma069c8f2011-11-28 19:54:56 +0000706
707#if 0
reed@google.comf3c1da12011-10-10 19:35:47 +0000708 SkAAClip clip;
709 SkRegion::Iterator iter(rgn);
710 for (; !iter.done(); iter.next()) {
711 clip.op(iter.rect(), SkRegion::kUnion_Op);
712 }
713 this->swap(clip);
reed@google.com3771a032011-10-11 17:18:04 +0000714 return !this->isEmpty();
reed@google.coma069c8f2011-11-28 19:54:56 +0000715#else
716 const SkIRect& bounds = rgn.getBounds();
717 const int offsetX = bounds.fLeft;
718 const int offsetY = bounds.fTop;
719
720 SkTDArray<YOffset> yArray;
721 SkTDArray<uint8_t> xArray;
722
723 yArray.setReserve(SkMin32(bounds.height(), 1024));
724 xArray.setReserve(SkMin32(bounds.width() * 128, 64 * 1024));
725
726 SkRegion::Iterator iter(rgn);
727 int prevRight = 0;
728 int prevBot = 0;
729 YOffset* currY = NULL;
730
731 for (; !iter.done(); iter.next()) {
732 const SkIRect& r = iter.rect();
733 SkASSERT(bounds.contains(r));
734
735 int bot = r.fBottom - offsetY;
736 SkASSERT(bot >= prevBot);
737 if (bot > prevBot) {
738 if (currY) {
739 // flush current row
740 append_run(xArray, 0, bounds.width() - prevRight);
741 }
742 // did we introduce an empty-gap from the prev row?
743 int top = r.fTop - offsetY;
744 if (top > prevBot) {
745 currY = yArray.append();
746 currY->fY = top - 1;
747 currY->fOffset = xArray.count();
748 append_run(xArray, 0, bounds.width());
749 }
750 // create a new record for this Y value
751 currY = yArray.append();
752 currY->fY = bot - 1;
753 currY->fOffset = xArray.count();
754 prevRight = 0;
755 prevBot = bot;
756 }
757
758 int x = r.fLeft - offsetX;
759 append_run(xArray, 0, x - prevRight);
760
761 int w = r.fRight - r.fLeft;
762 append_run(xArray, 0xFF, w);
763 prevRight = x + w;
764 SkASSERT(prevRight <= bounds.width());
765 }
766 // flush last row
767 append_run(xArray, 0, bounds.width() - prevRight);
768
769 // now pack everything into a RunHead
770 RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes());
771 memcpy(head->yoffsets(), yArray.begin(), yArray.bytes());
772 memcpy(head->data(), xArray.begin(), xArray.bytes());
773
774 this->setEmpty();
775 fBounds = bounds;
776 fRunHead = head;
777 this->validate();
778 return true;
779#endif
reed@google.come36707a2011-10-04 21:38:55 +0000780}
781
782///////////////////////////////////////////////////////////////////////////////
783
784const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000785 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000786
787 if (!y_in_rect(y, fBounds)) {
788 return NULL;
789 }
790 y -= fBounds.y(); // our yoffs values are relative to the top
791
792 const YOffset* yoff = fRunHead->yoffsets();
793 while (yoff->fY < y) {
794 yoff += 1;
795 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
796 }
797
798 if (lastYForRow) {
reed@google.com045e62d2011-10-24 12:19:46 +0000799 *lastYForRow = fBounds.y() + yoff->fY;
reed@google.come36707a2011-10-04 21:38:55 +0000800 }
801 return fRunHead->data() + yoff->fOffset;
802}
803
804const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
805 SkASSERT(x_in_rect(x, fBounds));
806 x -= fBounds.x();
807
808 // first skip up to X
809 for (;;) {
810 int n = data[0];
811 if (x < n) {
812 *initialCount = n - x;
813 break;
814 }
815 data += 2;
816 x -= n;
817 }
818 return data;
819}
820
821bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
822 if (this->isEmpty()) {
823 return false;
824 }
825 if (!fBounds.contains(left, top, right, bottom)) {
826 return false;
827 }
reed@google.com32287892011-10-05 16:27:44 +0000828#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000829 if (this->isRect()) {
830 return true;
831 }
reed@google.com32287892011-10-05 16:27:44 +0000832#endif
reed@google.come36707a2011-10-04 21:38:55 +0000833
834 int lastY;
835 const uint8_t* row = this->findRow(top, &lastY);
836 if (lastY < bottom) {
837 return false;
838 }
839 // now just need to check in X
reed@google.com045e62d2011-10-24 12:19:46 +0000840 int count;
841 row = this->findX(row, left, &count);
842#if 0
843 return count >= (right - left) && 0xFF == row[1];
844#else
845 int rectWidth = right - left;
846 while (0xFF == row[1]) {
847 if (count >= rectWidth) {
848 return true;
849 }
850 rectWidth -= count;
851 row += 2;
852 count = row[0];
853 }
854 return false;
855#endif
reed@google.come36707a2011-10-04 21:38:55 +0000856}
857
858///////////////////////////////////////////////////////////////////////////////
859
860class SkAAClip::Builder {
861 SkIRect fBounds;
862 struct Row {
863 int fY;
864 int fWidth;
865 SkTDArray<uint8_t>* fData;
866 };
867 SkTDArray<Row> fRows;
868 Row* fCurrRow;
869 int fPrevY;
870 int fWidth;
reed@google.com209c4152011-10-26 15:03:48 +0000871 int fMinY;
reed@google.come36707a2011-10-04 21:38:55 +0000872
873public:
874 Builder(const SkIRect& bounds) : fBounds(bounds) {
875 fPrevY = -1;
876 fWidth = bounds.width();
877 fCurrRow = NULL;
reed@google.com209c4152011-10-26 15:03:48 +0000878 fMinY = bounds.fTop;
reed@google.come36707a2011-10-04 21:38:55 +0000879 }
880
881 ~Builder() {
882 Row* row = fRows.begin();
883 Row* stop = fRows.end();
884 while (row < stop) {
885 delete row->fData;
886 row += 1;
887 }
888 }
889
reed@google.com32287892011-10-05 16:27:44 +0000890 const SkIRect& getBounds() const { return fBounds; }
891
reed@google.come36707a2011-10-04 21:38:55 +0000892 void addRun(int x, int y, U8CPU alpha, int count) {
893 SkASSERT(count > 0);
894 SkASSERT(fBounds.contains(x, y));
895 SkASSERT(fBounds.contains(x + count - 1, y));
reed@google.com80cdb9a2012-02-16 18:56:17 +0000896
reed@google.come36707a2011-10-04 21:38:55 +0000897 x -= fBounds.left();
898 y -= fBounds.top();
reed@google.com80cdb9a2012-02-16 18:56:17 +0000899
reed@google.come36707a2011-10-04 21:38:55 +0000900 Row* row = fCurrRow;
901 if (y != fPrevY) {
902 SkASSERT(y > fPrevY);
903 fPrevY = y;
904 row = this->flushRow(true);
905 row->fY = y;
906 row->fWidth = 0;
907 SkASSERT(row->fData);
908 SkASSERT(0 == row->fData->count());
909 fCurrRow = row;
910 }
911
912 SkASSERT(row->fWidth <= x);
913 SkASSERT(row->fWidth < fBounds.width());
914
915 SkTDArray<uint8_t>& data = *row->fData;
916
917 int gap = x - row->fWidth;
918 if (gap) {
919 AppendRun(data, 0, gap);
920 row->fWidth += gap;
921 SkASSERT(row->fWidth < fBounds.width());
922 }
923
924 AppendRun(data, alpha, count);
925 row->fWidth += count;
926 SkASSERT(row->fWidth <= fBounds.width());
927 }
928
tomhudson@google.com49eac192011-12-27 13:59:20 +0000929 void addColumn(int x, int y, U8CPU alpha, int height) {
930 SkASSERT(fBounds.contains(x, y + height - 1));
931
932 this->addRun(x, y, alpha, 1);
933 this->flushRowH(fCurrRow);
934 y -= fBounds.fTop;
935 SkASSERT(y == fCurrRow->fY);
936 fCurrRow->fY = y + height - 1;
937 }
938
reed@google.com9154eb02011-10-31 16:07:28 +0000939 void addRectRun(int x, int y, int width, int height) {
940 SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
941 this->addRun(x, y, 0xFF, width);
942
reed@google.coma89c77b2011-12-01 21:47:26 +0000943 // we assum the rect must be all we'll see for these scanlines
reed@google.com9154eb02011-10-31 16:07:28 +0000944 // so we ensure our row goes all the way to our right
945 this->flushRowH(fCurrRow);
946
947 y -= fBounds.fTop;
948 SkASSERT(y == fCurrRow->fY);
949 fCurrRow->fY = y + height - 1;
950 }
951
tomhudson@google.com49eac192011-12-27 13:59:20 +0000952 void addAntiRectRun(int x, int y, int width, int height,
953 SkAlpha leftAlpha, SkAlpha rightAlpha) {
954 SkASSERT(fBounds.contains(x + width - 1 +
955 (leftAlpha > 0 ? 1 : 0) + (rightAlpha > 0 ? 1 : 0),
956 y + height - 1));
957 SkASSERT(width >= 0);
958
959 // Conceptually we're always adding 3 runs, but we should
960 // merge or omit them if possible.
961 if (leftAlpha == 0xFF) {
962 width++;
963 } else if (leftAlpha > 0) {
964 this->addRun(x++, y, leftAlpha, 1);
965 }
966 if (rightAlpha == 0xFF) {
967 width++;
968 }
969 if (width > 0) {
970 this->addRun(x, y, 0xFF, width);
971 }
972 if (rightAlpha > 0 && rightAlpha < 255) {
973 this->addRun(x + width, y, rightAlpha, 1);
974 }
975
976 // we assume the rect must be all we'll see for these scanlines
977 // so we ensure our row goes all the way to our right
978 this->flushRowH(fCurrRow);
979
980 y -= fBounds.fTop;
981 SkASSERT(y == fCurrRow->fY);
982 fCurrRow->fY = y + height - 1;
983 }
984
reed@google.com045e62d2011-10-24 12:19:46 +0000985 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +0000986 this->flushRow(false);
987
988 const Row* row = fRows.begin();
989 const Row* stop = fRows.end();
990
991 size_t dataSize = 0;
992 while (row < stop) {
993 dataSize += row->fData->count();
994 row += 1;
995 }
996
reed@google.com045e62d2011-10-24 12:19:46 +0000997 if (0 == dataSize) {
998 return target->setEmpty();
999 }
1000
reed@google.com209c4152011-10-26 15:03:48 +00001001 SkASSERT(fMinY >= fBounds.fTop);
1002 SkASSERT(fMinY < fBounds.fBottom);
1003 int adjustY = fMinY - fBounds.fTop;
1004 fBounds.fTop = fMinY;
1005
reed@google.come36707a2011-10-04 21:38:55 +00001006 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
1007 YOffset* yoffset = head->yoffsets();
1008 uint8_t* data = head->data();
1009 uint8_t* baseData = data;
1010
1011 row = fRows.begin();
reed@google.comc9041912011-10-27 16:58:46 +00001012 SkDEBUGCODE(int prevY = row->fY - 1;)
reed@google.come36707a2011-10-04 21:38:55 +00001013 while (row < stop) {
reed@google.comc9041912011-10-27 16:58:46 +00001014 SkASSERT(prevY < row->fY); // must be monotonic
1015 SkDEBUGCODE(prevY = row->fY);
1016
reed@google.com209c4152011-10-26 15:03:48 +00001017 yoffset->fY = row->fY - adjustY;
reed@google.come36707a2011-10-04 21:38:55 +00001018 yoffset->fOffset = data - baseData;
1019 yoffset += 1;
1020
1021 size_t n = row->fData->count();
1022 memcpy(data, row->fData->begin(), n);
reed@google.comc9041912011-10-27 16:58:46 +00001023#ifdef SK_DEBUG
tomhudson@google.comf74ad8c2011-11-09 22:15:08 +00001024 size_t bytesNeeded = compute_row_length(data, fBounds.width());
reed@google.comc9041912011-10-27 16:58:46 +00001025 SkASSERT(bytesNeeded == n);
1026#endif
reed@google.come36707a2011-10-04 21:38:55 +00001027 data += n;
1028
1029 row += 1;
1030 }
1031
reed@google.com045e62d2011-10-24 12:19:46 +00001032 target->freeRuns();
1033 target->fBounds = fBounds;
1034 target->fRunHead = head;
1035 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +00001036 }
1037
1038 void dump() {
1039 this->validate();
1040 int y;
1041 for (y = 0; y < fRows.count(); ++y) {
1042 const Row& row = fRows[y];
1043 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
1044 const SkTDArray<uint8_t>& data = *row.fData;
1045 int count = data.count();
1046 SkASSERT(!(count & 1));
1047 const uint8_t* ptr = data.begin();
1048 for (int x = 0; x < count; x += 2) {
1049 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
1050 ptr += 2;
1051 }
1052 SkDebugf("\n");
1053 }
reed@google.come36707a2011-10-04 21:38:55 +00001054 }
1055
1056 void validate() {
1057#ifdef SK_DEBUG
1058 int prevY = -1;
1059 for (int i = 0; i < fRows.count(); ++i) {
1060 const Row& row = fRows[i];
1061 SkASSERT(prevY < row.fY);
1062 SkASSERT(fWidth == row.fWidth);
1063 int count = row.fData->count();
1064 const uint8_t* ptr = row.fData->begin();
1065 SkASSERT(!(count & 1));
1066 int w = 0;
1067 for (int x = 0; x < count; x += 2) {
reed@google.comd6040f62011-10-28 02:39:17 +00001068 int n = ptr[0];
1069 SkASSERT(n > 0);
1070 w += n;
reed@google.come36707a2011-10-04 21:38:55 +00001071 SkASSERT(w <= fWidth);
1072 ptr += 2;
1073 }
1074 SkASSERT(w == fWidth);
1075 prevY = row.fY;
1076 }
1077#endif
1078 }
1079
reed@google.com209c4152011-10-26 15:03:48 +00001080 // only called by BuilderBlitter
1081 void setMinY(int y) {
1082 fMinY = y;
1083 }
1084
reed@google.come36707a2011-10-04 21:38:55 +00001085private:
reed@google.com9154eb02011-10-31 16:07:28 +00001086 void flushRowH(Row* row) {
1087 // flush current row if needed
1088 if (row->fWidth < fWidth) {
1089 AppendRun(*row->fData, 0, fWidth - row->fWidth);
1090 row->fWidth = fWidth;
1091 }
1092 }
reed@google.com209c4152011-10-26 15:03:48 +00001093
reed@google.come36707a2011-10-04 21:38:55 +00001094 Row* flushRow(bool readyForAnother) {
1095 Row* next = NULL;
1096 int count = fRows.count();
1097 if (count > 0) {
reed@google.com9154eb02011-10-31 16:07:28 +00001098 this->flushRowH(&fRows[count - 1]);
reed@google.come36707a2011-10-04 21:38:55 +00001099 }
1100 if (count > 1) {
1101 // are our last two runs the same?
1102 Row* prev = &fRows[count - 2];
1103 Row* curr = &fRows[count - 1];
1104 SkASSERT(prev->fWidth == fWidth);
1105 SkASSERT(curr->fWidth == fWidth);
1106 if (*prev->fData == *curr->fData) {
1107 prev->fY = curr->fY;
1108 if (readyForAnother) {
1109 curr->fData->rewind();
1110 next = curr;
1111 } else {
1112 delete curr->fData;
1113 fRows.removeShuffle(count - 1);
1114 }
1115 } else {
1116 if (readyForAnother) {
1117 next = fRows.append();
1118 next->fData = new SkTDArray<uint8_t>;
1119 }
1120 }
1121 } else {
1122 if (readyForAnother) {
1123 next = fRows.append();
1124 next->fData = new SkTDArray<uint8_t>;
1125 }
1126 }
1127 return next;
1128 }
1129
1130 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
1131 do {
1132 int n = count;
1133 if (n > 255) {
1134 n = 255;
1135 }
1136 uint8_t* ptr = data.append(2);
1137 ptr[0] = n;
1138 ptr[1] = alpha;
1139 count -= n;
1140 } while (count > 0);
1141 }
1142};
1143
1144class SkAAClip::BuilderBlitter : public SkBlitter {
reed@google.com80cdb9a2012-02-16 18:56:17 +00001145 int fLastY;
1146
1147 /*
1148 If we see a gap of 1 or more empty scanlines while building in Y-order,
1149 we inject an explicit empty scanline (alpha==0)
1150
1151 See AAClipTest.cpp : test_path_with_hole()
1152 */
1153 void checkForYGap(int y) {
1154 SkASSERT(y >= fLastY);
1155 if (fLastY > -SK_MaxS32) {
1156 int gap = y - fLastY;
1157 if (gap > 1) {
1158 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft);
1159 }
1160 }
1161 fLastY = y;
1162 }
1163
reed@google.come36707a2011-10-04 21:38:55 +00001164public:
reed@google.com80cdb9a2012-02-16 18:56:17 +00001165
reed@google.come36707a2011-10-04 21:38:55 +00001166 BuilderBlitter(Builder* builder) {
1167 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001168 fLeft = builder->getBounds().fLeft;
1169 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001170 fMinY = SK_MaxS32;
reed@google.com80cdb9a2012-02-16 18:56:17 +00001171 fLastY = -SK_MaxS32; // sentinel
reed@google.com209c4152011-10-26 15:03:48 +00001172 }
1173
1174 void finish() {
1175 if (fMinY < SK_MaxS32) {
1176 fBuilder->setMinY(fMinY);
1177 }
reed@google.come36707a2011-10-04 21:38:55 +00001178 }
1179
tomhudson@google.com49eac192011-12-27 13:59:20 +00001180 /**
1181 Must evaluate clips in scan-line order, so don't want to allow blitV(),
1182 but an AAClip can be clipped down to a single pixel wide, so we
1183 must support it (given AntiRect semantics: minimum width is 2).
1184 Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
1185 any failure cases that misses may have minor artifacts.
1186 */
1187 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
1188 this->recordMinY(y);
1189 fBuilder->addColumn(x, y, alpha, height);
reed@google.com9b0da232012-02-29 13:59:15 +00001190 fLastY = y + height - 1;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001191 }
reed@google.com045e62d2011-10-24 12:19:46 +00001192
reed@google.com562a2ac2011-10-31 14:14:18 +00001193 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
reed@google.com9154eb02011-10-31 16:07:28 +00001194 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001195 this->checkForYGap(y);
reed@google.com9154eb02011-10-31 16:07:28 +00001196 fBuilder->addRectRun(x, y, width, height);
reed@google.com302b8612012-02-16 19:30:13 +00001197 fLastY = y + height - 1;
reed@google.com562a2ac2011-10-31 14:14:18 +00001198 }
reed@google.com045e62d2011-10-24 12:19:46 +00001199
tomhudson@google.com49eac192011-12-27 13:59:20 +00001200 virtual void blitAntiRect(int x, int y, int width, int height,
1201 SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE {
1202 this->recordMinY(y);
reed@google.com302b8612012-02-16 19:30:13 +00001203 this->checkForYGap(y);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001204 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
reed@google.com302b8612012-02-16 19:30:13 +00001205 fLastY = y + height - 1;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001206 }
1207
reed@google.come36707a2011-10-04 21:38:55 +00001208 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
1209 { unexpected(); }
1210
1211 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +00001212 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +00001213 }
1214
1215 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001216 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001217 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001218 fBuilder->addRun(x, y, 0xFF, width);
1219 }
1220
1221 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
1222 const int16_t runs[]) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001223 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001224 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001225 for (;;) {
1226 int count = *runs;
1227 if (count <= 0) {
1228 return;
1229 }
reed@google.com17785642011-10-12 20:23:55 +00001230
1231 // The supersampler's buffer can be the width of the device, so
1232 // we may have to trim the run to our bounds. If so, we assert that
1233 // the extra spans are always alpha==0
1234 int localX = x;
1235 int localCount = count;
1236 if (x < fLeft) {
1237 SkASSERT(0 == *alpha);
1238 int gap = fLeft - x;
1239 SkASSERT(gap <= count);
1240 localX += gap;
1241 localCount -= gap;
1242 }
1243 int right = x + count;
1244 if (right > fRight) {
1245 SkASSERT(0 == *alpha);
1246 localCount -= right - fRight;
1247 SkASSERT(localCount >= 0);
1248 }
1249
1250 if (localCount) {
1251 fBuilder->addRun(localX, y, *alpha, localCount);
1252 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001253 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001254 runs += count;
1255 alpha += count;
1256 x += count;
1257 }
1258 }
1259
1260private:
1261 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001262 int fLeft; // cache of builder's bounds' left edge
1263 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001264 int fMinY;
1265
1266 /*
1267 * We track this, in case the scan converter skipped some number of
1268 * scanlines at the (relative to the bounds it was given). This allows
1269 * the builder, during its finish, to trip its bounds down to the "real"
1270 * top.
1271 */
1272 void recordMinY(int y) {
1273 if (y < fMinY) {
1274 fMinY = y;
1275 }
1276 }
reed@google.come36707a2011-10-04 21:38:55 +00001277
1278 void unexpected() {
1279 SkDebugf("---- did not expect to get called here");
1280 sk_throw();
1281 }
1282};
1283
reed@google.comf3c1da12011-10-10 19:35:47 +00001284bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001285 AUTO_AACLIP_VALIDATE(*this);
1286
reed@google.com32287892011-10-05 16:27:44 +00001287 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001288 return this->setEmpty();
1289 }
1290
1291 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001292 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001293
reed@google.com32287892011-10-05 16:27:44 +00001294 SkRegion tmpClip;
1295 if (NULL == clip) {
1296 tmpClip.setRect(ibounds);
1297 clip = &tmpClip;
1298 }
1299
reed@google.com045e62d2011-10-24 12:19:46 +00001300 if (path.isInverseFillType()) {
1301 ibounds = clip->getBounds();
1302 } else {
reed@google.com32287892011-10-05 16:27:44 +00001303 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001304 return this->setEmpty();
1305 }
reed@google.come36707a2011-10-04 21:38:55 +00001306 }
1307
1308 Builder builder(ibounds);
1309 BuilderBlitter blitter(&builder);
1310
reed@google.comf3c1da12011-10-10 19:35:47 +00001311 if (doAA) {
1312 SkScan::AntiFillPath(path, *clip, &blitter, true);
1313 } else {
1314 SkScan::FillPath(path, *clip, &blitter);
1315 }
reed@google.come36707a2011-10-04 21:38:55 +00001316
reed@google.com209c4152011-10-26 15:03:48 +00001317 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001318 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001319}
1320
1321///////////////////////////////////////////////////////////////////////////////
1322
reed@google.com32287892011-10-05 16:27:44 +00001323typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1324 const uint8_t* rowA, const SkIRect& rectA,
1325 const uint8_t* rowB, const SkIRect& rectB);
1326
1327static void sectRowProc(SkAAClip::Builder& builder, int bottom,
1328 const uint8_t* rowA, const SkIRect& rectA,
1329 const uint8_t* rowB, const SkIRect& rectB) {
1330
1331}
1332
1333typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1334
1335static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1336 // Multiply
1337 return SkMulDiv255Round(alphaA, alphaB);
1338}
1339
1340static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1341 // SrcOver
1342 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1343}
1344
1345static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1346 // SrcOut
1347 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1348}
1349
1350static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1351 // XOR
1352 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1353}
1354
1355static AlphaProc find_alpha_proc(SkRegion::Op op) {
1356 switch (op) {
1357 case SkRegion::kIntersect_Op:
1358 return sectAlphaProc;
1359 case SkRegion::kDifference_Op:
1360 return diffAlphaProc;
1361 case SkRegion::kUnion_Op:
1362 return unionAlphaProc;
1363 case SkRegion::kXOR_Op:
1364 return xorAlphaProc;
1365 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001366 SkDEBUGFAIL("unexpected region op");
reed@google.com32287892011-10-05 16:27:44 +00001367 return sectAlphaProc;
1368 }
1369}
1370
1371static const uint8_t gEmptyRow[] = {
1372 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1373 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1374 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1375 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1376 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1377 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1378 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1379 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1380};
1381
1382class RowIter {
1383public:
1384 RowIter(const uint8_t* row, const SkIRect& bounds) {
1385 fRow = row;
1386 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001387 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001388 if (row) {
1389 fRight = bounds.fLeft + row[0];
1390 SkASSERT(fRight <= fBoundsRight);
1391 fAlpha = row[1];
1392 fDone = false;
1393 } else {
1394 fDone = true;
1395 fRight = kMaxInt32;
1396 fAlpha = 0;
1397 }
reed@google.com32287892011-10-05 16:27:44 +00001398 }
1399
1400 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001401 int left() const { return fLeft; }
1402 int right() const { return fRight; }
1403 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001404 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001405 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001406 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001407 if (fRight == fBoundsRight) {
1408 fDone = true;
1409 fRight = kMaxInt32;
1410 fAlpha = 0;
1411 } else {
1412 fRow += 2;
1413 fRight += fRow[0];
1414 fAlpha = fRow[1];
1415 SkASSERT(fRight <= fBoundsRight);
1416 }
reed@google.com32287892011-10-05 16:27:44 +00001417 }
1418 }
1419
1420private:
1421 const uint8_t* fRow;
1422 int fLeft;
1423 int fRight;
1424 int fBoundsRight;
1425 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001426 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001427};
1428
reed@google.com1c04bf92011-10-10 12:57:12 +00001429static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1430 if (rite == riteA) {
1431 iter.next();
1432 leftA = iter.left();
1433 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001434 }
1435}
1436
reed@google.com1c04bf92011-10-10 12:57:12 +00001437static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1438 SkASSERT(min < max);
1439 SkASSERT(boundsMin < boundsMax);
1440 if (min >= boundsMax || max <= boundsMin) {
1441 return false;
1442 }
1443 if (min < boundsMin) {
1444 min = boundsMin;
1445 }
1446 if (max > boundsMax) {
1447 max = boundsMax;
1448 }
1449 return true;
1450}
1451
reed@google.com32287892011-10-05 16:27:44 +00001452static void operatorX(SkAAClip::Builder& builder, int lastY,
1453 RowIter& iterA, RowIter& iterB,
1454 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001455 int leftA = iterA.left();
1456 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001457 int leftB = iterB.left();
1458 int riteB = iterB.right();
1459
reed@google.com1c04bf92011-10-10 12:57:12 +00001460 int prevRite = bounds.fLeft;
1461
1462 do {
reed@google.com32287892011-10-05 16:27:44 +00001463 U8CPU alphaA = 0;
1464 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001465 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +00001466
1467 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001468 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001469 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001470 if (riteA <= leftB) {
1471 rite = riteA;
1472 } else {
1473 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001474 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001475 } else if (leftB < leftA) {
1476 left = leftB;
1477 alphaB = iterB.alpha();
1478 if (riteB <= leftA) {
1479 rite = riteB;
1480 } else {
1481 rite = leftB = leftA;
1482 }
1483 } else {
1484 left = leftA; // or leftB, since leftA == leftB
1485 rite = leftA = leftB = SkMin32(riteA, riteB);
1486 alphaA = iterA.alpha();
1487 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001488 }
1489
1490 if (left >= bounds.fRight) {
1491 break;
1492 }
reed@google.com34f7e472011-10-13 15:11:59 +00001493 if (rite > bounds.fRight) {
1494 rite = bounds.fRight;
1495 }
1496
reed@google.com32287892011-10-05 16:27:44 +00001497 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001498 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001499 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001500 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001501 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001502
1503 adjust_row(iterA, leftA, riteA, rite);
1504 adjust_row(iterB, leftB, riteB, rite);
1505 } while (!iterA.done() || !iterB.done());
1506
1507 if (prevRite < bounds.fRight) {
1508 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001509 }
1510}
1511
reed@google.com1c04bf92011-10-10 12:57:12 +00001512static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1513 if (bot == botA) {
1514 iter.next();
1515 topA = botA;
1516 SkASSERT(botA == iter.top());
1517 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001518 }
1519}
1520
1521static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1522 const SkAAClip& B, SkRegion::Op op) {
1523 AlphaProc proc = find_alpha_proc(op);
1524 const SkIRect& bounds = builder.getBounds();
1525
1526 SkAAClip::Iter iterA(A);
1527 SkAAClip::Iter iterB(B);
1528
1529 SkASSERT(!iterA.done());
1530 int topA = iterA.top();
1531 int botA = iterA.bottom();
1532 SkASSERT(!iterB.done());
1533 int topB = iterB.top();
1534 int botB = iterB.bottom();
1535
reed@google.com1c04bf92011-10-10 12:57:12 +00001536 do {
1537 const uint8_t* rowA = NULL;
1538 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001539 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001540
1541 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001542 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001543 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001544 if (botA <= topB) {
1545 bot = botA;
1546 } else {
1547 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001548 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001549
1550 } else if (topB < topA) {
1551 top = topB;
1552 rowB = iterB.data();
1553 if (botB <= topA) {
1554 bot = botB;
1555 } else {
1556 bot = topB = topA;
1557 }
1558 } else {
1559 top = topA; // or topB, since topA == topB
1560 bot = topA = topB = SkMin32(botA, botB);
1561 rowA = iterA.data();
1562 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001563 }
1564
1565 if (top >= bounds.fBottom) {
1566 break;
1567 }
reed@google.com34f7e472011-10-13 15:11:59 +00001568
1569 if (bot > bounds.fBottom) {
1570 bot = bounds.fBottom;
1571 }
1572 SkASSERT(top < bot);
1573
reed@google.com1c04bf92011-10-10 12:57:12 +00001574 if (!rowA && !rowB) {
1575 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1576 } else if (top >= bounds.fTop) {
1577 SkASSERT(bot <= bounds.fBottom);
1578 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1579 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001580 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001581 }
1582
reed@google.com1c04bf92011-10-10 12:57:12 +00001583 adjust_iter(iterA, topA, botA, bot);
1584 adjust_iter(iterB, topB, botB, bot);
1585 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001586}
1587
1588bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1589 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001590 AUTO_AACLIP_VALIDATE(*this);
1591
reed@google.com32287892011-10-05 16:27:44 +00001592 if (SkRegion::kReplace_Op == op) {
1593 return this->set(clipBOrig);
1594 }
1595
1596 const SkAAClip* clipA = &clipAOrig;
1597 const SkAAClip* clipB = &clipBOrig;
1598
1599 if (SkRegion::kReverseDifference_Op == op) {
1600 SkTSwap(clipA, clipB);
1601 op = SkRegion::kDifference_Op;
1602 }
1603
1604 bool a_empty = clipA->isEmpty();
1605 bool b_empty = clipB->isEmpty();
1606
1607 SkIRect bounds;
1608 switch (op) {
1609 case SkRegion::kDifference_Op:
1610 if (a_empty) {
1611 return this->setEmpty();
1612 }
1613 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1614 return this->set(*clipA);
1615 }
1616 bounds = clipA->fBounds;
1617 break;
1618
1619 case SkRegion::kIntersect_Op:
1620 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1621 clipB->fBounds)) {
1622 return this->setEmpty();
1623 }
1624 break;
1625
1626 case SkRegion::kUnion_Op:
1627 case SkRegion::kXOR_Op:
1628 if (a_empty) {
1629 return this->set(*clipB);
1630 }
1631 if (b_empty) {
1632 return this->set(*clipA);
1633 }
1634 bounds = clipA->fBounds;
1635 bounds.join(clipB->fBounds);
1636 break;
1637
1638 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001639 SkDEBUGFAIL("unknown region op");
reed@google.com32287892011-10-05 16:27:44 +00001640 return !this->isEmpty();
1641 }
1642
reed@google.com32287892011-10-05 16:27:44 +00001643 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1644 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1645
1646 Builder builder(bounds);
1647 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001648
1649 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001650}
1651
reed@google.com045e62d2011-10-24 12:19:46 +00001652/*
1653 * It can be expensive to build a local aaclip before applying the op, so
1654 * we first see if we can restrict the bounds of new rect to our current
1655 * bounds, or note that the new rect subsumes our current clip.
1656 */
1657
1658bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1659 SkIRect rStorage;
1660 const SkIRect* r = &rOrig;
1661
1662 switch (op) {
1663 case SkRegion::kIntersect_Op:
1664 if (!rStorage.intersect(rOrig, fBounds)) {
1665 // no overlap, so we're empty
1666 return this->setEmpty();
1667 }
1668 if (rStorage == fBounds) {
1669 // we were wholly inside the rect, no change
1670 return !this->isEmpty();
1671 }
1672 if (this->quickContains(rStorage)) {
1673 // the intersection is wholly inside us, we're a rect
1674 return this->setRect(rStorage);
1675 }
1676 r = &rStorage; // use the intersected bounds
1677 break;
1678 case SkRegion::kDifference_Op:
1679 break;
1680 case SkRegion::kUnion_Op:
1681 if (rOrig.contains(fBounds)) {
1682 return this->setRect(rOrig);
1683 }
1684 break;
1685 default:
1686 break;
1687 }
1688
reed@google.com47ac84e2011-10-06 13:11:25 +00001689 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001690 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001691 return this->op(*this, clip, op);
1692}
1693
reed@google.com045e62d2011-10-24 12:19:46 +00001694bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1695 SkRect rStorage, boundsStorage;
1696 const SkRect* r = &rOrig;
1697
1698 boundsStorage.set(fBounds);
1699 switch (op) {
1700 case SkRegion::kIntersect_Op:
1701 case SkRegion::kDifference_Op:
1702 if (!rStorage.intersect(rOrig, boundsStorage)) {
1703 return this->setEmpty();
1704 }
1705 r = &rStorage; // use the intersected bounds
1706 break;
1707 case SkRegion::kUnion_Op:
1708 if (rOrig.contains(boundsStorage)) {
1709 return this->setRect(rOrig);
1710 }
1711 break;
1712 default:
1713 break;
1714 }
1715
reed@google.com47ac84e2011-10-06 13:11:25 +00001716 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001717 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001718 return this->op(*this, clip, op);
1719}
1720
1721bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1722 return this->op(*this, clip, op);
1723}
1724
reed@google.come36707a2011-10-04 21:38:55 +00001725///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001726
1727bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1728 if (NULL == dst) {
1729 return !this->isEmpty();
1730 }
1731
1732 if (this->isEmpty()) {
1733 return dst->setEmpty();
1734 }
1735
1736 if (this != dst) {
1737 sk_atomic_inc(&fRunHead->fRefCnt);
tomhudson@google.com19224c32012-03-28 15:46:37 +00001738 dst->freeRuns();
reed@google.com045e62d2011-10-24 12:19:46 +00001739 dst->fRunHead = fRunHead;
1740 dst->fBounds = fBounds;
1741 }
1742 dst->fBounds.offset(dx, dy);
1743 return true;
1744}
1745
1746static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1747 const uint8_t* SK_RESTRICT row,
1748 int width) {
1749 while (width > 0) {
1750 int n = row[0];
1751 SkASSERT(width >= n);
1752 memset(mask, row[1], n);
1753 mask += n;
1754 row += 2;
1755 width -= n;
1756 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001757 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001758}
1759
1760void SkAAClip::copyToMask(SkMask* mask) const {
1761 mask->fFormat = SkMask::kA8_Format;
1762 if (this->isEmpty()) {
1763 mask->fBounds.setEmpty();
1764 mask->fImage = NULL;
1765 mask->fRowBytes = 0;
1766 return;
1767 }
1768
1769 mask->fBounds = fBounds;
1770 mask->fRowBytes = fBounds.width();
1771 size_t size = mask->computeImageSize();
1772 mask->fImage = SkMask::AllocImage(size);
1773
1774 Iter iter(*this);
1775 uint8_t* dst = mask->fImage;
1776 const int width = fBounds.width();
1777
1778 int y = fBounds.fTop;
1779 while (!iter.done()) {
1780 do {
1781 expand_row_to_mask(dst, iter.data(), width);
1782 dst += mask->fRowBytes;
1783 } while (++y < iter.bottom());
1784 iter.next();
1785 }
1786}
1787
1788///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001789///////////////////////////////////////////////////////////////////////////////
1790
1791static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1792 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1793 // we don't read our initial n from data, since the caller may have had to
1794 // clip it, hence the initialCount parameter.
1795 int n = initialCount;
1796 for (;;) {
1797 if (n > width) {
1798 n = width;
1799 }
1800 SkASSERT(n > 0);
1801 runs[0] = n;
1802 runs += n;
1803
1804 aa[0] = data[1];
1805 aa += n;
1806
1807 data += 2;
1808 width -= n;
1809 if (0 == width) {
1810 break;
1811 }
1812 // load the next count
1813 n = data[0];
1814 }
1815 runs[0] = 0; // sentinel
1816}
1817
1818SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001819 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001820}
1821
1822void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001823 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001824 // add 1 so we can store the terminating run count of 0
1825 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001826 // we use this either for fRuns + fAA, or a scaline of a mask
1827 // which may be as deep as 32bits
1828 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1829 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001830 fAA = (SkAlpha*)(fRuns + count);
1831 }
1832}
1833
1834void SkAAClipBlitter::blitH(int x, int y, int width) {
1835 SkASSERT(width > 0);
1836 SkASSERT(fAAClipBounds.contains(x, y));
1837 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1838
1839 int lastY;
1840 const uint8_t* row = fAAClip->findRow(y, &lastY);
1841 int initialCount;
1842 row = fAAClip->findX(row, x, &initialCount);
1843
1844 if (initialCount >= width) {
1845 SkAlpha alpha = row[1];
1846 if (0 == alpha) {
1847 return;
1848 }
1849 if (0xFF == alpha) {
1850 fBlitter->blitH(x, y, width);
1851 return;
1852 }
1853 }
1854
1855 this->ensureRunsAndAA();
1856 expandToRuns(row, initialCount, width, fRuns, fAA);
1857
1858 fBlitter->blitAntiH(x, y, fAA, fRuns);
1859}
1860
1861static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1862 const SkAlpha* SK_RESTRICT srcAA,
1863 const int16_t* SK_RESTRICT srcRuns,
1864 SkAlpha* SK_RESTRICT dstAA,
1865 int16_t* SK_RESTRICT dstRuns,
1866 int width) {
1867 SkDEBUGCODE(int accumulated = 0;)
1868 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001869 // do we need this check?
1870 if (0 == srcN) {
1871 return;
1872 }
1873
reed@google.come36707a2011-10-04 21:38:55 +00001874 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001875 SkASSERT(rowN > 0);
1876 SkASSERT(srcN > 0);
1877
1878 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1879 int minN = SkMin32(srcN, rowN);
1880 dstRuns[0] = minN;
1881 dstRuns += minN;
1882 dstAA[0] = newAlpha;
1883 dstAA += minN;
1884
1885 if (0 == (srcN -= minN)) {
1886 srcN = srcRuns[0]; // refresh
1887 srcRuns += srcN;
1888 srcAA += srcN;
1889 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001890 if (0 == srcN) {
1891 break;
1892 }
reed@google.come36707a2011-10-04 21:38:55 +00001893 }
1894 if (0 == (rowN -= minN)) {
1895 row += 2;
1896 rowN = row[0]; // reload
1897 }
1898
1899 SkDEBUGCODE(accumulated += minN;)
1900 SkASSERT(accumulated <= width);
1901 }
reed@google.com34f7e472011-10-13 15:11:59 +00001902 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001903}
1904
1905void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1906 const int16_t runs[]) {
1907 int lastY;
1908 const uint8_t* row = fAAClip->findRow(y, &lastY);
1909 int initialCount;
1910 row = fAAClip->findX(row, x, &initialCount);
1911
1912 this->ensureRunsAndAA();
1913
1914 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1915 fBlitter->blitAntiH(x, y, fAA, fRuns);
1916}
1917
1918void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1919 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1920 fBlitter->blitV(x, y, height, alpha);
1921 return;
1922 }
1923
reed@google.com045e62d2011-10-24 12:19:46 +00001924 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001925 int lastY;
1926 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001927 int dy = lastY - y + 1;
1928 if (dy > height) {
1929 dy = height;
1930 }
1931 height -= dy;
1932
reed@google.come36707a2011-10-04 21:38:55 +00001933 int initialCount;
1934 row = fAAClip->findX(row, x, &initialCount);
1935 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1936 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001937 fBlitter->blitV(x, y, dy, newAlpha);
1938 }
1939 SkASSERT(height >= 0);
1940 if (height <= 0) {
1941 break;
reed@google.come36707a2011-10-04 21:38:55 +00001942 }
1943 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001944 }
reed@google.come36707a2011-10-04 21:38:55 +00001945}
1946
1947void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1948 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1949 fBlitter->blitRect(x, y, width, height);
1950 return;
1951 }
1952
1953 while (--height >= 0) {
1954 this->blitH(x, y, width);
1955 y += 1;
1956 }
1957}
1958
reed@google.com045e62d2011-10-24 12:19:46 +00001959typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1960 int initialRowCount, void* dst);
1961
1962static void small_memcpy(void* dst, const void* src, size_t n) {
1963 memcpy(dst, src, n);
1964}
1965
1966static void small_bzero(void* dst, size_t n) {
1967 sk_bzero(dst, n);
1968}
1969
1970static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1971 return SkMulDiv255Round(value, alpha);
1972}
1973static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1974 unsigned r = SkGetPackedR16(value);
1975 unsigned g = SkGetPackedG16(value);
1976 unsigned b = SkGetPackedB16(value);
1977 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1978 SkMulDiv255Round(r, alpha),
1979 SkMulDiv255Round(r, alpha));
1980}
1981static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1982 unsigned a = SkGetPackedA32(value);
1983 unsigned r = SkGetPackedR32(value);
1984 unsigned g = SkGetPackedG32(value);
1985 unsigned b = SkGetPackedB32(value);
1986 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1987 SkMulDiv255Round(r, alpha),
1988 SkMulDiv255Round(g, alpha),
1989 SkMulDiv255Round(b, alpha));
1990}
1991
1992template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1993 const uint8_t* SK_RESTRICT row, int rowN,
1994 T* SK_RESTRICT dst) {
1995 SkDEBUGCODE(int accumulated = 0;)
1996 for (;;) {
1997 SkASSERT(rowN > 0);
1998 SkASSERT(srcN > 0);
1999
2000 int n = SkMin32(rowN, srcN);
2001 unsigned rowA = row[1];
2002 if (0xFF == rowA) {
2003 small_memcpy(dst, src, n * sizeof(T));
2004 } else if (0 == rowA) {
2005 small_bzero(dst, n * sizeof(T));
2006 } else {
2007 for (int i = 0; i < n; ++i) {
2008 dst[i] = mergeOne(src[i], rowA);
2009 }
2010 }
2011
2012 if (0 == (srcN -= n)) {
2013 break;
2014 }
2015
2016 src += n;
2017 dst += n;
2018
2019 SkASSERT(rowN == n);
2020 row += 2;
2021 rowN = row[0];
2022 }
2023}
2024
2025static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2026 switch (format) {
2027 case SkMask::kBW_Format:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002028 SkDEBUGFAIL("unsupported");
reed@google.com045e62d2011-10-24 12:19:46 +00002029 return NULL;
2030 case SkMask::kA8_Format:
2031 case SkMask::k3D_Format: {
2032 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
2033 return (MergeAAProc)proc8;
2034 }
2035 case SkMask::kLCD16_Format: {
2036 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
2037 return (MergeAAProc)proc16;
2038 }
2039 case SkMask::kLCD32_Format: {
2040 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
2041 return (MergeAAProc)proc32;
2042 }
2043 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002044 SkDEBUGFAIL("unsupported");
reed@google.com045e62d2011-10-24 12:19:46 +00002045 return NULL;
2046 }
2047}
2048
2049static U8CPU bit2byte(int bitInAByte) {
2050 SkASSERT(bitInAByte <= 0xFF);
2051 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2052 // some value >= 8 to get a full FF value
2053 return -bitInAByte >> 8;
2054}
2055
2056static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2057 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2058 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2059
2060 const int width = srcMask.fBounds.width();
2061 const int height = srcMask.fBounds.height();
2062
2063 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2064 const size_t srcRB = srcMask.fRowBytes;
2065 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2066 const size_t dstRB = dstMask->fRowBytes;
2067
2068 const int wholeBytes = width >> 3;
2069 const int leftOverBits = width & 7;
2070
2071 for (int y = 0; y < height; ++y) {
2072 uint8_t* SK_RESTRICT d = dst;
2073 for (int i = 0; i < wholeBytes; ++i) {
2074 int srcByte = src[i];
2075 d[0] = bit2byte(srcByte & (1 << 7));
2076 d[1] = bit2byte(srcByte & (1 << 6));
2077 d[2] = bit2byte(srcByte & (1 << 5));
2078 d[3] = bit2byte(srcByte & (1 << 4));
2079 d[4] = bit2byte(srcByte & (1 << 3));
2080 d[5] = bit2byte(srcByte & (1 << 2));
2081 d[6] = bit2byte(srcByte & (1 << 1));
2082 d[7] = bit2byte(srcByte & (1 << 0));
2083 d += 8;
2084 }
2085 if (leftOverBits) {
2086 int srcByte = src[wholeBytes];
2087 for (int x = 0; x < leftOverBits; ++x) {
2088 *d++ = bit2byte(srcByte & 0x80);
2089 srcByte <<= 1;
2090 }
2091 }
2092 src += srcRB;
2093 dst += dstRB;
2094 }
2095}
2096
2097void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2098 SkASSERT(fAAClip->getBounds().contains(clip));
2099
2100 if (fAAClip->quickContains(clip)) {
2101 fBlitter->blitMask(origMask, clip);
2102 return;
2103 }
2104
2105 const SkMask* mask = &origMask;
2106
2107 // if we're BW, we need to upscale to A8 (ugh)
2108 SkMask grayMask;
2109 grayMask.fImage = NULL;
2110 if (SkMask::kBW_Format == origMask.fFormat) {
2111 grayMask.fFormat = SkMask::kA8_Format;
2112 grayMask.fBounds = origMask.fBounds;
2113 grayMask.fRowBytes = origMask.fBounds.width();
2114 size_t size = grayMask.computeImageSize();
2115 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2116 SkAutoMalloc::kReuse_OnShrink);
2117
2118 upscaleBW2A8(&grayMask, origMask);
2119 mask = &grayMask;
2120 }
2121
2122 this->ensureRunsAndAA();
2123
2124 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2125 // data into a temp block to support it better (ugh)
2126
2127 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2128 const size_t srcRB = mask->fRowBytes;
2129 const int width = clip.width();
2130 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2131
2132 SkMask rowMask;
2133 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2134 rowMask.fBounds.fLeft = clip.fLeft;
2135 rowMask.fBounds.fRight = clip.fRight;
2136 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2137 rowMask.fImage = (uint8_t*)fScanlineScratch;
2138
2139 int y = clip.fTop;
2140 const int stopY = y + clip.height();
2141
2142 do {
2143 int localStopY;
2144 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2145 // findRow returns last Y, not stop, so we add 1
2146 localStopY = SkMin32(localStopY + 1, stopY);
2147
2148 int initialCount;
2149 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2150 do {
2151 mergeProc(src, width, row, initialCount, rowMask.fImage);
2152 rowMask.fBounds.fTop = y;
2153 rowMask.fBounds.fBottom = y + 1;
2154 fBlitter->blitMask(rowMask, rowMask.fBounds);
2155 src = (const void*)((const char*)src + srcRB);
2156 } while (++y < localStopY);
2157 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002158}
2159
2160const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
2161 return NULL;
2162}
2163