blob: 9a0223d23103bf4c962a3482be65e1d1c684d419 [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.com302b8612012-02-16 19:30:13 +00001196 fLastY = y + height - 1;
reed@google.com562a2ac2011-10-31 14:14:18 +00001197 }
reed@google.com045e62d2011-10-24 12:19:46 +00001198
tomhudson@google.com49eac192011-12-27 13:59:20 +00001199 virtual void blitAntiRect(int x, int y, int width, int height,
1200 SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE {
1201 this->recordMinY(y);
reed@google.com302b8612012-02-16 19:30:13 +00001202 this->checkForYGap(y);
tomhudson@google.com49eac192011-12-27 13:59:20 +00001203 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
reed@google.com302b8612012-02-16 19:30:13 +00001204 fLastY = y + height - 1;
tomhudson@google.com49eac192011-12-27 13:59:20 +00001205 }
1206
reed@google.come36707a2011-10-04 21:38:55 +00001207 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
1208 { unexpected(); }
1209
1210 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +00001211 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +00001212 }
1213
1214 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001215 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001216 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001217 fBuilder->addRun(x, y, 0xFF, width);
1218 }
1219
1220 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
1221 const int16_t runs[]) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001222 this->recordMinY(y);
reed@google.com80cdb9a2012-02-16 18:56:17 +00001223 this->checkForYGap(y);
reed@google.come36707a2011-10-04 21:38:55 +00001224 for (;;) {
1225 int count = *runs;
1226 if (count <= 0) {
1227 return;
1228 }
reed@google.com17785642011-10-12 20:23:55 +00001229
1230 // The supersampler's buffer can be the width of the device, so
1231 // we may have to trim the run to our bounds. If so, we assert that
1232 // the extra spans are always alpha==0
1233 int localX = x;
1234 int localCount = count;
1235 if (x < fLeft) {
1236 SkASSERT(0 == *alpha);
1237 int gap = fLeft - x;
1238 SkASSERT(gap <= count);
1239 localX += gap;
1240 localCount -= gap;
1241 }
1242 int right = x + count;
1243 if (right > fRight) {
1244 SkASSERT(0 == *alpha);
1245 localCount -= right - fRight;
1246 SkASSERT(localCount >= 0);
1247 }
1248
1249 if (localCount) {
1250 fBuilder->addRun(localX, y, *alpha, localCount);
1251 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001252 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001253 runs += count;
1254 alpha += count;
1255 x += count;
1256 }
1257 }
1258
1259private:
1260 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001261 int fLeft; // cache of builder's bounds' left edge
1262 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001263 int fMinY;
1264
1265 /*
1266 * We track this, in case the scan converter skipped some number of
1267 * scanlines at the (relative to the bounds it was given). This allows
1268 * the builder, during its finish, to trip its bounds down to the "real"
1269 * top.
1270 */
1271 void recordMinY(int y) {
1272 if (y < fMinY) {
1273 fMinY = y;
1274 }
1275 }
reed@google.come36707a2011-10-04 21:38:55 +00001276
1277 void unexpected() {
1278 SkDebugf("---- did not expect to get called here");
1279 sk_throw();
1280 }
1281};
1282
reed@google.comf3c1da12011-10-10 19:35:47 +00001283bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001284 AUTO_AACLIP_VALIDATE(*this);
1285
reed@google.com32287892011-10-05 16:27:44 +00001286 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001287 return this->setEmpty();
1288 }
1289
1290 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001291 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001292
reed@google.com32287892011-10-05 16:27:44 +00001293 SkRegion tmpClip;
1294 if (NULL == clip) {
1295 tmpClip.setRect(ibounds);
1296 clip = &tmpClip;
1297 }
1298
reed@google.com045e62d2011-10-24 12:19:46 +00001299 if (path.isInverseFillType()) {
1300 ibounds = clip->getBounds();
1301 } else {
reed@google.com32287892011-10-05 16:27:44 +00001302 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001303 return this->setEmpty();
1304 }
reed@google.come36707a2011-10-04 21:38:55 +00001305 }
1306
1307 Builder builder(ibounds);
1308 BuilderBlitter blitter(&builder);
1309
reed@google.comf3c1da12011-10-10 19:35:47 +00001310 if (doAA) {
1311 SkScan::AntiFillPath(path, *clip, &blitter, true);
1312 } else {
1313 SkScan::FillPath(path, *clip, &blitter);
1314 }
reed@google.come36707a2011-10-04 21:38:55 +00001315
reed@google.com209c4152011-10-26 15:03:48 +00001316 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001317 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001318}
1319
1320///////////////////////////////////////////////////////////////////////////////
1321
reed@google.com32287892011-10-05 16:27:44 +00001322typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1323 const uint8_t* rowA, const SkIRect& rectA,
1324 const uint8_t* rowB, const SkIRect& rectB);
1325
1326static void sectRowProc(SkAAClip::Builder& builder, int bottom,
1327 const uint8_t* rowA, const SkIRect& rectA,
1328 const uint8_t* rowB, const SkIRect& rectB) {
1329
1330}
1331
1332typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1333
1334static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1335 // Multiply
1336 return SkMulDiv255Round(alphaA, alphaB);
1337}
1338
1339static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1340 // SrcOver
1341 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1342}
1343
1344static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1345 // SrcOut
1346 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1347}
1348
1349static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1350 // XOR
1351 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1352}
1353
1354static AlphaProc find_alpha_proc(SkRegion::Op op) {
1355 switch (op) {
1356 case SkRegion::kIntersect_Op:
1357 return sectAlphaProc;
1358 case SkRegion::kDifference_Op:
1359 return diffAlphaProc;
1360 case SkRegion::kUnion_Op:
1361 return unionAlphaProc;
1362 case SkRegion::kXOR_Op:
1363 return xorAlphaProc;
1364 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001365 SkDEBUGFAIL("unexpected region op");
reed@google.com32287892011-10-05 16:27:44 +00001366 return sectAlphaProc;
1367 }
1368}
1369
1370static const uint8_t gEmptyRow[] = {
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 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};
1380
1381class RowIter {
1382public:
1383 RowIter(const uint8_t* row, const SkIRect& bounds) {
1384 fRow = row;
1385 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001386 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001387 if (row) {
1388 fRight = bounds.fLeft + row[0];
1389 SkASSERT(fRight <= fBoundsRight);
1390 fAlpha = row[1];
1391 fDone = false;
1392 } else {
1393 fDone = true;
1394 fRight = kMaxInt32;
1395 fAlpha = 0;
1396 }
reed@google.com32287892011-10-05 16:27:44 +00001397 }
1398
1399 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001400 int left() const { return fLeft; }
1401 int right() const { return fRight; }
1402 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001403 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001404 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001405 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001406 if (fRight == fBoundsRight) {
1407 fDone = true;
1408 fRight = kMaxInt32;
1409 fAlpha = 0;
1410 } else {
1411 fRow += 2;
1412 fRight += fRow[0];
1413 fAlpha = fRow[1];
1414 SkASSERT(fRight <= fBoundsRight);
1415 }
reed@google.com32287892011-10-05 16:27:44 +00001416 }
1417 }
1418
1419private:
1420 const uint8_t* fRow;
1421 int fLeft;
1422 int fRight;
1423 int fBoundsRight;
1424 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001425 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001426};
1427
reed@google.com1c04bf92011-10-10 12:57:12 +00001428static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1429 if (rite == riteA) {
1430 iter.next();
1431 leftA = iter.left();
1432 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001433 }
1434}
1435
reed@google.com1c04bf92011-10-10 12:57:12 +00001436static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1437 SkASSERT(min < max);
1438 SkASSERT(boundsMin < boundsMax);
1439 if (min >= boundsMax || max <= boundsMin) {
1440 return false;
1441 }
1442 if (min < boundsMin) {
1443 min = boundsMin;
1444 }
1445 if (max > boundsMax) {
1446 max = boundsMax;
1447 }
1448 return true;
1449}
1450
reed@google.com32287892011-10-05 16:27:44 +00001451static void operatorX(SkAAClip::Builder& builder, int lastY,
1452 RowIter& iterA, RowIter& iterB,
1453 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001454 int leftA = iterA.left();
1455 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001456 int leftB = iterB.left();
1457 int riteB = iterB.right();
1458
reed@google.com1c04bf92011-10-10 12:57:12 +00001459 int prevRite = bounds.fLeft;
1460
1461 do {
reed@google.com32287892011-10-05 16:27:44 +00001462 U8CPU alphaA = 0;
1463 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001464 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +00001465
1466 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001467 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001468 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001469 if (riteA <= leftB) {
1470 rite = riteA;
1471 } else {
1472 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001473 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001474 } else if (leftB < leftA) {
1475 left = leftB;
1476 alphaB = iterB.alpha();
1477 if (riteB <= leftA) {
1478 rite = riteB;
1479 } else {
1480 rite = leftB = leftA;
1481 }
1482 } else {
1483 left = leftA; // or leftB, since leftA == leftB
1484 rite = leftA = leftB = SkMin32(riteA, riteB);
1485 alphaA = iterA.alpha();
1486 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001487 }
1488
1489 if (left >= bounds.fRight) {
1490 break;
1491 }
reed@google.com34f7e472011-10-13 15:11:59 +00001492 if (rite > bounds.fRight) {
1493 rite = bounds.fRight;
1494 }
1495
reed@google.com32287892011-10-05 16:27:44 +00001496 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001497 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001498 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001499 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001500 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001501
1502 adjust_row(iterA, leftA, riteA, rite);
1503 adjust_row(iterB, leftB, riteB, rite);
1504 } while (!iterA.done() || !iterB.done());
1505
1506 if (prevRite < bounds.fRight) {
1507 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001508 }
1509}
1510
reed@google.com1c04bf92011-10-10 12:57:12 +00001511static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1512 if (bot == botA) {
1513 iter.next();
1514 topA = botA;
1515 SkASSERT(botA == iter.top());
1516 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001517 }
1518}
1519
1520static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1521 const SkAAClip& B, SkRegion::Op op) {
1522 AlphaProc proc = find_alpha_proc(op);
1523 const SkIRect& bounds = builder.getBounds();
1524
1525 SkAAClip::Iter iterA(A);
1526 SkAAClip::Iter iterB(B);
1527
1528 SkASSERT(!iterA.done());
1529 int topA = iterA.top();
1530 int botA = iterA.bottom();
1531 SkASSERT(!iterB.done());
1532 int topB = iterB.top();
1533 int botB = iterB.bottom();
1534
reed@google.com1c04bf92011-10-10 12:57:12 +00001535 do {
1536 const uint8_t* rowA = NULL;
1537 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001538 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001539
1540 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001541 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001542 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001543 if (botA <= topB) {
1544 bot = botA;
1545 } else {
1546 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001547 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001548
1549 } else if (topB < topA) {
1550 top = topB;
1551 rowB = iterB.data();
1552 if (botB <= topA) {
1553 bot = botB;
1554 } else {
1555 bot = topB = topA;
1556 }
1557 } else {
1558 top = topA; // or topB, since topA == topB
1559 bot = topA = topB = SkMin32(botA, botB);
1560 rowA = iterA.data();
1561 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001562 }
1563
1564 if (top >= bounds.fBottom) {
1565 break;
1566 }
reed@google.com34f7e472011-10-13 15:11:59 +00001567
1568 if (bot > bounds.fBottom) {
1569 bot = bounds.fBottom;
1570 }
1571 SkASSERT(top < bot);
1572
reed@google.com1c04bf92011-10-10 12:57:12 +00001573 if (!rowA && !rowB) {
1574 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1575 } else if (top >= bounds.fTop) {
1576 SkASSERT(bot <= bounds.fBottom);
1577 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1578 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001579 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001580 }
1581
reed@google.com1c04bf92011-10-10 12:57:12 +00001582 adjust_iter(iterA, topA, botA, bot);
1583 adjust_iter(iterB, topB, botB, bot);
1584 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001585}
1586
1587bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1588 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001589 AUTO_AACLIP_VALIDATE(*this);
1590
reed@google.com32287892011-10-05 16:27:44 +00001591 if (SkRegion::kReplace_Op == op) {
1592 return this->set(clipBOrig);
1593 }
1594
1595 const SkAAClip* clipA = &clipAOrig;
1596 const SkAAClip* clipB = &clipBOrig;
1597
1598 if (SkRegion::kReverseDifference_Op == op) {
1599 SkTSwap(clipA, clipB);
1600 op = SkRegion::kDifference_Op;
1601 }
1602
1603 bool a_empty = clipA->isEmpty();
1604 bool b_empty = clipB->isEmpty();
1605
1606 SkIRect bounds;
1607 switch (op) {
1608 case SkRegion::kDifference_Op:
1609 if (a_empty) {
1610 return this->setEmpty();
1611 }
1612 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1613 return this->set(*clipA);
1614 }
1615 bounds = clipA->fBounds;
1616 break;
1617
1618 case SkRegion::kIntersect_Op:
1619 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1620 clipB->fBounds)) {
1621 return this->setEmpty();
1622 }
1623 break;
1624
1625 case SkRegion::kUnion_Op:
1626 case SkRegion::kXOR_Op:
1627 if (a_empty) {
1628 return this->set(*clipB);
1629 }
1630 if (b_empty) {
1631 return this->set(*clipA);
1632 }
1633 bounds = clipA->fBounds;
1634 bounds.join(clipB->fBounds);
1635 break;
1636
1637 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001638 SkDEBUGFAIL("unknown region op");
reed@google.com32287892011-10-05 16:27:44 +00001639 return !this->isEmpty();
1640 }
1641
reed@google.com32287892011-10-05 16:27:44 +00001642 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1643 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1644
1645 Builder builder(bounds);
1646 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001647
1648 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001649}
1650
reed@google.com045e62d2011-10-24 12:19:46 +00001651/*
1652 * It can be expensive to build a local aaclip before applying the op, so
1653 * we first see if we can restrict the bounds of new rect to our current
1654 * bounds, or note that the new rect subsumes our current clip.
1655 */
1656
1657bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1658 SkIRect rStorage;
1659 const SkIRect* r = &rOrig;
1660
1661 switch (op) {
1662 case SkRegion::kIntersect_Op:
1663 if (!rStorage.intersect(rOrig, fBounds)) {
1664 // no overlap, so we're empty
1665 return this->setEmpty();
1666 }
1667 if (rStorage == fBounds) {
1668 // we were wholly inside the rect, no change
1669 return !this->isEmpty();
1670 }
1671 if (this->quickContains(rStorage)) {
1672 // the intersection is wholly inside us, we're a rect
1673 return this->setRect(rStorage);
1674 }
1675 r = &rStorage; // use the intersected bounds
1676 break;
1677 case SkRegion::kDifference_Op:
1678 break;
1679 case SkRegion::kUnion_Op:
1680 if (rOrig.contains(fBounds)) {
1681 return this->setRect(rOrig);
1682 }
1683 break;
1684 default:
1685 break;
1686 }
1687
reed@google.com47ac84e2011-10-06 13:11:25 +00001688 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001689 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001690 return this->op(*this, clip, op);
1691}
1692
reed@google.com045e62d2011-10-24 12:19:46 +00001693bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1694 SkRect rStorage, boundsStorage;
1695 const SkRect* r = &rOrig;
1696
1697 boundsStorage.set(fBounds);
1698 switch (op) {
1699 case SkRegion::kIntersect_Op:
1700 case SkRegion::kDifference_Op:
1701 if (!rStorage.intersect(rOrig, boundsStorage)) {
1702 return this->setEmpty();
1703 }
1704 r = &rStorage; // use the intersected bounds
1705 break;
1706 case SkRegion::kUnion_Op:
1707 if (rOrig.contains(boundsStorage)) {
1708 return this->setRect(rOrig);
1709 }
1710 break;
1711 default:
1712 break;
1713 }
1714
reed@google.com47ac84e2011-10-06 13:11:25 +00001715 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001716 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001717 return this->op(*this, clip, op);
1718}
1719
1720bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1721 return this->op(*this, clip, op);
1722}
1723
reed@google.come36707a2011-10-04 21:38:55 +00001724///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001725
1726bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1727 if (NULL == dst) {
1728 return !this->isEmpty();
1729 }
1730
1731 if (this->isEmpty()) {
1732 return dst->setEmpty();
1733 }
1734
1735 if (this != dst) {
1736 sk_atomic_inc(&fRunHead->fRefCnt);
1737 dst->fRunHead = fRunHead;
1738 dst->fBounds = fBounds;
1739 }
1740 dst->fBounds.offset(dx, dy);
1741 return true;
1742}
1743
1744static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1745 const uint8_t* SK_RESTRICT row,
1746 int width) {
1747 while (width > 0) {
1748 int n = row[0];
1749 SkASSERT(width >= n);
1750 memset(mask, row[1], n);
1751 mask += n;
1752 row += 2;
1753 width -= n;
1754 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001755 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001756}
1757
1758void SkAAClip::copyToMask(SkMask* mask) const {
1759 mask->fFormat = SkMask::kA8_Format;
1760 if (this->isEmpty()) {
1761 mask->fBounds.setEmpty();
1762 mask->fImage = NULL;
1763 mask->fRowBytes = 0;
1764 return;
1765 }
1766
1767 mask->fBounds = fBounds;
1768 mask->fRowBytes = fBounds.width();
1769 size_t size = mask->computeImageSize();
1770 mask->fImage = SkMask::AllocImage(size);
1771
1772 Iter iter(*this);
1773 uint8_t* dst = mask->fImage;
1774 const int width = fBounds.width();
1775
1776 int y = fBounds.fTop;
1777 while (!iter.done()) {
1778 do {
1779 expand_row_to_mask(dst, iter.data(), width);
1780 dst += mask->fRowBytes;
1781 } while (++y < iter.bottom());
1782 iter.next();
1783 }
1784}
1785
1786///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001787///////////////////////////////////////////////////////////////////////////////
1788
1789static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1790 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1791 // we don't read our initial n from data, since the caller may have had to
1792 // clip it, hence the initialCount parameter.
1793 int n = initialCount;
1794 for (;;) {
1795 if (n > width) {
1796 n = width;
1797 }
1798 SkASSERT(n > 0);
1799 runs[0] = n;
1800 runs += n;
1801
1802 aa[0] = data[1];
1803 aa += n;
1804
1805 data += 2;
1806 width -= n;
1807 if (0 == width) {
1808 break;
1809 }
1810 // load the next count
1811 n = data[0];
1812 }
1813 runs[0] = 0; // sentinel
1814}
1815
1816SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001817 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001818}
1819
1820void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001821 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001822 // add 1 so we can store the terminating run count of 0
1823 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001824 // we use this either for fRuns + fAA, or a scaline of a mask
1825 // which may be as deep as 32bits
1826 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1827 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001828 fAA = (SkAlpha*)(fRuns + count);
1829 }
1830}
1831
1832void SkAAClipBlitter::blitH(int x, int y, int width) {
1833 SkASSERT(width > 0);
1834 SkASSERT(fAAClipBounds.contains(x, y));
1835 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1836
1837 int lastY;
1838 const uint8_t* row = fAAClip->findRow(y, &lastY);
1839 int initialCount;
1840 row = fAAClip->findX(row, x, &initialCount);
1841
1842 if (initialCount >= width) {
1843 SkAlpha alpha = row[1];
1844 if (0 == alpha) {
1845 return;
1846 }
1847 if (0xFF == alpha) {
1848 fBlitter->blitH(x, y, width);
1849 return;
1850 }
1851 }
1852
1853 this->ensureRunsAndAA();
1854 expandToRuns(row, initialCount, width, fRuns, fAA);
1855
1856 fBlitter->blitAntiH(x, y, fAA, fRuns);
1857}
1858
1859static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1860 const SkAlpha* SK_RESTRICT srcAA,
1861 const int16_t* SK_RESTRICT srcRuns,
1862 SkAlpha* SK_RESTRICT dstAA,
1863 int16_t* SK_RESTRICT dstRuns,
1864 int width) {
1865 SkDEBUGCODE(int accumulated = 0;)
1866 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001867 // do we need this check?
1868 if (0 == srcN) {
1869 return;
1870 }
1871
reed@google.come36707a2011-10-04 21:38:55 +00001872 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001873 SkASSERT(rowN > 0);
1874 SkASSERT(srcN > 0);
1875
1876 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1877 int minN = SkMin32(srcN, rowN);
1878 dstRuns[0] = minN;
1879 dstRuns += minN;
1880 dstAA[0] = newAlpha;
1881 dstAA += minN;
1882
1883 if (0 == (srcN -= minN)) {
1884 srcN = srcRuns[0]; // refresh
1885 srcRuns += srcN;
1886 srcAA += srcN;
1887 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001888 if (0 == srcN) {
1889 break;
1890 }
reed@google.come36707a2011-10-04 21:38:55 +00001891 }
1892 if (0 == (rowN -= minN)) {
1893 row += 2;
1894 rowN = row[0]; // reload
1895 }
1896
1897 SkDEBUGCODE(accumulated += minN;)
1898 SkASSERT(accumulated <= width);
1899 }
reed@google.com34f7e472011-10-13 15:11:59 +00001900 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001901}
1902
1903void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1904 const int16_t runs[]) {
1905 int lastY;
1906 const uint8_t* row = fAAClip->findRow(y, &lastY);
1907 int initialCount;
1908 row = fAAClip->findX(row, x, &initialCount);
1909
1910 this->ensureRunsAndAA();
1911
1912 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1913 fBlitter->blitAntiH(x, y, fAA, fRuns);
1914}
1915
1916void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1917 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1918 fBlitter->blitV(x, y, height, alpha);
1919 return;
1920 }
1921
reed@google.com045e62d2011-10-24 12:19:46 +00001922 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001923 int lastY;
1924 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001925 int dy = lastY - y + 1;
1926 if (dy > height) {
1927 dy = height;
1928 }
1929 height -= dy;
1930
reed@google.come36707a2011-10-04 21:38:55 +00001931 int initialCount;
1932 row = fAAClip->findX(row, x, &initialCount);
1933 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1934 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001935 fBlitter->blitV(x, y, dy, newAlpha);
1936 }
1937 SkASSERT(height >= 0);
1938 if (height <= 0) {
1939 break;
reed@google.come36707a2011-10-04 21:38:55 +00001940 }
1941 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001942 }
reed@google.come36707a2011-10-04 21:38:55 +00001943}
1944
1945void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1946 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1947 fBlitter->blitRect(x, y, width, height);
1948 return;
1949 }
1950
1951 while (--height >= 0) {
1952 this->blitH(x, y, width);
1953 y += 1;
1954 }
1955}
1956
reed@google.com045e62d2011-10-24 12:19:46 +00001957typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1958 int initialRowCount, void* dst);
1959
1960static void small_memcpy(void* dst, const void* src, size_t n) {
1961 memcpy(dst, src, n);
1962}
1963
1964static void small_bzero(void* dst, size_t n) {
1965 sk_bzero(dst, n);
1966}
1967
1968static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1969 return SkMulDiv255Round(value, alpha);
1970}
1971static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1972 unsigned r = SkGetPackedR16(value);
1973 unsigned g = SkGetPackedG16(value);
1974 unsigned b = SkGetPackedB16(value);
1975 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1976 SkMulDiv255Round(r, alpha),
1977 SkMulDiv255Round(r, alpha));
1978}
1979static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1980 unsigned a = SkGetPackedA32(value);
1981 unsigned r = SkGetPackedR32(value);
1982 unsigned g = SkGetPackedG32(value);
1983 unsigned b = SkGetPackedB32(value);
1984 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1985 SkMulDiv255Round(r, alpha),
1986 SkMulDiv255Round(g, alpha),
1987 SkMulDiv255Round(b, alpha));
1988}
1989
1990template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1991 const uint8_t* SK_RESTRICT row, int rowN,
1992 T* SK_RESTRICT dst) {
1993 SkDEBUGCODE(int accumulated = 0;)
1994 for (;;) {
1995 SkASSERT(rowN > 0);
1996 SkASSERT(srcN > 0);
1997
1998 int n = SkMin32(rowN, srcN);
1999 unsigned rowA = row[1];
2000 if (0xFF == rowA) {
2001 small_memcpy(dst, src, n * sizeof(T));
2002 } else if (0 == rowA) {
2003 small_bzero(dst, n * sizeof(T));
2004 } else {
2005 for (int i = 0; i < n; ++i) {
2006 dst[i] = mergeOne(src[i], rowA);
2007 }
2008 }
2009
2010 if (0 == (srcN -= n)) {
2011 break;
2012 }
2013
2014 src += n;
2015 dst += n;
2016
2017 SkASSERT(rowN == n);
2018 row += 2;
2019 rowN = row[0];
2020 }
2021}
2022
2023static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
2024 switch (format) {
2025 case SkMask::kBW_Format:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002026 SkDEBUGFAIL("unsupported");
reed@google.com045e62d2011-10-24 12:19:46 +00002027 return NULL;
2028 case SkMask::kA8_Format:
2029 case SkMask::k3D_Format: {
2030 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
2031 return (MergeAAProc)proc8;
2032 }
2033 case SkMask::kLCD16_Format: {
2034 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
2035 return (MergeAAProc)proc16;
2036 }
2037 case SkMask::kLCD32_Format: {
2038 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
2039 return (MergeAAProc)proc32;
2040 }
2041 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002042 SkDEBUGFAIL("unsupported");
reed@google.com045e62d2011-10-24 12:19:46 +00002043 return NULL;
2044 }
2045}
2046
2047static U8CPU bit2byte(int bitInAByte) {
2048 SkASSERT(bitInAByte <= 0xFF);
2049 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2050 // some value >= 8 to get a full FF value
2051 return -bitInAByte >> 8;
2052}
2053
2054static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2055 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2056 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2057
2058 const int width = srcMask.fBounds.width();
2059 const int height = srcMask.fBounds.height();
2060
2061 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2062 const size_t srcRB = srcMask.fRowBytes;
2063 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2064 const size_t dstRB = dstMask->fRowBytes;
2065
2066 const int wholeBytes = width >> 3;
2067 const int leftOverBits = width & 7;
2068
2069 for (int y = 0; y < height; ++y) {
2070 uint8_t* SK_RESTRICT d = dst;
2071 for (int i = 0; i < wholeBytes; ++i) {
2072 int srcByte = src[i];
2073 d[0] = bit2byte(srcByte & (1 << 7));
2074 d[1] = bit2byte(srcByte & (1 << 6));
2075 d[2] = bit2byte(srcByte & (1 << 5));
2076 d[3] = bit2byte(srcByte & (1 << 4));
2077 d[4] = bit2byte(srcByte & (1 << 3));
2078 d[5] = bit2byte(srcByte & (1 << 2));
2079 d[6] = bit2byte(srcByte & (1 << 1));
2080 d[7] = bit2byte(srcByte & (1 << 0));
2081 d += 8;
2082 }
2083 if (leftOverBits) {
2084 int srcByte = src[wholeBytes];
2085 for (int x = 0; x < leftOverBits; ++x) {
2086 *d++ = bit2byte(srcByte & 0x80);
2087 srcByte <<= 1;
2088 }
2089 }
2090 src += srcRB;
2091 dst += dstRB;
2092 }
2093}
2094
2095void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2096 SkASSERT(fAAClip->getBounds().contains(clip));
2097
2098 if (fAAClip->quickContains(clip)) {
2099 fBlitter->blitMask(origMask, clip);
2100 return;
2101 }
2102
2103 const SkMask* mask = &origMask;
2104
2105 // if we're BW, we need to upscale to A8 (ugh)
2106 SkMask grayMask;
2107 grayMask.fImage = NULL;
2108 if (SkMask::kBW_Format == origMask.fFormat) {
2109 grayMask.fFormat = SkMask::kA8_Format;
2110 grayMask.fBounds = origMask.fBounds;
2111 grayMask.fRowBytes = origMask.fBounds.width();
2112 size_t size = grayMask.computeImageSize();
2113 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2114 SkAutoMalloc::kReuse_OnShrink);
2115
2116 upscaleBW2A8(&grayMask, origMask);
2117 mask = &grayMask;
2118 }
2119
2120 this->ensureRunsAndAA();
2121
2122 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2123 // data into a temp block to support it better (ugh)
2124
2125 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2126 const size_t srcRB = mask->fRowBytes;
2127 const int width = clip.width();
2128 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2129
2130 SkMask rowMask;
2131 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2132 rowMask.fBounds.fLeft = clip.fLeft;
2133 rowMask.fBounds.fRight = clip.fRight;
2134 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2135 rowMask.fImage = (uint8_t*)fScanlineScratch;
2136
2137 int y = clip.fTop;
2138 const int stopY = y + clip.height();
2139
2140 do {
2141 int localStopY;
2142 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2143 // findRow returns last Y, not stop, so we add 1
2144 localStopY = SkMin32(localStopY + 1, stopY);
2145
2146 int initialCount;
2147 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2148 do {
2149 mergeProc(src, width, row, initialCount, rowMask.fImage);
2150 rowMask.fBounds.fTop = y;
2151 rowMask.fBounds.fBottom = y + 1;
2152 fBlitter->blitMask(rowMask, rowMask.fBounds);
2153 src = (const void*)((const char*)src + srcRB);
2154 } while (++y < localStopY);
2155 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002156}
2157
2158const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
2159 return NULL;
2160}
2161