blob: 05742487b8c49dafd58437e39877982337e3a1bb [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());
reed@google.comc9041912011-10-27 16:58:46 +0000212 SkASSERT(yoff->fOffset + rowLength <= head->fDataSize);
213 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
685bool SkAAClip::setRegion(const SkRegion& rgn) {
686 if (rgn.isEmpty()) {
687 return this->setEmpty();
688 }
689 if (rgn.isRect()) {
690 return this->setRect(rgn.getBounds());
691 }
692
693 SkAAClip clip;
694 SkRegion::Iterator iter(rgn);
695 for (; !iter.done(); iter.next()) {
696 clip.op(iter.rect(), SkRegion::kUnion_Op);
697 }
698 this->swap(clip);
reed@google.com3771a032011-10-11 17:18:04 +0000699 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000700}
701
702///////////////////////////////////////////////////////////////////////////////
703
704const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000705 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000706
707 if (!y_in_rect(y, fBounds)) {
708 return NULL;
709 }
710 y -= fBounds.y(); // our yoffs values are relative to the top
711
712 const YOffset* yoff = fRunHead->yoffsets();
713 while (yoff->fY < y) {
714 yoff += 1;
715 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
716 }
717
718 if (lastYForRow) {
reed@google.com045e62d2011-10-24 12:19:46 +0000719 *lastYForRow = fBounds.y() + yoff->fY;
reed@google.come36707a2011-10-04 21:38:55 +0000720 }
721 return fRunHead->data() + yoff->fOffset;
722}
723
724const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
725 SkASSERT(x_in_rect(x, fBounds));
726 x -= fBounds.x();
727
728 // first skip up to X
729 for (;;) {
730 int n = data[0];
731 if (x < n) {
732 *initialCount = n - x;
733 break;
734 }
735 data += 2;
736 x -= n;
737 }
738 return data;
739}
740
741bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
742 if (this->isEmpty()) {
743 return false;
744 }
745 if (!fBounds.contains(left, top, right, bottom)) {
746 return false;
747 }
reed@google.com32287892011-10-05 16:27:44 +0000748#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000749 if (this->isRect()) {
750 return true;
751 }
reed@google.com32287892011-10-05 16:27:44 +0000752#endif
reed@google.come36707a2011-10-04 21:38:55 +0000753
754 int lastY;
755 const uint8_t* row = this->findRow(top, &lastY);
756 if (lastY < bottom) {
757 return false;
758 }
759 // now just need to check in X
reed@google.com045e62d2011-10-24 12:19:46 +0000760 int count;
761 row = this->findX(row, left, &count);
762#if 0
763 return count >= (right - left) && 0xFF == row[1];
764#else
765 int rectWidth = right - left;
766 while (0xFF == row[1]) {
767 if (count >= rectWidth) {
768 return true;
769 }
770 rectWidth -= count;
771 row += 2;
772 count = row[0];
773 }
774 return false;
775#endif
reed@google.come36707a2011-10-04 21:38:55 +0000776}
777
778///////////////////////////////////////////////////////////////////////////////
779
780class SkAAClip::Builder {
781 SkIRect fBounds;
782 struct Row {
783 int fY;
784 int fWidth;
785 SkTDArray<uint8_t>* fData;
786 };
787 SkTDArray<Row> fRows;
788 Row* fCurrRow;
789 int fPrevY;
790 int fWidth;
reed@google.com209c4152011-10-26 15:03:48 +0000791 int fMinY;
reed@google.come36707a2011-10-04 21:38:55 +0000792
793public:
794 Builder(const SkIRect& bounds) : fBounds(bounds) {
795 fPrevY = -1;
796 fWidth = bounds.width();
797 fCurrRow = NULL;
reed@google.com209c4152011-10-26 15:03:48 +0000798 fMinY = bounds.fTop;
reed@google.come36707a2011-10-04 21:38:55 +0000799 }
800
801 ~Builder() {
802 Row* row = fRows.begin();
803 Row* stop = fRows.end();
804 while (row < stop) {
805 delete row->fData;
806 row += 1;
807 }
808 }
809
reed@google.com32287892011-10-05 16:27:44 +0000810 const SkIRect& getBounds() const { return fBounds; }
811
reed@google.come36707a2011-10-04 21:38:55 +0000812 void addRun(int x, int y, U8CPU alpha, int count) {
813 SkASSERT(count > 0);
814 SkASSERT(fBounds.contains(x, y));
815 SkASSERT(fBounds.contains(x + count - 1, y));
816
817 x -= fBounds.left();
818 y -= fBounds.top();
819
820 Row* row = fCurrRow;
821 if (y != fPrevY) {
822 SkASSERT(y > fPrevY);
823 fPrevY = y;
824 row = this->flushRow(true);
825 row->fY = y;
826 row->fWidth = 0;
827 SkASSERT(row->fData);
828 SkASSERT(0 == row->fData->count());
829 fCurrRow = row;
830 }
831
832 SkASSERT(row->fWidth <= x);
833 SkASSERT(row->fWidth < fBounds.width());
834
835 SkTDArray<uint8_t>& data = *row->fData;
836
837 int gap = x - row->fWidth;
838 if (gap) {
839 AppendRun(data, 0, gap);
840 row->fWidth += gap;
841 SkASSERT(row->fWidth < fBounds.width());
842 }
843
844 AppendRun(data, alpha, count);
845 row->fWidth += count;
846 SkASSERT(row->fWidth <= fBounds.width());
847 }
848
reed@google.com9154eb02011-10-31 16:07:28 +0000849 void addRectRun(int x, int y, int width, int height) {
850 SkASSERT(fBounds.contains(x + width - 1, y + height - 1));
851 this->addRun(x, y, 0xFF, width);
852
853 // we assum the rect must be all we'll see for these scanlines
854 // so we ensure our row goes all the way to our right
855 this->flushRowH(fCurrRow);
856
857 y -= fBounds.fTop;
858 SkASSERT(y == fCurrRow->fY);
859 fCurrRow->fY = y + height - 1;
860 }
861
reed@google.com045e62d2011-10-24 12:19:46 +0000862 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +0000863 this->flushRow(false);
864
865 const Row* row = fRows.begin();
866 const Row* stop = fRows.end();
867
868 size_t dataSize = 0;
869 while (row < stop) {
870 dataSize += row->fData->count();
871 row += 1;
872 }
873
reed@google.com045e62d2011-10-24 12:19:46 +0000874 if (0 == dataSize) {
875 return target->setEmpty();
876 }
877
reed@google.com209c4152011-10-26 15:03:48 +0000878 SkASSERT(fMinY >= fBounds.fTop);
879 SkASSERT(fMinY < fBounds.fBottom);
880 int adjustY = fMinY - fBounds.fTop;
881 fBounds.fTop = fMinY;
882
reed@google.come36707a2011-10-04 21:38:55 +0000883 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
884 YOffset* yoffset = head->yoffsets();
885 uint8_t* data = head->data();
886 uint8_t* baseData = data;
887
888 row = fRows.begin();
reed@google.comc9041912011-10-27 16:58:46 +0000889 SkDEBUGCODE(int prevY = row->fY - 1;)
reed@google.come36707a2011-10-04 21:38:55 +0000890 while (row < stop) {
reed@google.comc9041912011-10-27 16:58:46 +0000891 SkASSERT(prevY < row->fY); // must be monotonic
892 SkDEBUGCODE(prevY = row->fY);
893
reed@google.com209c4152011-10-26 15:03:48 +0000894 yoffset->fY = row->fY - adjustY;
reed@google.come36707a2011-10-04 21:38:55 +0000895 yoffset->fOffset = data - baseData;
896 yoffset += 1;
897
898 size_t n = row->fData->count();
899 memcpy(data, row->fData->begin(), n);
reed@google.comc9041912011-10-27 16:58:46 +0000900#ifdef SK_DEBUG
901 int bytesNeeded = compute_row_length(data, fBounds.width());
902 SkASSERT(bytesNeeded == n);
903#endif
reed@google.come36707a2011-10-04 21:38:55 +0000904 data += n;
905
906 row += 1;
907 }
908
reed@google.com045e62d2011-10-24 12:19:46 +0000909 target->freeRuns();
910 target->fBounds = fBounds;
911 target->fRunHead = head;
912 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +0000913 }
914
915 void dump() {
916 this->validate();
917 int y;
918 for (y = 0; y < fRows.count(); ++y) {
919 const Row& row = fRows[y];
920 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
921 const SkTDArray<uint8_t>& data = *row.fData;
922 int count = data.count();
923 SkASSERT(!(count & 1));
924 const uint8_t* ptr = data.begin();
925 for (int x = 0; x < count; x += 2) {
926 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
927 ptr += 2;
928 }
929 SkDebugf("\n");
930 }
reed@google.come36707a2011-10-04 21:38:55 +0000931 }
932
933 void validate() {
934#ifdef SK_DEBUG
935 int prevY = -1;
936 for (int i = 0; i < fRows.count(); ++i) {
937 const Row& row = fRows[i];
938 SkASSERT(prevY < row.fY);
939 SkASSERT(fWidth == row.fWidth);
940 int count = row.fData->count();
941 const uint8_t* ptr = row.fData->begin();
942 SkASSERT(!(count & 1));
943 int w = 0;
944 for (int x = 0; x < count; x += 2) {
reed@google.comd6040f62011-10-28 02:39:17 +0000945 int n = ptr[0];
946 SkASSERT(n > 0);
947 w += n;
reed@google.come36707a2011-10-04 21:38:55 +0000948 SkASSERT(w <= fWidth);
949 ptr += 2;
950 }
951 SkASSERT(w == fWidth);
952 prevY = row.fY;
953 }
954#endif
955 }
956
reed@google.com209c4152011-10-26 15:03:48 +0000957 // only called by BuilderBlitter
958 void setMinY(int y) {
959 fMinY = y;
960 }
961
reed@google.come36707a2011-10-04 21:38:55 +0000962private:
reed@google.com9154eb02011-10-31 16:07:28 +0000963 void flushRowH(Row* row) {
964 // flush current row if needed
965 if (row->fWidth < fWidth) {
966 AppendRun(*row->fData, 0, fWidth - row->fWidth);
967 row->fWidth = fWidth;
968 }
969 }
reed@google.com209c4152011-10-26 15:03:48 +0000970
reed@google.come36707a2011-10-04 21:38:55 +0000971 Row* flushRow(bool readyForAnother) {
972 Row* next = NULL;
973 int count = fRows.count();
974 if (count > 0) {
reed@google.com9154eb02011-10-31 16:07:28 +0000975 this->flushRowH(&fRows[count - 1]);
reed@google.come36707a2011-10-04 21:38:55 +0000976 }
977 if (count > 1) {
978 // are our last two runs the same?
979 Row* prev = &fRows[count - 2];
980 Row* curr = &fRows[count - 1];
981 SkASSERT(prev->fWidth == fWidth);
982 SkASSERT(curr->fWidth == fWidth);
983 if (*prev->fData == *curr->fData) {
984 prev->fY = curr->fY;
985 if (readyForAnother) {
986 curr->fData->rewind();
987 next = curr;
988 } else {
989 delete curr->fData;
990 fRows.removeShuffle(count - 1);
991 }
992 } else {
993 if (readyForAnother) {
994 next = fRows.append();
995 next->fData = new SkTDArray<uint8_t>;
996 }
997 }
998 } else {
999 if (readyForAnother) {
1000 next = fRows.append();
1001 next->fData = new SkTDArray<uint8_t>;
1002 }
1003 }
1004 return next;
1005 }
1006
1007 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
1008 do {
1009 int n = count;
1010 if (n > 255) {
1011 n = 255;
1012 }
1013 uint8_t* ptr = data.append(2);
1014 ptr[0] = n;
1015 ptr[1] = alpha;
1016 count -= n;
1017 } while (count > 0);
1018 }
1019};
1020
1021class SkAAClip::BuilderBlitter : public SkBlitter {
1022public:
1023 BuilderBlitter(Builder* builder) {
1024 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001025 fLeft = builder->getBounds().fLeft;
1026 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001027 fMinY = SK_MaxS32;
1028 }
1029
1030 void finish() {
1031 if (fMinY < SK_MaxS32) {
1032 fBuilder->setMinY(fMinY);
1033 }
reed@google.come36707a2011-10-04 21:38:55 +00001034 }
1035
1036 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
1037 { unexpected(); }
reed@google.com045e62d2011-10-24 12:19:46 +00001038
reed@google.com562a2ac2011-10-31 14:14:18 +00001039 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE {
reed@google.com9154eb02011-10-31 16:07:28 +00001040 this->recordMinY(y);
1041 fBuilder->addRectRun(x, y, width, height);
reed@google.com562a2ac2011-10-31 14:14:18 +00001042 }
reed@google.com045e62d2011-10-24 12:19:46 +00001043
reed@google.come36707a2011-10-04 21:38:55 +00001044 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
1045 { unexpected(); }
1046
1047 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +00001048 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +00001049 }
1050
1051 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001052 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +00001053 fBuilder->addRun(x, y, 0xFF, width);
1054 }
1055
1056 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
1057 const int16_t runs[]) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001058 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +00001059 for (;;) {
1060 int count = *runs;
1061 if (count <= 0) {
1062 return;
1063 }
reed@google.com17785642011-10-12 20:23:55 +00001064
1065 // The supersampler's buffer can be the width of the device, so
1066 // we may have to trim the run to our bounds. If so, we assert that
1067 // the extra spans are always alpha==0
1068 int localX = x;
1069 int localCount = count;
1070 if (x < fLeft) {
1071 SkASSERT(0 == *alpha);
1072 int gap = fLeft - x;
1073 SkASSERT(gap <= count);
1074 localX += gap;
1075 localCount -= gap;
1076 }
1077 int right = x + count;
1078 if (right > fRight) {
1079 SkASSERT(0 == *alpha);
1080 localCount -= right - fRight;
1081 SkASSERT(localCount >= 0);
1082 }
1083
1084 if (localCount) {
1085 fBuilder->addRun(localX, y, *alpha, localCount);
1086 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001087 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001088 runs += count;
1089 alpha += count;
1090 x += count;
1091 }
1092 }
1093
1094private:
1095 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001096 int fLeft; // cache of builder's bounds' left edge
1097 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001098 int fMinY;
1099
1100 /*
1101 * We track this, in case the scan converter skipped some number of
1102 * scanlines at the (relative to the bounds it was given). This allows
1103 * the builder, during its finish, to trip its bounds down to the "real"
1104 * top.
1105 */
1106 void recordMinY(int y) {
1107 if (y < fMinY) {
1108 fMinY = y;
1109 }
1110 }
reed@google.come36707a2011-10-04 21:38:55 +00001111
1112 void unexpected() {
1113 SkDebugf("---- did not expect to get called here");
1114 sk_throw();
1115 }
1116};
1117
reed@google.comf3c1da12011-10-10 19:35:47 +00001118bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001119 AUTO_AACLIP_VALIDATE(*this);
1120
reed@google.com32287892011-10-05 16:27:44 +00001121 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001122 return this->setEmpty();
1123 }
1124
1125 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001126 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001127
reed@google.com32287892011-10-05 16:27:44 +00001128 SkRegion tmpClip;
1129 if (NULL == clip) {
1130 tmpClip.setRect(ibounds);
1131 clip = &tmpClip;
1132 }
1133
reed@google.com045e62d2011-10-24 12:19:46 +00001134 if (path.isInverseFillType()) {
1135 ibounds = clip->getBounds();
1136 } else {
reed@google.com32287892011-10-05 16:27:44 +00001137 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001138 return this->setEmpty();
1139 }
reed@google.come36707a2011-10-04 21:38:55 +00001140 }
1141
1142 Builder builder(ibounds);
1143 BuilderBlitter blitter(&builder);
1144
reed@google.comf3c1da12011-10-10 19:35:47 +00001145 if (doAA) {
1146 SkScan::AntiFillPath(path, *clip, &blitter, true);
1147 } else {
1148 SkScan::FillPath(path, *clip, &blitter);
1149 }
reed@google.come36707a2011-10-04 21:38:55 +00001150
reed@google.com209c4152011-10-26 15:03:48 +00001151 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001152 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001153}
1154
1155///////////////////////////////////////////////////////////////////////////////
1156
reed@google.com32287892011-10-05 16:27:44 +00001157typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1158 const uint8_t* rowA, const SkIRect& rectA,
1159 const uint8_t* rowB, const SkIRect& rectB);
1160
1161static void sectRowProc(SkAAClip::Builder& builder, int bottom,
1162 const uint8_t* rowA, const SkIRect& rectA,
1163 const uint8_t* rowB, const SkIRect& rectB) {
1164
1165}
1166
1167typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1168
1169static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1170 // Multiply
1171 return SkMulDiv255Round(alphaA, alphaB);
1172}
1173
1174static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1175 // SrcOver
1176 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1177}
1178
1179static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1180 // SrcOut
1181 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1182}
1183
1184static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1185 // XOR
1186 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1187}
1188
1189static AlphaProc find_alpha_proc(SkRegion::Op op) {
1190 switch (op) {
1191 case SkRegion::kIntersect_Op:
1192 return sectAlphaProc;
1193 case SkRegion::kDifference_Op:
1194 return diffAlphaProc;
1195 case SkRegion::kUnion_Op:
1196 return unionAlphaProc;
1197 case SkRegion::kXOR_Op:
1198 return xorAlphaProc;
1199 default:
1200 SkASSERT(!"unexpected region op");
1201 return sectAlphaProc;
1202 }
1203}
1204
1205static const uint8_t gEmptyRow[] = {
1206 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1207 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1208 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1209 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1210 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1211 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1212 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1213 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1214};
1215
1216class RowIter {
1217public:
1218 RowIter(const uint8_t* row, const SkIRect& bounds) {
1219 fRow = row;
1220 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001221 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001222 if (row) {
1223 fRight = bounds.fLeft + row[0];
1224 SkASSERT(fRight <= fBoundsRight);
1225 fAlpha = row[1];
1226 fDone = false;
1227 } else {
1228 fDone = true;
1229 fRight = kMaxInt32;
1230 fAlpha = 0;
1231 }
reed@google.com32287892011-10-05 16:27:44 +00001232 }
1233
1234 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001235 int left() const { return fLeft; }
1236 int right() const { return fRight; }
1237 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001238 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001239 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001240 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001241 if (fRight == fBoundsRight) {
1242 fDone = true;
1243 fRight = kMaxInt32;
1244 fAlpha = 0;
1245 } else {
1246 fRow += 2;
1247 fRight += fRow[0];
1248 fAlpha = fRow[1];
1249 SkASSERT(fRight <= fBoundsRight);
1250 }
reed@google.com32287892011-10-05 16:27:44 +00001251 }
1252 }
1253
1254private:
1255 const uint8_t* fRow;
1256 int fLeft;
1257 int fRight;
1258 int fBoundsRight;
1259 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001260 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001261};
1262
reed@google.com1c04bf92011-10-10 12:57:12 +00001263static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1264 if (rite == riteA) {
1265 iter.next();
1266 leftA = iter.left();
1267 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001268 }
1269}
1270
reed@google.com1c04bf92011-10-10 12:57:12 +00001271static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1272 SkASSERT(min < max);
1273 SkASSERT(boundsMin < boundsMax);
1274 if (min >= boundsMax || max <= boundsMin) {
1275 return false;
1276 }
1277 if (min < boundsMin) {
1278 min = boundsMin;
1279 }
1280 if (max > boundsMax) {
1281 max = boundsMax;
1282 }
1283 return true;
1284}
1285
reed@google.com32287892011-10-05 16:27:44 +00001286static void operatorX(SkAAClip::Builder& builder, int lastY,
1287 RowIter& iterA, RowIter& iterB,
1288 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001289 int leftA = iterA.left();
1290 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001291 int leftB = iterB.left();
1292 int riteB = iterB.right();
1293
reed@google.com1c04bf92011-10-10 12:57:12 +00001294 int prevRite = bounds.fLeft;
1295
1296 do {
reed@google.com32287892011-10-05 16:27:44 +00001297 U8CPU alphaA = 0;
1298 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001299 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +00001300
1301 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001302 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001303 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001304 if (riteA <= leftB) {
1305 rite = riteA;
1306 } else {
1307 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001308 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001309 } else if (leftB < leftA) {
1310 left = leftB;
1311 alphaB = iterB.alpha();
1312 if (riteB <= leftA) {
1313 rite = riteB;
1314 } else {
1315 rite = leftB = leftA;
1316 }
1317 } else {
1318 left = leftA; // or leftB, since leftA == leftB
1319 rite = leftA = leftB = SkMin32(riteA, riteB);
1320 alphaA = iterA.alpha();
1321 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001322 }
1323
1324 if (left >= bounds.fRight) {
1325 break;
1326 }
reed@google.com34f7e472011-10-13 15:11:59 +00001327 if (rite > bounds.fRight) {
1328 rite = bounds.fRight;
1329 }
1330
reed@google.com32287892011-10-05 16:27:44 +00001331 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001332 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001333 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001334 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001335 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001336
1337 adjust_row(iterA, leftA, riteA, rite);
1338 adjust_row(iterB, leftB, riteB, rite);
1339 } while (!iterA.done() || !iterB.done());
1340
1341 if (prevRite < bounds.fRight) {
1342 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001343 }
1344}
1345
reed@google.com1c04bf92011-10-10 12:57:12 +00001346static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1347 if (bot == botA) {
1348 iter.next();
1349 topA = botA;
1350 SkASSERT(botA == iter.top());
1351 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001352 }
1353}
1354
1355static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1356 const SkAAClip& B, SkRegion::Op op) {
1357 AlphaProc proc = find_alpha_proc(op);
1358 const SkIRect& bounds = builder.getBounds();
1359
1360 SkAAClip::Iter iterA(A);
1361 SkAAClip::Iter iterB(B);
1362
1363 SkASSERT(!iterA.done());
1364 int topA = iterA.top();
1365 int botA = iterA.bottom();
1366 SkASSERT(!iterB.done());
1367 int topB = iterB.top();
1368 int botB = iterB.bottom();
1369
reed@google.com1c04bf92011-10-10 12:57:12 +00001370 do {
1371 const uint8_t* rowA = NULL;
1372 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001373 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001374
1375 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001376 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001377 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001378 if (botA <= topB) {
1379 bot = botA;
1380 } else {
1381 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001382 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001383
1384 } else if (topB < topA) {
1385 top = topB;
1386 rowB = iterB.data();
1387 if (botB <= topA) {
1388 bot = botB;
1389 } else {
1390 bot = topB = topA;
1391 }
1392 } else {
1393 top = topA; // or topB, since topA == topB
1394 bot = topA = topB = SkMin32(botA, botB);
1395 rowA = iterA.data();
1396 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001397 }
1398
1399 if (top >= bounds.fBottom) {
1400 break;
1401 }
reed@google.com34f7e472011-10-13 15:11:59 +00001402
1403 if (bot > bounds.fBottom) {
1404 bot = bounds.fBottom;
1405 }
1406 SkASSERT(top < bot);
1407
reed@google.com1c04bf92011-10-10 12:57:12 +00001408 if (!rowA && !rowB) {
1409 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1410 } else if (top >= bounds.fTop) {
1411 SkASSERT(bot <= bounds.fBottom);
1412 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1413 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001414 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001415 }
1416
reed@google.com1c04bf92011-10-10 12:57:12 +00001417 adjust_iter(iterA, topA, botA, bot);
1418 adjust_iter(iterB, topB, botB, bot);
1419 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001420}
1421
1422bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1423 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001424 AUTO_AACLIP_VALIDATE(*this);
1425
reed@google.com32287892011-10-05 16:27:44 +00001426 if (SkRegion::kReplace_Op == op) {
1427 return this->set(clipBOrig);
1428 }
1429
1430 const SkAAClip* clipA = &clipAOrig;
1431 const SkAAClip* clipB = &clipBOrig;
1432
1433 if (SkRegion::kReverseDifference_Op == op) {
1434 SkTSwap(clipA, clipB);
1435 op = SkRegion::kDifference_Op;
1436 }
1437
1438 bool a_empty = clipA->isEmpty();
1439 bool b_empty = clipB->isEmpty();
1440
1441 SkIRect bounds;
1442 switch (op) {
1443 case SkRegion::kDifference_Op:
1444 if (a_empty) {
1445 return this->setEmpty();
1446 }
1447 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1448 return this->set(*clipA);
1449 }
1450 bounds = clipA->fBounds;
1451 break;
1452
1453 case SkRegion::kIntersect_Op:
1454 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1455 clipB->fBounds)) {
1456 return this->setEmpty();
1457 }
1458 break;
1459
1460 case SkRegion::kUnion_Op:
1461 case SkRegion::kXOR_Op:
1462 if (a_empty) {
1463 return this->set(*clipB);
1464 }
1465 if (b_empty) {
1466 return this->set(*clipA);
1467 }
1468 bounds = clipA->fBounds;
1469 bounds.join(clipB->fBounds);
1470 break;
1471
1472 default:
1473 SkASSERT(!"unknown region op");
1474 return !this->isEmpty();
1475 }
1476
reed@google.com32287892011-10-05 16:27:44 +00001477 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1478 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1479
1480 Builder builder(bounds);
1481 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001482
1483 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001484}
1485
reed@google.com045e62d2011-10-24 12:19:46 +00001486/*
1487 * It can be expensive to build a local aaclip before applying the op, so
1488 * we first see if we can restrict the bounds of new rect to our current
1489 * bounds, or note that the new rect subsumes our current clip.
1490 */
1491
1492bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1493 SkIRect rStorage;
1494 const SkIRect* r = &rOrig;
1495
1496 switch (op) {
1497 case SkRegion::kIntersect_Op:
1498 if (!rStorage.intersect(rOrig, fBounds)) {
1499 // no overlap, so we're empty
1500 return this->setEmpty();
1501 }
1502 if (rStorage == fBounds) {
1503 // we were wholly inside the rect, no change
1504 return !this->isEmpty();
1505 }
1506 if (this->quickContains(rStorage)) {
1507 // the intersection is wholly inside us, we're a rect
1508 return this->setRect(rStorage);
1509 }
1510 r = &rStorage; // use the intersected bounds
1511 break;
1512 case SkRegion::kDifference_Op:
1513 break;
1514 case SkRegion::kUnion_Op:
1515 if (rOrig.contains(fBounds)) {
1516 return this->setRect(rOrig);
1517 }
1518 break;
1519 default:
1520 break;
1521 }
1522
reed@google.com47ac84e2011-10-06 13:11:25 +00001523 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001524 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001525 return this->op(*this, clip, op);
1526}
1527
reed@google.com045e62d2011-10-24 12:19:46 +00001528bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1529 SkRect rStorage, boundsStorage;
1530 const SkRect* r = &rOrig;
1531
1532 boundsStorage.set(fBounds);
1533 switch (op) {
1534 case SkRegion::kIntersect_Op:
1535 case SkRegion::kDifference_Op:
1536 if (!rStorage.intersect(rOrig, boundsStorage)) {
1537 return this->setEmpty();
1538 }
1539 r = &rStorage; // use the intersected bounds
1540 break;
1541 case SkRegion::kUnion_Op:
1542 if (rOrig.contains(boundsStorage)) {
1543 return this->setRect(rOrig);
1544 }
1545 break;
1546 default:
1547 break;
1548 }
1549
reed@google.com47ac84e2011-10-06 13:11:25 +00001550 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001551 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001552 return this->op(*this, clip, op);
1553}
1554
1555bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1556 return this->op(*this, clip, op);
1557}
1558
reed@google.come36707a2011-10-04 21:38:55 +00001559///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001560
1561bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1562 if (NULL == dst) {
1563 return !this->isEmpty();
1564 }
1565
1566 if (this->isEmpty()) {
1567 return dst->setEmpty();
1568 }
1569
1570 if (this != dst) {
1571 sk_atomic_inc(&fRunHead->fRefCnt);
1572 dst->fRunHead = fRunHead;
1573 dst->fBounds = fBounds;
1574 }
1575 dst->fBounds.offset(dx, dy);
1576 return true;
1577}
1578
1579static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1580 const uint8_t* SK_RESTRICT row,
1581 int width) {
1582 while (width > 0) {
1583 int n = row[0];
1584 SkASSERT(width >= n);
1585 memset(mask, row[1], n);
1586 mask += n;
1587 row += 2;
1588 width -= n;
1589 }
1590}
1591
1592void SkAAClip::copyToMask(SkMask* mask) const {
1593 mask->fFormat = SkMask::kA8_Format;
1594 if (this->isEmpty()) {
1595 mask->fBounds.setEmpty();
1596 mask->fImage = NULL;
1597 mask->fRowBytes = 0;
1598 return;
1599 }
1600
1601 mask->fBounds = fBounds;
1602 mask->fRowBytes = fBounds.width();
1603 size_t size = mask->computeImageSize();
1604 mask->fImage = SkMask::AllocImage(size);
1605
1606 Iter iter(*this);
1607 uint8_t* dst = mask->fImage;
1608 const int width = fBounds.width();
1609
1610 int y = fBounds.fTop;
1611 while (!iter.done()) {
1612 do {
1613 expand_row_to_mask(dst, iter.data(), width);
1614 dst += mask->fRowBytes;
1615 } while (++y < iter.bottom());
1616 iter.next();
1617 }
1618}
1619
1620///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001621///////////////////////////////////////////////////////////////////////////////
1622
1623static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1624 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1625 // we don't read our initial n from data, since the caller may have had to
1626 // clip it, hence the initialCount parameter.
1627 int n = initialCount;
1628 for (;;) {
1629 if (n > width) {
1630 n = width;
1631 }
1632 SkASSERT(n > 0);
1633 runs[0] = n;
1634 runs += n;
1635
1636 aa[0] = data[1];
1637 aa += n;
1638
1639 data += 2;
1640 width -= n;
1641 if (0 == width) {
1642 break;
1643 }
1644 // load the next count
1645 n = data[0];
1646 }
1647 runs[0] = 0; // sentinel
1648}
1649
1650SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001651 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001652}
1653
1654void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001655 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001656 // add 1 so we can store the terminating run count of 0
1657 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001658 // we use this either for fRuns + fAA, or a scaline of a mask
1659 // which may be as deep as 32bits
1660 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1661 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001662 fAA = (SkAlpha*)(fRuns + count);
1663 }
1664}
1665
1666void SkAAClipBlitter::blitH(int x, int y, int width) {
1667 SkASSERT(width > 0);
1668 SkASSERT(fAAClipBounds.contains(x, y));
1669 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1670
1671 int lastY;
1672 const uint8_t* row = fAAClip->findRow(y, &lastY);
1673 int initialCount;
1674 row = fAAClip->findX(row, x, &initialCount);
1675
1676 if (initialCount >= width) {
1677 SkAlpha alpha = row[1];
1678 if (0 == alpha) {
1679 return;
1680 }
1681 if (0xFF == alpha) {
1682 fBlitter->blitH(x, y, width);
1683 return;
1684 }
1685 }
1686
1687 this->ensureRunsAndAA();
1688 expandToRuns(row, initialCount, width, fRuns, fAA);
1689
1690 fBlitter->blitAntiH(x, y, fAA, fRuns);
1691}
1692
1693static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1694 const SkAlpha* SK_RESTRICT srcAA,
1695 const int16_t* SK_RESTRICT srcRuns,
1696 SkAlpha* SK_RESTRICT dstAA,
1697 int16_t* SK_RESTRICT dstRuns,
1698 int width) {
1699 SkDEBUGCODE(int accumulated = 0;)
1700 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001701 // do we need this check?
1702 if (0 == srcN) {
1703 return;
1704 }
1705
reed@google.come36707a2011-10-04 21:38:55 +00001706 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001707 SkASSERT(rowN > 0);
1708 SkASSERT(srcN > 0);
1709
1710 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1711 int minN = SkMin32(srcN, rowN);
1712 dstRuns[0] = minN;
1713 dstRuns += minN;
1714 dstAA[0] = newAlpha;
1715 dstAA += minN;
1716
1717 if (0 == (srcN -= minN)) {
1718 srcN = srcRuns[0]; // refresh
1719 srcRuns += srcN;
1720 srcAA += srcN;
1721 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001722 if (0 == srcN) {
1723 break;
1724 }
reed@google.come36707a2011-10-04 21:38:55 +00001725 }
1726 if (0 == (rowN -= minN)) {
1727 row += 2;
1728 rowN = row[0]; // reload
1729 }
1730
1731 SkDEBUGCODE(accumulated += minN;)
1732 SkASSERT(accumulated <= width);
1733 }
reed@google.com34f7e472011-10-13 15:11:59 +00001734 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001735}
1736
1737void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1738 const int16_t runs[]) {
1739 int lastY;
1740 const uint8_t* row = fAAClip->findRow(y, &lastY);
1741 int initialCount;
1742 row = fAAClip->findX(row, x, &initialCount);
1743
1744 this->ensureRunsAndAA();
1745
1746 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1747 fBlitter->blitAntiH(x, y, fAA, fRuns);
1748}
1749
1750void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1751 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1752 fBlitter->blitV(x, y, height, alpha);
1753 return;
1754 }
1755
reed@google.com045e62d2011-10-24 12:19:46 +00001756 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001757 int lastY;
1758 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001759 int dy = lastY - y + 1;
1760 if (dy > height) {
1761 dy = height;
1762 }
1763 height -= dy;
1764
reed@google.come36707a2011-10-04 21:38:55 +00001765 int initialCount;
1766 row = fAAClip->findX(row, x, &initialCount);
1767 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1768 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001769 fBlitter->blitV(x, y, dy, newAlpha);
1770 }
1771 SkASSERT(height >= 0);
1772 if (height <= 0) {
1773 break;
reed@google.come36707a2011-10-04 21:38:55 +00001774 }
1775 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001776 }
reed@google.come36707a2011-10-04 21:38:55 +00001777}
1778
1779void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1780 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1781 fBlitter->blitRect(x, y, width, height);
1782 return;
1783 }
1784
1785 while (--height >= 0) {
1786 this->blitH(x, y, width);
1787 y += 1;
1788 }
1789}
1790
reed@google.com045e62d2011-10-24 12:19:46 +00001791typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1792 int initialRowCount, void* dst);
1793
1794static void small_memcpy(void* dst, const void* src, size_t n) {
1795 memcpy(dst, src, n);
1796}
1797
1798static void small_bzero(void* dst, size_t n) {
1799 sk_bzero(dst, n);
1800}
1801
1802static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1803 return SkMulDiv255Round(value, alpha);
1804}
1805static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1806 unsigned r = SkGetPackedR16(value);
1807 unsigned g = SkGetPackedG16(value);
1808 unsigned b = SkGetPackedB16(value);
1809 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1810 SkMulDiv255Round(r, alpha),
1811 SkMulDiv255Round(r, alpha));
1812}
1813static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1814 unsigned a = SkGetPackedA32(value);
1815 unsigned r = SkGetPackedR32(value);
1816 unsigned g = SkGetPackedG32(value);
1817 unsigned b = SkGetPackedB32(value);
1818 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1819 SkMulDiv255Round(r, alpha),
1820 SkMulDiv255Round(g, alpha),
1821 SkMulDiv255Round(b, alpha));
1822}
1823
1824template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1825 const uint8_t* SK_RESTRICT row, int rowN,
1826 T* SK_RESTRICT dst) {
1827 SkDEBUGCODE(int accumulated = 0;)
1828 for (;;) {
1829 SkASSERT(rowN > 0);
1830 SkASSERT(srcN > 0);
1831
1832 int n = SkMin32(rowN, srcN);
1833 unsigned rowA = row[1];
1834 if (0xFF == rowA) {
1835 small_memcpy(dst, src, n * sizeof(T));
1836 } else if (0 == rowA) {
1837 small_bzero(dst, n * sizeof(T));
1838 } else {
1839 for (int i = 0; i < n; ++i) {
1840 dst[i] = mergeOne(src[i], rowA);
1841 }
1842 }
1843
1844 if (0 == (srcN -= n)) {
1845 break;
1846 }
1847
1848 src += n;
1849 dst += n;
1850
1851 SkASSERT(rowN == n);
1852 row += 2;
1853 rowN = row[0];
1854 }
1855}
1856
1857static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
1858 switch (format) {
1859 case SkMask::kBW_Format:
1860 SkASSERT(!"unsupported");
1861 return NULL;
1862 case SkMask::kA8_Format:
1863 case SkMask::k3D_Format: {
1864 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
1865 return (MergeAAProc)proc8;
1866 }
1867 case SkMask::kLCD16_Format: {
1868 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
1869 return (MergeAAProc)proc16;
1870 }
1871 case SkMask::kLCD32_Format: {
1872 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
1873 return (MergeAAProc)proc32;
1874 }
1875 default:
1876 SkASSERT(!"unsupported");
1877 return NULL;
1878 }
1879}
1880
1881static U8CPU bit2byte(int bitInAByte) {
1882 SkASSERT(bitInAByte <= 0xFF);
1883 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
1884 // some value >= 8 to get a full FF value
1885 return -bitInAByte >> 8;
1886}
1887
1888static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
1889 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
1890 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
1891
1892 const int width = srcMask.fBounds.width();
1893 const int height = srcMask.fBounds.height();
1894
1895 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
1896 const size_t srcRB = srcMask.fRowBytes;
1897 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
1898 const size_t dstRB = dstMask->fRowBytes;
1899
1900 const int wholeBytes = width >> 3;
1901 const int leftOverBits = width & 7;
1902
1903 for (int y = 0; y < height; ++y) {
1904 uint8_t* SK_RESTRICT d = dst;
1905 for (int i = 0; i < wholeBytes; ++i) {
1906 int srcByte = src[i];
1907 d[0] = bit2byte(srcByte & (1 << 7));
1908 d[1] = bit2byte(srcByte & (1 << 6));
1909 d[2] = bit2byte(srcByte & (1 << 5));
1910 d[3] = bit2byte(srcByte & (1 << 4));
1911 d[4] = bit2byte(srcByte & (1 << 3));
1912 d[5] = bit2byte(srcByte & (1 << 2));
1913 d[6] = bit2byte(srcByte & (1 << 1));
1914 d[7] = bit2byte(srcByte & (1 << 0));
1915 d += 8;
1916 }
1917 if (leftOverBits) {
1918 int srcByte = src[wholeBytes];
1919 for (int x = 0; x < leftOverBits; ++x) {
1920 *d++ = bit2byte(srcByte & 0x80);
1921 srcByte <<= 1;
1922 }
1923 }
1924 src += srcRB;
1925 dst += dstRB;
1926 }
1927}
1928
1929void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
1930 SkASSERT(fAAClip->getBounds().contains(clip));
1931
1932 if (fAAClip->quickContains(clip)) {
1933 fBlitter->blitMask(origMask, clip);
1934 return;
1935 }
1936
1937 const SkMask* mask = &origMask;
1938
1939 // if we're BW, we need to upscale to A8 (ugh)
1940 SkMask grayMask;
1941 grayMask.fImage = NULL;
1942 if (SkMask::kBW_Format == origMask.fFormat) {
1943 grayMask.fFormat = SkMask::kA8_Format;
1944 grayMask.fBounds = origMask.fBounds;
1945 grayMask.fRowBytes = origMask.fBounds.width();
1946 size_t size = grayMask.computeImageSize();
1947 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
1948 SkAutoMalloc::kReuse_OnShrink);
1949
1950 upscaleBW2A8(&grayMask, origMask);
1951 mask = &grayMask;
1952 }
1953
1954 this->ensureRunsAndAA();
1955
1956 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
1957 // data into a temp block to support it better (ugh)
1958
1959 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
1960 const size_t srcRB = mask->fRowBytes;
1961 const int width = clip.width();
1962 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
1963
1964 SkMask rowMask;
1965 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
1966 rowMask.fBounds.fLeft = clip.fLeft;
1967 rowMask.fBounds.fRight = clip.fRight;
1968 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
1969 rowMask.fImage = (uint8_t*)fScanlineScratch;
1970
1971 int y = clip.fTop;
1972 const int stopY = y + clip.height();
1973
1974 do {
1975 int localStopY;
1976 const uint8_t* row = fAAClip->findRow(y, &localStopY);
1977 // findRow returns last Y, not stop, so we add 1
1978 localStopY = SkMin32(localStopY + 1, stopY);
1979
1980 int initialCount;
1981 row = fAAClip->findX(row, clip.fLeft, &initialCount);
1982 do {
1983 mergeProc(src, width, row, initialCount, rowMask.fImage);
1984 rowMask.fBounds.fTop = y;
1985 rowMask.fBounds.fBottom = y + 1;
1986 fBlitter->blitMask(rowMask, rowMask.fBounds);
1987 src = (const void*)((const char*)src + srcRB);
1988 } while (++y < localStopY);
1989 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00001990}
1991
1992const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1993 return NULL;
1994}
1995