blob: 39eadbf243695dcad77ec1ed5136dd68b95ec86c [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));
896
897 x -= fBounds.left();
898 y -= fBounds.top();
899
900 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 {
1145public:
1146 BuilderBlitter(Builder* builder) {
1147 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001148 fLeft = builder->getBounds().fLeft;
1149 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001150 fMinY = SK_MaxS32;
1151 }
1152
1153 void finish() {
1154 if (fMinY < SK_MaxS32) {
1155 fBuilder->setMinY(fMinY);
1156 }
reed@google.come36707a2011-10-04 21:38:55 +00001157 }
1158
tomhudson@google.com49eac192011-12-27 13:59:20 +00001159 /**
1160 Must evaluate clips in scan-line order, so don't want to allow blitV(),
1161 but an AAClip can be clipped down to a single pixel wide, so we
1162 must support it (given AntiRect semantics: minimum width is 2).
1163 Instead we'll rely on the runtime asserts to guarantee Y monotonicity;
1164 any failure cases that misses may have minor artifacts.
1165 */
1166 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
1167 this->recordMinY(y);
1168 fBuilder->addColumn(x, y, alpha, height);
1169 }
reed@google.com045e62d2011-10-24 12:19:46 +00001170
reed@google.com562a2ac2011-10-31 14:14:18 +00001171 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
reed@google.com9154eb02011-10-31 16:07:28 +00001172 this->recordMinY(y);
1173 fBuilder->addRectRun(x, y, width, height);
reed@google.com562a2ac2011-10-31 14:14:18 +00001174 }
reed@google.com045e62d2011-10-24 12:19:46 +00001175
tomhudson@google.com49eac192011-12-27 13:59:20 +00001176 virtual void blitAntiRect(int x, int y, int width, int height,
1177 SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE {
1178 this->recordMinY(y);
1179 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha);
1180 }
1181
reed@google.come36707a2011-10-04 21:38:55 +00001182 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
1183 { unexpected(); }
1184
1185 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +00001186 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +00001187 }
1188
1189 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001190 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +00001191 fBuilder->addRun(x, y, 0xFF, width);
1192 }
1193
1194 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
1195 const int16_t runs[]) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001196 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +00001197 for (;;) {
1198 int count = *runs;
1199 if (count <= 0) {
1200 return;
1201 }
reed@google.com17785642011-10-12 20:23:55 +00001202
1203 // The supersampler's buffer can be the width of the device, so
1204 // we may have to trim the run to our bounds. If so, we assert that
1205 // the extra spans are always alpha==0
1206 int localX = x;
1207 int localCount = count;
1208 if (x < fLeft) {
1209 SkASSERT(0 == *alpha);
1210 int gap = fLeft - x;
1211 SkASSERT(gap <= count);
1212 localX += gap;
1213 localCount -= gap;
1214 }
1215 int right = x + count;
1216 if (right > fRight) {
1217 SkASSERT(0 == *alpha);
1218 localCount -= right - fRight;
1219 SkASSERT(localCount >= 0);
1220 }
1221
1222 if (localCount) {
1223 fBuilder->addRun(localX, y, *alpha, localCount);
1224 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001225 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001226 runs += count;
1227 alpha += count;
1228 x += count;
1229 }
1230 }
1231
1232private:
1233 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001234 int fLeft; // cache of builder's bounds' left edge
1235 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001236 int fMinY;
1237
1238 /*
1239 * We track this, in case the scan converter skipped some number of
1240 * scanlines at the (relative to the bounds it was given). This allows
1241 * the builder, during its finish, to trip its bounds down to the "real"
1242 * top.
1243 */
1244 void recordMinY(int y) {
1245 if (y < fMinY) {
1246 fMinY = y;
1247 }
1248 }
reed@google.come36707a2011-10-04 21:38:55 +00001249
1250 void unexpected() {
1251 SkDebugf("---- did not expect to get called here");
1252 sk_throw();
1253 }
1254};
1255
reed@google.comf3c1da12011-10-10 19:35:47 +00001256bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001257 AUTO_AACLIP_VALIDATE(*this);
1258
reed@google.com32287892011-10-05 16:27:44 +00001259 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001260 return this->setEmpty();
1261 }
1262
1263 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001264 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001265
reed@google.com32287892011-10-05 16:27:44 +00001266 SkRegion tmpClip;
1267 if (NULL == clip) {
1268 tmpClip.setRect(ibounds);
1269 clip = &tmpClip;
1270 }
1271
reed@google.com045e62d2011-10-24 12:19:46 +00001272 if (path.isInverseFillType()) {
1273 ibounds = clip->getBounds();
1274 } else {
reed@google.com32287892011-10-05 16:27:44 +00001275 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001276 return this->setEmpty();
1277 }
reed@google.come36707a2011-10-04 21:38:55 +00001278 }
1279
1280 Builder builder(ibounds);
1281 BuilderBlitter blitter(&builder);
1282
reed@google.comf3c1da12011-10-10 19:35:47 +00001283 if (doAA) {
1284 SkScan::AntiFillPath(path, *clip, &blitter, true);
1285 } else {
1286 SkScan::FillPath(path, *clip, &blitter);
1287 }
reed@google.come36707a2011-10-04 21:38:55 +00001288
reed@google.com209c4152011-10-26 15:03:48 +00001289 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001290 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001291}
1292
1293///////////////////////////////////////////////////////////////////////////////
1294
reed@google.com32287892011-10-05 16:27:44 +00001295typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1296 const uint8_t* rowA, const SkIRect& rectA,
1297 const uint8_t* rowB, const SkIRect& rectB);
1298
1299static void sectRowProc(SkAAClip::Builder& builder, int bottom,
1300 const uint8_t* rowA, const SkIRect& rectA,
1301 const uint8_t* rowB, const SkIRect& rectB) {
1302
1303}
1304
1305typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1306
1307static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1308 // Multiply
1309 return SkMulDiv255Round(alphaA, alphaB);
1310}
1311
1312static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1313 // SrcOver
1314 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1315}
1316
1317static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1318 // SrcOut
1319 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1320}
1321
1322static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1323 // XOR
1324 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1325}
1326
1327static AlphaProc find_alpha_proc(SkRegion::Op op) {
1328 switch (op) {
1329 case SkRegion::kIntersect_Op:
1330 return sectAlphaProc;
1331 case SkRegion::kDifference_Op:
1332 return diffAlphaProc;
1333 case SkRegion::kUnion_Op:
1334 return unionAlphaProc;
1335 case SkRegion::kXOR_Op:
1336 return xorAlphaProc;
1337 default:
1338 SkASSERT(!"unexpected region op");
1339 return sectAlphaProc;
1340 }
1341}
1342
1343static const uint8_t gEmptyRow[] = {
1344 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1345 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1346 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1347 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1348 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1349 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1350 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1351 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1352};
1353
1354class RowIter {
1355public:
1356 RowIter(const uint8_t* row, const SkIRect& bounds) {
1357 fRow = row;
1358 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001359 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001360 if (row) {
1361 fRight = bounds.fLeft + row[0];
1362 SkASSERT(fRight <= fBoundsRight);
1363 fAlpha = row[1];
1364 fDone = false;
1365 } else {
1366 fDone = true;
1367 fRight = kMaxInt32;
1368 fAlpha = 0;
1369 }
reed@google.com32287892011-10-05 16:27:44 +00001370 }
1371
1372 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001373 int left() const { return fLeft; }
1374 int right() const { return fRight; }
1375 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001376 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001377 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001378 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001379 if (fRight == fBoundsRight) {
1380 fDone = true;
1381 fRight = kMaxInt32;
1382 fAlpha = 0;
1383 } else {
1384 fRow += 2;
1385 fRight += fRow[0];
1386 fAlpha = fRow[1];
1387 SkASSERT(fRight <= fBoundsRight);
1388 }
reed@google.com32287892011-10-05 16:27:44 +00001389 }
1390 }
1391
1392private:
1393 const uint8_t* fRow;
1394 int fLeft;
1395 int fRight;
1396 int fBoundsRight;
1397 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001398 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001399};
1400
reed@google.com1c04bf92011-10-10 12:57:12 +00001401static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1402 if (rite == riteA) {
1403 iter.next();
1404 leftA = iter.left();
1405 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001406 }
1407}
1408
reed@google.com1c04bf92011-10-10 12:57:12 +00001409static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1410 SkASSERT(min < max);
1411 SkASSERT(boundsMin < boundsMax);
1412 if (min >= boundsMax || max <= boundsMin) {
1413 return false;
1414 }
1415 if (min < boundsMin) {
1416 min = boundsMin;
1417 }
1418 if (max > boundsMax) {
1419 max = boundsMax;
1420 }
1421 return true;
1422}
1423
reed@google.com32287892011-10-05 16:27:44 +00001424static void operatorX(SkAAClip::Builder& builder, int lastY,
1425 RowIter& iterA, RowIter& iterB,
1426 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001427 int leftA = iterA.left();
1428 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001429 int leftB = iterB.left();
1430 int riteB = iterB.right();
1431
reed@google.com1c04bf92011-10-10 12:57:12 +00001432 int prevRite = bounds.fLeft;
1433
1434 do {
reed@google.com32287892011-10-05 16:27:44 +00001435 U8CPU alphaA = 0;
1436 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001437 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +00001438
1439 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001440 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001441 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001442 if (riteA <= leftB) {
1443 rite = riteA;
1444 } else {
1445 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001446 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001447 } else if (leftB < leftA) {
1448 left = leftB;
1449 alphaB = iterB.alpha();
1450 if (riteB <= leftA) {
1451 rite = riteB;
1452 } else {
1453 rite = leftB = leftA;
1454 }
1455 } else {
1456 left = leftA; // or leftB, since leftA == leftB
1457 rite = leftA = leftB = SkMin32(riteA, riteB);
1458 alphaA = iterA.alpha();
1459 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001460 }
1461
1462 if (left >= bounds.fRight) {
1463 break;
1464 }
reed@google.com34f7e472011-10-13 15:11:59 +00001465 if (rite > bounds.fRight) {
1466 rite = bounds.fRight;
1467 }
1468
reed@google.com32287892011-10-05 16:27:44 +00001469 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001470 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001471 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001472 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001473 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001474
1475 adjust_row(iterA, leftA, riteA, rite);
1476 adjust_row(iterB, leftB, riteB, rite);
1477 } while (!iterA.done() || !iterB.done());
1478
1479 if (prevRite < bounds.fRight) {
1480 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001481 }
1482}
1483
reed@google.com1c04bf92011-10-10 12:57:12 +00001484static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1485 if (bot == botA) {
1486 iter.next();
1487 topA = botA;
1488 SkASSERT(botA == iter.top());
1489 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001490 }
1491}
1492
1493static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1494 const SkAAClip& B, SkRegion::Op op) {
1495 AlphaProc proc = find_alpha_proc(op);
1496 const SkIRect& bounds = builder.getBounds();
1497
1498 SkAAClip::Iter iterA(A);
1499 SkAAClip::Iter iterB(B);
1500
1501 SkASSERT(!iterA.done());
1502 int topA = iterA.top();
1503 int botA = iterA.bottom();
1504 SkASSERT(!iterB.done());
1505 int topB = iterB.top();
1506 int botB = iterB.bottom();
1507
reed@google.com1c04bf92011-10-10 12:57:12 +00001508 do {
1509 const uint8_t* rowA = NULL;
1510 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001511 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001512
1513 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001514 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001515 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001516 if (botA <= topB) {
1517 bot = botA;
1518 } else {
1519 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001520 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001521
1522 } else if (topB < topA) {
1523 top = topB;
1524 rowB = iterB.data();
1525 if (botB <= topA) {
1526 bot = botB;
1527 } else {
1528 bot = topB = topA;
1529 }
1530 } else {
1531 top = topA; // or topB, since topA == topB
1532 bot = topA = topB = SkMin32(botA, botB);
1533 rowA = iterA.data();
1534 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001535 }
1536
1537 if (top >= bounds.fBottom) {
1538 break;
1539 }
reed@google.com34f7e472011-10-13 15:11:59 +00001540
1541 if (bot > bounds.fBottom) {
1542 bot = bounds.fBottom;
1543 }
1544 SkASSERT(top < bot);
1545
reed@google.com1c04bf92011-10-10 12:57:12 +00001546 if (!rowA && !rowB) {
1547 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1548 } else if (top >= bounds.fTop) {
1549 SkASSERT(bot <= bounds.fBottom);
1550 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1551 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001552 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001553 }
1554
reed@google.com1c04bf92011-10-10 12:57:12 +00001555 adjust_iter(iterA, topA, botA, bot);
1556 adjust_iter(iterB, topB, botB, bot);
1557 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001558}
1559
1560bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1561 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001562 AUTO_AACLIP_VALIDATE(*this);
1563
reed@google.com32287892011-10-05 16:27:44 +00001564 if (SkRegion::kReplace_Op == op) {
1565 return this->set(clipBOrig);
1566 }
1567
1568 const SkAAClip* clipA = &clipAOrig;
1569 const SkAAClip* clipB = &clipBOrig;
1570
1571 if (SkRegion::kReverseDifference_Op == op) {
1572 SkTSwap(clipA, clipB);
1573 op = SkRegion::kDifference_Op;
1574 }
1575
1576 bool a_empty = clipA->isEmpty();
1577 bool b_empty = clipB->isEmpty();
1578
1579 SkIRect bounds;
1580 switch (op) {
1581 case SkRegion::kDifference_Op:
1582 if (a_empty) {
1583 return this->setEmpty();
1584 }
1585 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1586 return this->set(*clipA);
1587 }
1588 bounds = clipA->fBounds;
1589 break;
1590
1591 case SkRegion::kIntersect_Op:
1592 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1593 clipB->fBounds)) {
1594 return this->setEmpty();
1595 }
1596 break;
1597
1598 case SkRegion::kUnion_Op:
1599 case SkRegion::kXOR_Op:
1600 if (a_empty) {
1601 return this->set(*clipB);
1602 }
1603 if (b_empty) {
1604 return this->set(*clipA);
1605 }
1606 bounds = clipA->fBounds;
1607 bounds.join(clipB->fBounds);
1608 break;
1609
1610 default:
1611 SkASSERT(!"unknown region op");
1612 return !this->isEmpty();
1613 }
1614
reed@google.com32287892011-10-05 16:27:44 +00001615 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1616 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1617
1618 Builder builder(bounds);
1619 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001620
1621 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001622}
1623
reed@google.com045e62d2011-10-24 12:19:46 +00001624/*
1625 * It can be expensive to build a local aaclip before applying the op, so
1626 * we first see if we can restrict the bounds of new rect to our current
1627 * bounds, or note that the new rect subsumes our current clip.
1628 */
1629
1630bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1631 SkIRect rStorage;
1632 const SkIRect* r = &rOrig;
1633
1634 switch (op) {
1635 case SkRegion::kIntersect_Op:
1636 if (!rStorage.intersect(rOrig, fBounds)) {
1637 // no overlap, so we're empty
1638 return this->setEmpty();
1639 }
1640 if (rStorage == fBounds) {
1641 // we were wholly inside the rect, no change
1642 return !this->isEmpty();
1643 }
1644 if (this->quickContains(rStorage)) {
1645 // the intersection is wholly inside us, we're a rect
1646 return this->setRect(rStorage);
1647 }
1648 r = &rStorage; // use the intersected bounds
1649 break;
1650 case SkRegion::kDifference_Op:
1651 break;
1652 case SkRegion::kUnion_Op:
1653 if (rOrig.contains(fBounds)) {
1654 return this->setRect(rOrig);
1655 }
1656 break;
1657 default:
1658 break;
1659 }
1660
reed@google.com47ac84e2011-10-06 13:11:25 +00001661 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001662 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001663 return this->op(*this, clip, op);
1664}
1665
reed@google.com045e62d2011-10-24 12:19:46 +00001666bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1667 SkRect rStorage, boundsStorage;
1668 const SkRect* r = &rOrig;
1669
1670 boundsStorage.set(fBounds);
1671 switch (op) {
1672 case SkRegion::kIntersect_Op:
1673 case SkRegion::kDifference_Op:
1674 if (!rStorage.intersect(rOrig, boundsStorage)) {
1675 return this->setEmpty();
1676 }
1677 r = &rStorage; // use the intersected bounds
1678 break;
1679 case SkRegion::kUnion_Op:
1680 if (rOrig.contains(boundsStorage)) {
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, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001690 return this->op(*this, clip, op);
1691}
1692
1693bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1694 return this->op(*this, clip, op);
1695}
1696
reed@google.come36707a2011-10-04 21:38:55 +00001697///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001698
1699bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1700 if (NULL == dst) {
1701 return !this->isEmpty();
1702 }
1703
1704 if (this->isEmpty()) {
1705 return dst->setEmpty();
1706 }
1707
1708 if (this != dst) {
1709 sk_atomic_inc(&fRunHead->fRefCnt);
1710 dst->fRunHead = fRunHead;
1711 dst->fBounds = fBounds;
1712 }
1713 dst->fBounds.offset(dx, dy);
1714 return true;
1715}
1716
1717static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1718 const uint8_t* SK_RESTRICT row,
1719 int width) {
1720 while (width > 0) {
1721 int n = row[0];
1722 SkASSERT(width >= n);
1723 memset(mask, row[1], n);
1724 mask += n;
1725 row += 2;
1726 width -= n;
1727 }
reed@google.coma069c8f2011-11-28 19:54:56 +00001728 SkASSERT(0 == width);
reed@google.com045e62d2011-10-24 12:19:46 +00001729}
1730
1731void SkAAClip::copyToMask(SkMask* mask) const {
1732 mask->fFormat = SkMask::kA8_Format;
1733 if (this->isEmpty()) {
1734 mask->fBounds.setEmpty();
1735 mask->fImage = NULL;
1736 mask->fRowBytes = 0;
1737 return;
1738 }
1739
1740 mask->fBounds = fBounds;
1741 mask->fRowBytes = fBounds.width();
1742 size_t size = mask->computeImageSize();
1743 mask->fImage = SkMask::AllocImage(size);
1744
1745 Iter iter(*this);
1746 uint8_t* dst = mask->fImage;
1747 const int width = fBounds.width();
1748
1749 int y = fBounds.fTop;
1750 while (!iter.done()) {
1751 do {
1752 expand_row_to_mask(dst, iter.data(), width);
1753 dst += mask->fRowBytes;
1754 } while (++y < iter.bottom());
1755 iter.next();
1756 }
1757}
1758
1759///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001760///////////////////////////////////////////////////////////////////////////////
1761
1762static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1763 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1764 // we don't read our initial n from data, since the caller may have had to
1765 // clip it, hence the initialCount parameter.
1766 int n = initialCount;
1767 for (;;) {
1768 if (n > width) {
1769 n = width;
1770 }
1771 SkASSERT(n > 0);
1772 runs[0] = n;
1773 runs += n;
1774
1775 aa[0] = data[1];
1776 aa += n;
1777
1778 data += 2;
1779 width -= n;
1780 if (0 == width) {
1781 break;
1782 }
1783 // load the next count
1784 n = data[0];
1785 }
1786 runs[0] = 0; // sentinel
1787}
1788
1789SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001790 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001791}
1792
1793void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001794 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001795 // add 1 so we can store the terminating run count of 0
1796 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001797 // we use this either for fRuns + fAA, or a scaline of a mask
1798 // which may be as deep as 32bits
1799 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1800 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001801 fAA = (SkAlpha*)(fRuns + count);
1802 }
1803}
1804
1805void SkAAClipBlitter::blitH(int x, int y, int width) {
1806 SkASSERT(width > 0);
1807 SkASSERT(fAAClipBounds.contains(x, y));
1808 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1809
1810 int lastY;
1811 const uint8_t* row = fAAClip->findRow(y, &lastY);
1812 int initialCount;
1813 row = fAAClip->findX(row, x, &initialCount);
1814
1815 if (initialCount >= width) {
1816 SkAlpha alpha = row[1];
1817 if (0 == alpha) {
1818 return;
1819 }
1820 if (0xFF == alpha) {
1821 fBlitter->blitH(x, y, width);
1822 return;
1823 }
1824 }
1825
1826 this->ensureRunsAndAA();
1827 expandToRuns(row, initialCount, width, fRuns, fAA);
1828
1829 fBlitter->blitAntiH(x, y, fAA, fRuns);
1830}
1831
1832static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1833 const SkAlpha* SK_RESTRICT srcAA,
1834 const int16_t* SK_RESTRICT srcRuns,
1835 SkAlpha* SK_RESTRICT dstAA,
1836 int16_t* SK_RESTRICT dstRuns,
1837 int width) {
1838 SkDEBUGCODE(int accumulated = 0;)
1839 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001840 // do we need this check?
1841 if (0 == srcN) {
1842 return;
1843 }
1844
reed@google.come36707a2011-10-04 21:38:55 +00001845 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001846 SkASSERT(rowN > 0);
1847 SkASSERT(srcN > 0);
1848
1849 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1850 int minN = SkMin32(srcN, rowN);
1851 dstRuns[0] = minN;
1852 dstRuns += minN;
1853 dstAA[0] = newAlpha;
1854 dstAA += minN;
1855
1856 if (0 == (srcN -= minN)) {
1857 srcN = srcRuns[0]; // refresh
1858 srcRuns += srcN;
1859 srcAA += srcN;
1860 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001861 if (0 == srcN) {
1862 break;
1863 }
reed@google.come36707a2011-10-04 21:38:55 +00001864 }
1865 if (0 == (rowN -= minN)) {
1866 row += 2;
1867 rowN = row[0]; // reload
1868 }
1869
1870 SkDEBUGCODE(accumulated += minN;)
1871 SkASSERT(accumulated <= width);
1872 }
reed@google.com34f7e472011-10-13 15:11:59 +00001873 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001874}
1875
1876void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1877 const int16_t runs[]) {
1878 int lastY;
1879 const uint8_t* row = fAAClip->findRow(y, &lastY);
1880 int initialCount;
1881 row = fAAClip->findX(row, x, &initialCount);
1882
1883 this->ensureRunsAndAA();
1884
1885 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1886 fBlitter->blitAntiH(x, y, fAA, fRuns);
1887}
1888
1889void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1890 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1891 fBlitter->blitV(x, y, height, alpha);
1892 return;
1893 }
1894
reed@google.com045e62d2011-10-24 12:19:46 +00001895 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001896 int lastY;
1897 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001898 int dy = lastY - y + 1;
1899 if (dy > height) {
1900 dy = height;
1901 }
1902 height -= dy;
1903
reed@google.come36707a2011-10-04 21:38:55 +00001904 int initialCount;
1905 row = fAAClip->findX(row, x, &initialCount);
1906 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1907 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001908 fBlitter->blitV(x, y, dy, newAlpha);
1909 }
1910 SkASSERT(height >= 0);
1911 if (height <= 0) {
1912 break;
reed@google.come36707a2011-10-04 21:38:55 +00001913 }
1914 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001915 }
reed@google.come36707a2011-10-04 21:38:55 +00001916}
1917
1918void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1919 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1920 fBlitter->blitRect(x, y, width, height);
1921 return;
1922 }
1923
1924 while (--height >= 0) {
1925 this->blitH(x, y, width);
1926 y += 1;
1927 }
1928}
1929
reed@google.com045e62d2011-10-24 12:19:46 +00001930typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1931 int initialRowCount, void* dst);
1932
1933static void small_memcpy(void* dst, const void* src, size_t n) {
1934 memcpy(dst, src, n);
1935}
1936
1937static void small_bzero(void* dst, size_t n) {
1938 sk_bzero(dst, n);
1939}
1940
1941static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1942 return SkMulDiv255Round(value, alpha);
1943}
1944static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1945 unsigned r = SkGetPackedR16(value);
1946 unsigned g = SkGetPackedG16(value);
1947 unsigned b = SkGetPackedB16(value);
1948 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1949 SkMulDiv255Round(r, alpha),
1950 SkMulDiv255Round(r, alpha));
1951}
1952static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1953 unsigned a = SkGetPackedA32(value);
1954 unsigned r = SkGetPackedR32(value);
1955 unsigned g = SkGetPackedG32(value);
1956 unsigned b = SkGetPackedB32(value);
1957 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1958 SkMulDiv255Round(r, alpha),
1959 SkMulDiv255Round(g, alpha),
1960 SkMulDiv255Round(b, alpha));
1961}
1962
1963template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1964 const uint8_t* SK_RESTRICT row, int rowN,
1965 T* SK_RESTRICT dst) {
1966 SkDEBUGCODE(int accumulated = 0;)
1967 for (;;) {
1968 SkASSERT(rowN > 0);
1969 SkASSERT(srcN > 0);
1970
1971 int n = SkMin32(rowN, srcN);
1972 unsigned rowA = row[1];
1973 if (0xFF == rowA) {
1974 small_memcpy(dst, src, n * sizeof(T));
1975 } else if (0 == rowA) {
1976 small_bzero(dst, n * sizeof(T));
1977 } else {
1978 for (int i = 0; i < n; ++i) {
1979 dst[i] = mergeOne(src[i], rowA);
1980 }
1981 }
1982
1983 if (0 == (srcN -= n)) {
1984 break;
1985 }
1986
1987 src += n;
1988 dst += n;
1989
1990 SkASSERT(rowN == n);
1991 row += 2;
1992 rowN = row[0];
1993 }
1994}
1995
1996static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
1997 switch (format) {
1998 case SkMask::kBW_Format:
1999 SkASSERT(!"unsupported");
2000 return NULL;
2001 case SkMask::kA8_Format:
2002 case SkMask::k3D_Format: {
2003 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
2004 return (MergeAAProc)proc8;
2005 }
2006 case SkMask::kLCD16_Format: {
2007 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
2008 return (MergeAAProc)proc16;
2009 }
2010 case SkMask::kLCD32_Format: {
2011 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
2012 return (MergeAAProc)proc32;
2013 }
2014 default:
2015 SkASSERT(!"unsupported");
2016 return NULL;
2017 }
2018}
2019
2020static U8CPU bit2byte(int bitInAByte) {
2021 SkASSERT(bitInAByte <= 0xFF);
2022 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
2023 // some value >= 8 to get a full FF value
2024 return -bitInAByte >> 8;
2025}
2026
2027static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
2028 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
2029 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
2030
2031 const int width = srcMask.fBounds.width();
2032 const int height = srcMask.fBounds.height();
2033
2034 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
2035 const size_t srcRB = srcMask.fRowBytes;
2036 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
2037 const size_t dstRB = dstMask->fRowBytes;
2038
2039 const int wholeBytes = width >> 3;
2040 const int leftOverBits = width & 7;
2041
2042 for (int y = 0; y < height; ++y) {
2043 uint8_t* SK_RESTRICT d = dst;
2044 for (int i = 0; i < wholeBytes; ++i) {
2045 int srcByte = src[i];
2046 d[0] = bit2byte(srcByte & (1 << 7));
2047 d[1] = bit2byte(srcByte & (1 << 6));
2048 d[2] = bit2byte(srcByte & (1 << 5));
2049 d[3] = bit2byte(srcByte & (1 << 4));
2050 d[4] = bit2byte(srcByte & (1 << 3));
2051 d[5] = bit2byte(srcByte & (1 << 2));
2052 d[6] = bit2byte(srcByte & (1 << 1));
2053 d[7] = bit2byte(srcByte & (1 << 0));
2054 d += 8;
2055 }
2056 if (leftOverBits) {
2057 int srcByte = src[wholeBytes];
2058 for (int x = 0; x < leftOverBits; ++x) {
2059 *d++ = bit2byte(srcByte & 0x80);
2060 srcByte <<= 1;
2061 }
2062 }
2063 src += srcRB;
2064 dst += dstRB;
2065 }
2066}
2067
2068void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
2069 SkASSERT(fAAClip->getBounds().contains(clip));
2070
2071 if (fAAClip->quickContains(clip)) {
2072 fBlitter->blitMask(origMask, clip);
2073 return;
2074 }
2075
2076 const SkMask* mask = &origMask;
2077
2078 // if we're BW, we need to upscale to A8 (ugh)
2079 SkMask grayMask;
2080 grayMask.fImage = NULL;
2081 if (SkMask::kBW_Format == origMask.fFormat) {
2082 grayMask.fFormat = SkMask::kA8_Format;
2083 grayMask.fBounds = origMask.fBounds;
2084 grayMask.fRowBytes = origMask.fBounds.width();
2085 size_t size = grayMask.computeImageSize();
2086 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
2087 SkAutoMalloc::kReuse_OnShrink);
2088
2089 upscaleBW2A8(&grayMask, origMask);
2090 mask = &grayMask;
2091 }
2092
2093 this->ensureRunsAndAA();
2094
2095 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
2096 // data into a temp block to support it better (ugh)
2097
2098 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
2099 const size_t srcRB = mask->fRowBytes;
2100 const int width = clip.width();
2101 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
2102
2103 SkMask rowMask;
2104 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
2105 rowMask.fBounds.fLeft = clip.fLeft;
2106 rowMask.fBounds.fRight = clip.fRight;
2107 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
2108 rowMask.fImage = (uint8_t*)fScanlineScratch;
2109
2110 int y = clip.fTop;
2111 const int stopY = y + clip.height();
2112
2113 do {
2114 int localStopY;
2115 const uint8_t* row = fAAClip->findRow(y, &localStopY);
2116 // findRow returns last Y, not stop, so we add 1
2117 localStopY = SkMin32(localStopY + 1, stopY);
2118
2119 int initialCount;
2120 row = fAAClip->findX(row, clip.fLeft, &initialCount);
2121 do {
2122 mergeProc(src, width, row, initialCount, rowMask.fImage);
2123 rowMask.fBounds.fTop = y;
2124 rowMask.fBounds.fBottom = y + 1;
2125 fBlitter->blitMask(rowMask, rowMask.fBounds);
2126 src = (const void*)((const char*)src + srcRB);
2127 } while (++y < localStopY);
2128 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00002129}
2130
2131const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
2132 return NULL;
2133}
2134