blob: 5402bcf8324ef7a90db6d57d7b573132795f6737 [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);
1190 }
reed@google.com045e62d2011-10-24 12:19:46 +00001191
reed@google.com562a2ac2011-10-31 14:14:18 +00001192 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
reed@google.com9154eb02011-10-31 16:07:28 +00001193 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001194 this->checkForYGap(y);
reed@google.com9154eb02011-10-31 16:07:28 +00001195 fBuilder->addRectRun(x, y, width, height);
reed@google.com562a2ac2011-10-31 14:14:18 +00001196 }
reed@google.com045e62d2011-10-24 12:19:46 +00001197
tomhudson@google.com49eac192011-12-27 13:59:20 +00001198 virtual void blitAntiRect(int x, int y, int width, int height,
1199 SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE {
1200 this->recordMinY(y);
1201 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
1202 }
1203
reed@google.come36707a2011-10-04 21:38:55 +00001204 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
1205 { unexpected(); }
1206
1207 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +00001208 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +00001209 }
1210
1211 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001212 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001213 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001214 fBuilder->addRun(x, y, 0xFF, width);
1215 }
1216
1217 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
1218 const int16_t runs[]) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001219 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001220 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001221 for (;;) {
1222 int count = *runs;
1223 if (count <= 0) {
1224 return;
1225 }
reed@google.com17785642011-10-12 20:23:55 +00001226
1227 // The supersampler's buffer can be the width of the device, so
1228 // we may have to trim the run to our bounds. If so, we assert that
1229 // the extra spans are always alpha==0
1230 int localX = x;
1231 int localCount = count;
1232 if (x < fLeft) {
1233 SkASSERT(0 == *alpha);
1234 int gap = fLeft - x;
1235 SkASSERT(gap <= count);
1236 localX += gap;
1237 localCount -= gap;
1238 }
1239 int right = x + count;
1240 if (right > fRight) {
1241 SkASSERT(0 == *alpha);
1242 localCount -= right - fRight;
1243 SkASSERT(localCount >= 0);
1244 }
1245
1246 if (localCount) {
1247 fBuilder->addRun(localX, y, *alpha, localCount);
1248 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001249 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001250 runs += count;
1251 alpha += count;
1252 x += count;
1253 }
1254 }
1255
1256private:
1257 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001258 int fLeft; // cache of builder's bounds' left edge
1259 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001260 int fMinY;
1261
1262 /*
1263 * We track this, in case the scan converter skipped some number of
1264 * scanlines at the (relative to the bounds it was given). This allows
1265 * the builder, during its finish, to trip its bounds down to the "real"
1266 * top.
1267 */
1268 void recordMinY(int y) {
1269 if (y < fMinY) {
1270 fMinY = y;
1271 }
1272 }
reed@google.come36707a2011-10-04 21:38:55 +00001273
1274 void unexpected() {
1275 SkDebugf("---- did not expect to get called here");
1276 sk_throw();
1277 }
1278};
1279
reed@google.comf3c1da12011-10-10 19:35:47 +00001280bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001281 AUTO_AACLIP_VALIDATE(*this);
1282
reed@google.com32287892011-10-05 16:27:44 +00001283 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001284 return this->setEmpty();
1285 }
1286
1287 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001288 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001289
reed@google.com32287892011-10-05 16:27:44 +00001290 SkRegion tmpClip;
1291 if (NULL == clip) {
1292 tmpClip.setRect(ibounds);
1293 clip = &tmpClip;
1294 }
1295
reed@google.com045e62d2011-10-24 12:19:46 +00001296 if (path.isInverseFillType()) {
1297 ibounds = clip->getBounds();
1298 } else {
reed@google.com32287892011-10-05 16:27:44 +00001299 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001300 return this->setEmpty();
1301 }
reed@google.come36707a2011-10-04 21:38:55 +00001302 }
1303
1304 Builder builder(ibounds);
1305 BuilderBlitter blitter(&builder);
1306
reed@google.comf3c1da12011-10-10 19:35:47 +00001307 if (doAA) {
1308 SkScan::AntiFillPath(path, *clip, &blitter, true);
1309 } else {
1310 SkScan::FillPath(path, *clip, &blitter);
1311 }
reed@google.come36707a2011-10-04 21:38:55 +00001312
reed@google.com209c4152011-10-26 15:03:48 +00001313 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001314 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001315}
1316
1317///////////////////////////////////////////////////////////////////////////////
1318
reed@google.com32287892011-10-05 16:27:44 +00001319typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1320 const uint8_t* rowA, const SkIRect& rectA,
1321 const uint8_t* rowB, const SkIRect& rectB);
1322
1323static void sectRowProc(SkAAClip::Builder& builder, int bottom,
1324 const uint8_t* rowA, const SkIRect& rectA,
1325 const uint8_t* rowB, const SkIRect& rectB) {
1326
1327}
1328
1329typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1330
1331static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1332 // Multiply
1333 return SkMulDiv255Round(alphaA, alphaB);
1334}
1335
1336static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1337 // SrcOver
1338 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1339}
1340
1341static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1342 // SrcOut
1343 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1344}
1345
1346static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1347 // XOR
1348 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1349}
1350
1351static AlphaProc find_alpha_proc(SkRegion::Op op) {
1352 switch (op) {
1353 case SkRegion::kIntersect_Op:
1354 return sectAlphaProc;
1355 case SkRegion::kDifference_Op:
1356 return diffAlphaProc;
1357 case SkRegion::kUnion_Op:
1358 return unionAlphaProc;
1359 case SkRegion::kXOR_Op:
1360 return xorAlphaProc;
1361 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001362 SkDEBUGFAIL("unexpected region op");
reed@google.com32287892011-10-05 16:27:44 +00001363 return sectAlphaProc;
1364 }
1365}
1366
1367static const uint8_t gEmptyRow[] = {
1368 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1369 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1370 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1371 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
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};
1377
1378class RowIter {
1379public:
1380 RowIter(const uint8_t* row, const SkIRect& bounds) {
1381 fRow = row;
1382 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001383 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001384 if (row) {
1385 fRight = bounds.fLeft + row[0];
1386 SkASSERT(fRight <= fBoundsRight);
1387 fAlpha = row[1];
1388 fDone = false;
1389 } else {
1390 fDone = true;
1391 fRight = kMaxInt32;
1392 fAlpha = 0;
1393 }
reed@google.com32287892011-10-05 16:27:44 +00001394 }
1395
1396 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001397 int left() const { return fLeft; }
1398 int right() const { return fRight; }
1399 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001400 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001401 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001402 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001403 if (fRight == fBoundsRight) {
1404 fDone = true;
1405 fRight = kMaxInt32;
1406 fAlpha = 0;
1407 } else {
1408 fRow += 2;
1409 fRight += fRow[0];
1410 fAlpha = fRow[1];
1411 SkASSERT(fRight <= fBoundsRight);
1412 }
reed@google.com32287892011-10-05 16:27:44 +00001413 }
1414 }
1415
1416private:
1417 const uint8_t* fRow;
1418 int fLeft;
1419 int fRight;
1420 int fBoundsRight;
1421 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001422 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001423};
1424
reed@google.com1c04bf92011-10-10 12:57:12 +00001425static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1426 if (rite == riteA) {
1427 iter.next();
1428 leftA = iter.left();
1429 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001430 }
1431}
1432
reed@google.com1c04bf92011-10-10 12:57:12 +00001433static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1434 SkASSERT(min < max);
1435 SkASSERT(boundsMin < boundsMax);
1436 if (min >= boundsMax || max <= boundsMin) {
1437 return false;
1438 }
1439 if (min < boundsMin) {
1440 min = boundsMin;
1441 }
1442 if (max > boundsMax) {
1443 max = boundsMax;
1444 }
1445 return true;
1446}
1447
reed@google.com32287892011-10-05 16:27:44 +00001448static void operatorX(SkAAClip::Builder& builder, int lastY,
1449 RowIter& iterA, RowIter& iterB,
1450 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001451 int leftA = iterA.left();
1452 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001453 int leftB = iterB.left();
1454 int riteB = iterB.right();
1455
reed@google.com1c04bf92011-10-10 12:57:12 +00001456 int prevRite = bounds.fLeft;
1457
1458 do {
reed@google.com32287892011-10-05 16:27:44 +00001459 U8CPU alphaA = 0;
1460 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001461 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +00001462
1463 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001464 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001465 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001466 if (riteA <= leftB) {
1467 rite = riteA;
1468 } else {
1469 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001470 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001471 } else if (leftB < leftA) {
1472 left = leftB;
1473 alphaB = iterB.alpha();
1474 if (riteB <= leftA) {
1475 rite = riteB;
1476 } else {
1477 rite = leftB = leftA;
1478 }
1479 } else {
1480 left = leftA; // or leftB, since leftA == leftB
1481 rite = leftA = leftB = SkMin32(riteA, riteB);
1482 alphaA = iterA.alpha();
1483 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001484 }
1485
1486 if (left >= bounds.fRight) {
1487 break;
1488 }
reed@google.com34f7e472011-10-13 15:11:59 +00001489 if (rite > bounds.fRight) {
1490 rite = bounds.fRight;
1491 }
1492
reed@google.com32287892011-10-05 16:27:44 +00001493 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001494 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001495 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001496 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001497 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001498
1499 adjust_row(iterA, leftA, riteA, rite);
1500 adjust_row(iterB, leftB, riteB, rite);
1501 } while (!iterA.done() || !iterB.done());
1502
1503 if (prevRite < bounds.fRight) {
1504 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001505 }
1506}
1507
reed@google.com1c04bf92011-10-10 12:57:12 +00001508static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1509 if (bot == botA) {
1510 iter.next();
1511 topA = botA;
1512 SkASSERT(botA == iter.top());
1513 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001514 }
1515}
1516
1517static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1518 const SkAAClip& B, SkRegion::Op op) {
1519 AlphaProc proc = find_alpha_proc(op);
1520 const SkIRect& bounds = builder.getBounds();
1521
1522 SkAAClip::Iter iterA(A);
1523 SkAAClip::Iter iterB(B);
1524
1525 SkASSERT(!iterA.done());
1526 int topA = iterA.top();
1527 int botA = iterA.bottom();
1528 SkASSERT(!iterB.done());
1529 int topB = iterB.top();
1530 int botB = iterB.bottom();
1531
reed@google.com1c04bf92011-10-10 12:57:12 +00001532 do {
1533 const uint8_t* rowA = NULL;
1534 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001535 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001536
1537 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001538 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001539 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001540 if (botA <= topB) {
1541 bot = botA;
1542 } else {
1543 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001544 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001545
1546 } else if (topB < topA) {
1547 top = topB;
1548 rowB = iterB.data();
1549 if (botB <= topA) {
1550 bot = botB;
1551 } else {
1552 bot = topB = topA;
1553 }
1554 } else {
1555 top = topA; // or topB, since topA == topB
1556 bot = topA = topB = SkMin32(botA, botB);
1557 rowA = iterA.data();
1558 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001559 }
1560
1561 if (top >= bounds.fBottom) {
1562 break;
1563 }
reed@google.com34f7e472011-10-13 15:11:59 +00001564
1565 if (bot > bounds.fBottom) {
1566 bot = bounds.fBottom;
1567 }
1568 SkASSERT(top < bot);
1569
reed@google.com1c04bf92011-10-10 12:57:12 +00001570 if (!rowA && !rowB) {
1571 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1572 } else if (top >= bounds.fTop) {
1573 SkASSERT(bot <= bounds.fBottom);
1574 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1575 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001576 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001577 }
1578
reed@google.com1c04bf92011-10-10 12:57:12 +00001579 adjust_iter(iterA, topA, botA, bot);
1580 adjust_iter(iterB, topB, botB, bot);
1581 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001582}
1583
1584bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1585 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001586 AUTO_AACLIP_VALIDATE(*this);
1587
reed@google.com32287892011-10-05 16:27:44 +00001588 if (SkRegion::kReplace_Op == op) {
1589 return this->set(clipBOrig);
1590 }
1591
1592 const SkAAClip* clipA = &clipAOrig;
1593 const SkAAClip* clipB = &clipBOrig;
1594
1595 if (SkRegion::kReverseDifference_Op == op) {
1596 SkTSwap(clipA, clipB);
1597 op = SkRegion::kDifference_Op;
1598 }
1599
1600 bool a_empty = clipA->isEmpty();
1601 bool b_empty = clipB->isEmpty();
1602
1603 SkIRect bounds;
1604 switch (op) {
1605 case SkRegion::kDifference_Op:
1606 if (a_empty) {
1607 return this->setEmpty();
1608 }
1609 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1610 return this->set(*clipA);
1611 }
1612 bounds = clipA->fBounds;
1613 break;
1614
1615 case SkRegion::kIntersect_Op:
1616 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1617 clipB->fBounds)) {
1618 return this->setEmpty();
1619 }
1620 break;
1621
1622 case SkRegion::kUnion_Op:
1623 case SkRegion::kXOR_Op:
1624 if (a_empty) {
1625 return this->set(*clipB);
1626 }
1627 if (b_empty) {
1628 return this->set(*clipA);
1629 }
1630 bounds = clipA->fBounds;
1631 bounds.join(clipB->fBounds);
1632 break;
1633
1634 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001635 SkDEBUGFAIL("unknown region op");
reed@google.com32287892011-10-05 16:27:44 +00001636 return !this->isEmpty();
1637 }
1638
reed@google.com32287892011-10-05 16:27:44 +00001639 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1640 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1641
1642 Builder builder(bounds);
1643 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001644
1645 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001646}
1647
reed@google.com045e62d2011-10-24 12:19:46 +00001648/*
1649 * It can be expensive to build a local aaclip before applying the op, so
1650 * we first see if we can restrict the bounds of new rect to our current
1651 * bounds, or note that the new rect subsumes our current clip.
1652 */
1653
1654bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1655 SkIRect rStorage;
1656 const SkIRect* r = &rOrig;
1657
1658 switch (op) {
1659 case SkRegion::kIntersect_Op:
1660 if (!rStorage.intersect(rOrig, fBounds)) {
1661 // no overlap, so we're empty
1662 return this->setEmpty();
1663 }
1664 if (rStorage == fBounds) {
1665 // we were wholly inside the rect, no change
1666 return !this->isEmpty();
1667 }
1668 if (this->quickContains(rStorage)) {
1669 // the intersection is wholly inside us, we're a rect
1670 return this->setRect(rStorage);
1671 }
1672 r = &rStorage; // use the intersected bounds
1673 break;
1674 case SkRegion::kDifference_Op:
1675 break;
1676 case SkRegion::kUnion_Op:
1677 if (rOrig.contains(fBounds)) {
1678 return this->setRect(rOrig);
1679 }
1680 break;
1681 default:
1682 break;
1683 }
1684
reed@google.com47ac84e2011-10-06 13:11:25 +00001685 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001686 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001687 return this->op(*this, clip, op);
1688}
1689
reed@google.com045e62d2011-10-24 12:19:46 +00001690bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1691 SkRect rStorage, boundsStorage;
1692 const SkRect* r = &rOrig;
1693
1694 boundsStorage.set(fBounds);
1695 switch (op) {
1696 case SkRegion::kIntersect_Op:
1697 case SkRegion::kDifference_Op:
1698 if (!rStorage.intersect(rOrig, boundsStorage)) {
1699 return this->setEmpty();
1700 }
1701 r = &rStorage; // use the intersected bounds
1702 break;
1703 case SkRegion::kUnion_Op:
1704 if (rOrig.contains(boundsStorage)) {
1705 return this->setRect(rOrig);
1706 }
1707 break;
1708 default:
1709 break;
1710 }
1711
reed@google.com47ac84e2011-10-06 13:11:25 +00001712 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001713 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001714 return this->op(*this, clip, op);
1715}
1716
1717bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1718 return this->op(*this, clip, op);
1719}
1720
reed@google.come36707a2011-10-04 21:38:55 +00001721///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001722
1723bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1724 if (NULL == dst) {
1725 return !this->isEmpty();
1726 }
1727
1728 if (this->isEmpty()) {
1729 return dst->setEmpty();
1730 }
1731
1732 if (this != dst) {
1733 sk_atomic_inc(&fRunHead->fRefCnt);
1734 dst->fRunHead = fRunHead;
1735 dst->fBounds = fBounds;
1736 }
1737 dst->fBounds.offset(dx, dy);
1738 return true;
1739}
1740
1741static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1742 const uint8_t* SK_RESTRICT row,
1743 int width) {
1744 while (width > 0) {
1745 int n = row[0];
1746 SkASSERT(width >= n);
1747 memset(mask, row[1], n);
1748 mask += n;
1749 row += 2;
1750 width -= n;
1751 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001752 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001753}
1754
1755void SkAAClip::copyToMask(SkMask* mask) const {
1756 mask->fFormat = SkMask::kA8_Format;
1757 if (this->isEmpty()) {
1758 mask->fBounds.setEmpty();
1759 mask->fImage = NULL;
1760 mask->fRowBytes = 0;
1761 return;
1762 }
1763
1764 mask->fBounds = fBounds;
1765 mask->fRowBytes = fBounds.width();
1766 size_t size = mask->computeImageSize();
1767 mask->fImage = SkMask::AllocImage(size);
1768
1769 Iter iter(*this);
1770 uint8_t* dst = mask->fImage;
1771 const int width = fBounds.width();
1772
1773 int y = fBounds.fTop;
1774 while (!iter.done()) {
1775 do {
1776 expand_row_to_mask(dst, iter.data(), width);
1777 dst += mask->fRowBytes;
1778 } while (++y < iter.bottom());
1779 iter.next();
1780 }
1781}
1782
1783///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001784///////////////////////////////////////////////////////////////////////////////
1785
1786static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1787 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1788 // we don't read our initial n from data, since the caller may have had to
1789 // clip it, hence the initialCount parameter.
1790 int n = initialCount;
1791 for (;;) {
1792 if (n > width) {
1793 n = width;
1794 }
1795 SkASSERT(n > 0);
1796 runs[0] = n;
1797 runs += n;
1798
1799 aa[0] = data[1];
1800 aa += n;
1801
1802 data += 2;
1803 width -= n;
1804 if (0 == width) {
1805 break;
1806 }
1807 // load the next count
1808 n = data[0];
1809 }
1810 runs[0] = 0; // sentinel
1811}
1812
1813SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001814 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001815}
1816
1817void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001818 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001819 // add 1 so we can store the terminating run count of 0
1820 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001821 // we use this either for fRuns + fAA, or a scaline of a mask
1822 // which may be as deep as 32bits
1823 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1824 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001825 fAA = (SkAlpha*)(fRuns + count);
1826 }
1827}
1828
1829void SkAAClipBlitter::blitH(int x, int y, int width) {
1830 SkASSERT(width > 0);
1831 SkASSERT(fAAClipBounds.contains(x, y));
1832 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1833
1834 int lastY;
1835 const uint8_t* row = fAAClip->findRow(y, &lastY);
1836 int initialCount;
1837 row = fAAClip->findX(row, x, &initialCount);
1838
1839 if (initialCount >= width) {
1840 SkAlpha alpha = row[1];
1841 if (0 == alpha) {
1842 return;
1843 }
1844 if (0xFF == alpha) {
1845 fBlitter->blitH(x, y, width);
1846 return;
1847 }
1848 }
1849
1850 this->ensureRunsAndAA();
1851 expandToRuns(row, initialCount, width, fRuns, fAA);
1852
1853 fBlitter->blitAntiH(x, y, fAA, fRuns);
1854}
1855
1856static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1857 const SkAlpha* SK_RESTRICT srcAA,
1858 const int16_t* SK_RESTRICT srcRuns,
1859 SkAlpha* SK_RESTRICT dstAA,
1860 int16_t* SK_RESTRICT dstRuns,
1861 int width) {
1862 SkDEBUGCODE(int accumulated = 0;)
1863 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001864 // do we need this check?
1865 if (0 == srcN) {
1866 return;
1867 }
1868
reed@google.come36707a2011-10-04 21:38:55 +00001869 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001870 SkASSERT(rowN > 0);
1871 SkASSERT(srcN > 0);
1872
1873 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1874 int minN = SkMin32(srcN, rowN);
1875 dstRuns[0] = minN;
1876 dstRuns += minN;
1877 dstAA[0] = newAlpha;
1878 dstAA += minN;
1879
1880 if (0 == (srcN -= minN)) {
1881 srcN = srcRuns[0]; // refresh
1882 srcRuns += srcN;
1883 srcAA += srcN;
1884 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001885 if (0 == srcN) {
1886 break;
1887 }
reed@google.come36707a2011-10-04 21:38:55 +00001888 }
1889 if (0 == (rowN -= minN)) {
1890 row += 2;
1891 rowN = row[0]; // reload
1892 }
1893
1894 SkDEBUGCODE(accumulated += minN;)
1895 SkASSERT(accumulated <= width);
1896 }
reed@google.com34f7e472011-10-13 15:11:59 +00001897 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001898}
1899
1900void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1901 const int16_t runs[]) {
1902 int lastY;
1903 const uint8_t* row = fAAClip->findRow(y, &lastY);
1904 int initialCount;
1905 row = fAAClip->findX(row, x, &initialCount);
1906
1907 this->ensureRunsAndAA();
1908
1909 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1910 fBlitter->blitAntiH(x, y, fAA, fRuns);
1911}
1912
1913void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1914 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1915 fBlitter->blitV(x, y, height, alpha);
1916 return;
1917 }
1918
reed@google.com045e62d2011-10-24 12:19:46 +00001919 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001920 int lastY;
1921 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001922 int dy = lastY - y + 1;
1923 if (dy > height) {
1924 dy = height;
1925 }
1926 height -= dy;
1927
reed@google.come36707a2011-10-04 21:38:55 +00001928 int initialCount;
1929 row = fAAClip->findX(row, x, &initialCount);
1930 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1931 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001932 fBlitter->blitV(x, y, dy, newAlpha);
1933 }
1934 SkASSERT(height >= 0);
1935 if (height <= 0) {
1936 break;
reed@google.come36707a2011-10-04 21:38:55 +00001937 }
1938 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001939 }
reed@google.come36707a2011-10-04 21:38:55 +00001940}
1941
1942void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1943 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1944 fBlitter->blitRect(x, y, width, height);
1945 return;
1946 }
1947
1948 while (--height >= 0) {
1949 this->blitH(x, y, width);
1950 y += 1;
1951 }
1952}
1953
reed@google.com045e62d2011-10-24 12:19:46 +00001954typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1955 int initialRowCount, void* dst);
1956
1957static void small_memcpy(void* dst, const void* src, size_t n) {
1958 memcpy(dst, src, n);
1959}
1960
1961static void small_bzero(void* dst, size_t n) {
1962 sk_bzero(dst, n);
1963}
1964
1965static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1966 return SkMulDiv255Round(value, alpha);
1967}
1968static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1969 unsigned r = SkGetPackedR16(value);
1970 unsigned g = SkGetPackedG16(value);
1971 unsigned b = SkGetPackedB16(value);
1972 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1973 SkMulDiv255Round(r, alpha),
1974 SkMulDiv255Round(r, alpha));
1975}
1976static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1977 unsigned a = SkGetPackedA32(value);
1978 unsigned r = SkGetPackedR32(value);
1979 unsigned g = SkGetPackedG32(value);
1980 unsigned b = SkGetPackedB32(value);
1981 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1982 SkMulDiv255Round(r, alpha),
1983 SkMulDiv255Round(g, alpha),
1984 SkMulDiv255Round(b, alpha));
1985}
1986
1987template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1988 const uint8_t* SK_RESTRICT row, int rowN,
1989 T* SK_RESTRICT dst) {
1990 SkDEBUGCODE(int accumulated = 0;)
1991 for (;;) {
1992 SkASSERT(rowN > 0);
1993 SkASSERT(srcN > 0);
1994
1995 int n = SkMin32(rowN, srcN);
1996 unsigned rowA = row[1];
1997 if (0xFF == rowA) {
1998 small_memcpy(dst, src, n * sizeof(T));
1999 } else if (0 == rowA) {
2000 small_bzero(dst, n * sizeof(T));
2001 } else {
2002 for (int i = 0; i < n; ++i) {
2003 dst[i] = mergeOne(src[i], rowA);
2004 }
2005 }
2006
2007 if (0 == (srcN -= n)) {
2008 break;
2009 }
2010
2011 src += n;
2012 dst += n;
2013
2014 SkASSERT(rowN == n);
2015 row += 2;
2016 rowN = row[0];
2017 }
2018}
2019
2020static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2021 switch (format) {
2022 case SkMask::kBW_Format:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002023 SkDEBUGFAIL("unsupported");
reed@google.com045e62d2011-10-24 12:19:46 +00002024 return NULL;
2025 case SkMask::kA8_Format:
2026 case SkMask::k3D_Format: {
2027 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
2028 return (MergeAAProc)proc8;
2029 }
2030 case SkMask::kLCD16_Format: {
2031 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
2032 return (MergeAAProc)proc16;
2033 }
2034 case SkMask::kLCD32_Format: {
2035 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
2036 return (MergeAAProc)proc32;
2037 }
2038 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002039 SkDEBUGFAIL("unsupported");
reed@google.com045e62d2011-10-24 12:19:46 +00002040 return NULL;
2041 }
2042}
2043
2044static U8CPU bit2byte(int bitInAByte) {
2045 SkASSERT(bitInAByte <= 0xFF);
2046 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2047 // some value >= 8 to get a full FF value
2048 return -bitInAByte >> 8;
2049}
2050
2051static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2052 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2053 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2054
2055 const int width = srcMask.fBounds.width();
2056 const int height = srcMask.fBounds.height();
2057
2058 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2059 const size_t srcRB = srcMask.fRowBytes;
2060 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2061 const size_t dstRB = dstMask->fRowBytes;
2062
2063 const int wholeBytes = width >> 3;
2064 const int leftOverBits = width & 7;
2065
2066 for (int y = 0; y < height; ++y) {
2067 uint8_t* SK_RESTRICT d = dst;
2068 for (int i = 0; i < wholeBytes; ++i) {
2069 int srcByte = src[i];
2070 d[0] = bit2byte(srcByte & (1 << 7));
2071 d[1] = bit2byte(srcByte & (1 << 6));
2072 d[2] = bit2byte(srcByte & (1 << 5));
2073 d[3] = bit2byte(srcByte & (1 << 4));
2074 d[4] = bit2byte(srcByte & (1 << 3));
2075 d[5] = bit2byte(srcByte & (1 << 2));
2076 d[6] = bit2byte(srcByte & (1 << 1));
2077 d[7] = bit2byte(srcByte & (1 << 0));
2078 d += 8;
2079 }
2080 if (leftOverBits) {
2081 int srcByte = src[wholeBytes];
2082 for (int x = 0; x < leftOverBits; ++x) {
2083 *d++ = bit2byte(srcByte & 0x80);
2084 srcByte <<= 1;
2085 }
2086 }
2087 src += srcRB;
2088 dst += dstRB;
2089 }
2090}
2091
2092void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2093 SkASSERT(fAAClip->getBounds().contains(clip));
2094
2095 if (fAAClip->quickContains(clip)) {
2096 fBlitter->blitMask(origMask, clip);
2097 return;
2098 }
2099
2100 const SkMask* mask = &origMask;
2101
2102 // if we're BW, we need to upscale to A8 (ugh)
2103 SkMask grayMask;
2104 grayMask.fImage = NULL;
2105 if (SkMask::kBW_Format == origMask.fFormat) {
2106 grayMask.fFormat = SkMask::kA8_Format;
2107 grayMask.fBounds = origMask.fBounds;
2108 grayMask.fRowBytes = origMask.fBounds.width();
2109 size_t size = grayMask.computeImageSize();
2110 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2111 SkAutoMalloc::kReuse_OnShrink);
2112
2113 upscaleBW2A8(&grayMask, origMask);
2114 mask = &grayMask;
2115 }
2116
2117 this->ensureRunsAndAA();
2118
2119 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2120 // data into a temp block to support it better (ugh)
2121
2122 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2123 const size_t srcRB = mask->fRowBytes;
2124 const int width = clip.width();
2125 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2126
2127 SkMask rowMask;
2128 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2129 rowMask.fBounds.fLeft = clip.fLeft;
2130 rowMask.fBounds.fRight = clip.fRight;
2131 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2132 rowMask.fImage = (uint8_t*)fScanlineScratch;
2133
2134 int y = clip.fTop;
2135 const int stopY = y + clip.height();
2136
2137 do {
2138 int localStopY;
2139 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2140 // findRow returns last Y, not stop, so we add 1
2141 localStopY = SkMin32(localStopY + 1, stopY);
2142
2143 int initialCount;
2144 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2145 do {
2146 mergeProc(src, width, row, initialCount, rowMask.fImage);
2147 rowMask.fBounds.fTop = y;
2148 rowMask.fBounds.fBottom = y + 1;
2149 fBlitter->blitMask(rowMask, rowMask.fBounds);
2150 src = (const void*)((const char*)src + srcRB);
2151 } while (++y < localStopY);
2152 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002153}
2154
2155const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
2156 return NULL;
2157}
2158