blob: 47c650e9a20113cbfef44b0d9be6650273ab0aaa [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.com045e62d2011-10-24 12:19:46 +0000849 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +0000850 this->flushRow(false);
851
852 const Row* row = fRows.begin();
853 const Row* stop = fRows.end();
854
855 size_t dataSize = 0;
856 while (row < stop) {
857 dataSize += row->fData->count();
858 row += 1;
859 }
860
reed@google.com045e62d2011-10-24 12:19:46 +0000861 if (0 == dataSize) {
862 return target->setEmpty();
863 }
864
reed@google.com209c4152011-10-26 15:03:48 +0000865 SkASSERT(fMinY >= fBounds.fTop);
866 SkASSERT(fMinY < fBounds.fBottom);
867 int adjustY = fMinY - fBounds.fTop;
868 fBounds.fTop = fMinY;
869
reed@google.come36707a2011-10-04 21:38:55 +0000870 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
871 YOffset* yoffset = head->yoffsets();
872 uint8_t* data = head->data();
873 uint8_t* baseData = data;
874
875 row = fRows.begin();
reed@google.comc9041912011-10-27 16:58:46 +0000876 SkDEBUGCODE(int prevY = row->fY - 1;)
reed@google.come36707a2011-10-04 21:38:55 +0000877 while (row < stop) {
reed@google.comc9041912011-10-27 16:58:46 +0000878 SkASSERT(prevY < row->fY); // must be monotonic
879 SkDEBUGCODE(prevY = row->fY);
880
reed@google.com209c4152011-10-26 15:03:48 +0000881 yoffset->fY = row->fY - adjustY;
reed@google.come36707a2011-10-04 21:38:55 +0000882 yoffset->fOffset = data - baseData;
883 yoffset += 1;
884
885 size_t n = row->fData->count();
886 memcpy(data, row->fData->begin(), n);
reed@google.comc9041912011-10-27 16:58:46 +0000887#ifdef SK_DEBUG
888 int bytesNeeded = compute_row_length(data, fBounds.width());
889 SkASSERT(bytesNeeded == n);
890#endif
reed@google.come36707a2011-10-04 21:38:55 +0000891 data += n;
892
893 row += 1;
894 }
895
reed@google.com045e62d2011-10-24 12:19:46 +0000896 target->freeRuns();
897 target->fBounds = fBounds;
898 target->fRunHead = head;
899 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +0000900 }
901
902 void dump() {
903 this->validate();
904 int y;
905 for (y = 0; y < fRows.count(); ++y) {
906 const Row& row = fRows[y];
907 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
908 const SkTDArray<uint8_t>& data = *row.fData;
909 int count = data.count();
910 SkASSERT(!(count & 1));
911 const uint8_t* ptr = data.begin();
912 for (int x = 0; x < count; x += 2) {
913 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
914 ptr += 2;
915 }
916 SkDebugf("\n");
917 }
reed@google.come36707a2011-10-04 21:38:55 +0000918 }
919
920 void validate() {
921#ifdef SK_DEBUG
922 int prevY = -1;
923 for (int i = 0; i < fRows.count(); ++i) {
924 const Row& row = fRows[i];
925 SkASSERT(prevY < row.fY);
926 SkASSERT(fWidth == row.fWidth);
927 int count = row.fData->count();
928 const uint8_t* ptr = row.fData->begin();
929 SkASSERT(!(count & 1));
930 int w = 0;
931 for (int x = 0; x < count; x += 2) {
reed@google.comd6040f62011-10-28 02:39:17 +0000932 int n = ptr[0];
933 SkASSERT(n > 0);
934 w += n;
reed@google.come36707a2011-10-04 21:38:55 +0000935 SkASSERT(w <= fWidth);
936 ptr += 2;
937 }
938 SkASSERT(w == fWidth);
939 prevY = row.fY;
940 }
941#endif
942 }
943
reed@google.com209c4152011-10-26 15:03:48 +0000944 // only called by BuilderBlitter
945 void setMinY(int y) {
946 fMinY = y;
947 }
948
reed@google.come36707a2011-10-04 21:38:55 +0000949private:
reed@google.com209c4152011-10-26 15:03:48 +0000950
reed@google.come36707a2011-10-04 21:38:55 +0000951 Row* flushRow(bool readyForAnother) {
952 Row* next = NULL;
953 int count = fRows.count();
954 if (count > 0) {
955 // flush current row if needed
956 Row* curr = &fRows[count - 1];
957 if (curr->fWidth < fWidth) {
958 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
reed@google.com045e62d2011-10-24 12:19:46 +0000959 curr->fWidth = fWidth;
reed@google.come36707a2011-10-04 21:38:55 +0000960 }
961 }
962 if (count > 1) {
963 // are our last two runs the same?
964 Row* prev = &fRows[count - 2];
965 Row* curr = &fRows[count - 1];
966 SkASSERT(prev->fWidth == fWidth);
967 SkASSERT(curr->fWidth == fWidth);
968 if (*prev->fData == *curr->fData) {
969 prev->fY = curr->fY;
970 if (readyForAnother) {
971 curr->fData->rewind();
972 next = curr;
973 } else {
974 delete curr->fData;
975 fRows.removeShuffle(count - 1);
976 }
977 } else {
978 if (readyForAnother) {
979 next = fRows.append();
980 next->fData = new SkTDArray<uint8_t>;
981 }
982 }
983 } else {
984 if (readyForAnother) {
985 next = fRows.append();
986 next->fData = new SkTDArray<uint8_t>;
987 }
988 }
989 return next;
990 }
991
992 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
993 do {
994 int n = count;
995 if (n > 255) {
996 n = 255;
997 }
998 uint8_t* ptr = data.append(2);
999 ptr[0] = n;
1000 ptr[1] = alpha;
1001 count -= n;
1002 } while (count > 0);
1003 }
1004};
1005
1006class SkAAClip::BuilderBlitter : public SkBlitter {
1007public:
1008 BuilderBlitter(Builder* builder) {
1009 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +00001010 fLeft = builder->getBounds().fLeft;
1011 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001012 fMinY = SK_MaxS32;
1013 }
1014
1015 void finish() {
1016 if (fMinY < SK_MaxS32) {
1017 fBuilder->setMinY(fMinY);
1018 }
reed@google.come36707a2011-10-04 21:38:55 +00001019 }
1020
1021 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
1022 { unexpected(); }
reed@google.com045e62d2011-10-24 12:19:46 +00001023
1024 // let the default impl call blitH
1025// virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
1026
reed@google.come36707a2011-10-04 21:38:55 +00001027 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
1028 { unexpected(); }
1029
1030 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +00001031 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +00001032 }
1033
1034 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001035 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +00001036 fBuilder->addRun(x, y, 0xFF, width);
1037 }
1038
1039 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
1040 const int16_t runs[]) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +00001041 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +00001042 for (;;) {
1043 int count = *runs;
1044 if (count <= 0) {
1045 return;
1046 }
reed@google.com17785642011-10-12 20:23:55 +00001047
1048 // The supersampler's buffer can be the width of the device, so
1049 // we may have to trim the run to our bounds. If so, we assert that
1050 // the extra spans are always alpha==0
1051 int localX = x;
1052 int localCount = count;
1053 if (x < fLeft) {
1054 SkASSERT(0 == *alpha);
1055 int gap = fLeft - x;
1056 SkASSERT(gap <= count);
1057 localX += gap;
1058 localCount -= gap;
1059 }
1060 int right = x + count;
1061 if (right > fRight) {
1062 SkASSERT(0 == *alpha);
1063 localCount -= right - fRight;
1064 SkASSERT(localCount >= 0);
1065 }
1066
1067 if (localCount) {
1068 fBuilder->addRun(localX, y, *alpha, localCount);
1069 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +00001070 // Next run
reed@google.come36707a2011-10-04 21:38:55 +00001071 runs += count;
1072 alpha += count;
1073 x += count;
1074 }
1075 }
1076
1077private:
1078 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +00001079 int fLeft; // cache of builder's bounds' left edge
1080 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +00001081 int fMinY;
1082
1083 /*
1084 * We track this, in case the scan converter skipped some number of
1085 * scanlines at the (relative to the bounds it was given). This allows
1086 * the builder, during its finish, to trip its bounds down to the "real"
1087 * top.
1088 */
1089 void recordMinY(int y) {
1090 if (y < fMinY) {
1091 fMinY = y;
1092 }
1093 }
reed@google.come36707a2011-10-04 21:38:55 +00001094
1095 void unexpected() {
1096 SkDebugf("---- did not expect to get called here");
1097 sk_throw();
1098 }
1099};
1100
reed@google.comf3c1da12011-10-10 19:35:47 +00001101bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +00001102 AUTO_AACLIP_VALIDATE(*this);
1103
reed@google.com32287892011-10-05 16:27:44 +00001104 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +00001105 return this->setEmpty();
1106 }
1107
1108 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +00001109 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +00001110
reed@google.com32287892011-10-05 16:27:44 +00001111 SkRegion tmpClip;
1112 if (NULL == clip) {
1113 tmpClip.setRect(ibounds);
1114 clip = &tmpClip;
1115 }
1116
reed@google.com045e62d2011-10-24 12:19:46 +00001117 if (path.isInverseFillType()) {
1118 ibounds = clip->getBounds();
1119 } else {
reed@google.com32287892011-10-05 16:27:44 +00001120 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +00001121 return this->setEmpty();
1122 }
reed@google.come36707a2011-10-04 21:38:55 +00001123 }
1124
1125 Builder builder(ibounds);
1126 BuilderBlitter blitter(&builder);
1127
reed@google.comf3c1da12011-10-10 19:35:47 +00001128 if (doAA) {
1129 SkScan::AntiFillPath(path, *clip, &blitter, true);
1130 } else {
1131 SkScan::FillPath(path, *clip, &blitter);
1132 }
reed@google.come36707a2011-10-04 21:38:55 +00001133
reed@google.com209c4152011-10-26 15:03:48 +00001134 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +00001135 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001136}
1137
1138///////////////////////////////////////////////////////////////////////////////
1139
reed@google.com32287892011-10-05 16:27:44 +00001140typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
1141 const uint8_t* rowA, const SkIRect& rectA,
1142 const uint8_t* rowB, const SkIRect& rectB);
1143
1144static void sectRowProc(SkAAClip::Builder& builder, int bottom,
1145 const uint8_t* rowA, const SkIRect& rectA,
1146 const uint8_t* rowB, const SkIRect& rectB) {
1147
1148}
1149
1150typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
1151
1152static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1153 // Multiply
1154 return SkMulDiv255Round(alphaA, alphaB);
1155}
1156
1157static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1158 // SrcOver
1159 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
1160}
1161
1162static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1163 // SrcOut
1164 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
1165}
1166
1167static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
1168 // XOR
1169 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
1170}
1171
1172static AlphaProc find_alpha_proc(SkRegion::Op op) {
1173 switch (op) {
1174 case SkRegion::kIntersect_Op:
1175 return sectAlphaProc;
1176 case SkRegion::kDifference_Op:
1177 return diffAlphaProc;
1178 case SkRegion::kUnion_Op:
1179 return unionAlphaProc;
1180 case SkRegion::kXOR_Op:
1181 return xorAlphaProc;
1182 default:
1183 SkASSERT(!"unexpected region op");
1184 return sectAlphaProc;
1185 }
1186}
1187
1188static const uint8_t gEmptyRow[] = {
1189 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1190 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1191 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1192 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1193 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1194 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1195 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1196 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
1197};
1198
1199class RowIter {
1200public:
1201 RowIter(const uint8_t* row, const SkIRect& bounds) {
1202 fRow = row;
1203 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +00001204 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001205 if (row) {
1206 fRight = bounds.fLeft + row[0];
1207 SkASSERT(fRight <= fBoundsRight);
1208 fAlpha = row[1];
1209 fDone = false;
1210 } else {
1211 fDone = true;
1212 fRight = kMaxInt32;
1213 fAlpha = 0;
1214 }
reed@google.com32287892011-10-05 16:27:44 +00001215 }
1216
1217 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +00001218 int left() const { return fLeft; }
1219 int right() const { return fRight; }
1220 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +00001221 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +00001222 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +00001223 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +00001224 if (fRight == fBoundsRight) {
1225 fDone = true;
1226 fRight = kMaxInt32;
1227 fAlpha = 0;
1228 } else {
1229 fRow += 2;
1230 fRight += fRow[0];
1231 fAlpha = fRow[1];
1232 SkASSERT(fRight <= fBoundsRight);
1233 }
reed@google.com32287892011-10-05 16:27:44 +00001234 }
1235 }
1236
1237private:
1238 const uint8_t* fRow;
1239 int fLeft;
1240 int fRight;
1241 int fBoundsRight;
1242 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +00001243 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +00001244};
1245
reed@google.com1c04bf92011-10-10 12:57:12 +00001246static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
1247 if (rite == riteA) {
1248 iter.next();
1249 leftA = iter.left();
1250 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +00001251 }
1252}
1253
reed@google.com1c04bf92011-10-10 12:57:12 +00001254static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
1255 SkASSERT(min < max);
1256 SkASSERT(boundsMin < boundsMax);
1257 if (min >= boundsMax || max <= boundsMin) {
1258 return false;
1259 }
1260 if (min < boundsMin) {
1261 min = boundsMin;
1262 }
1263 if (max > boundsMax) {
1264 max = boundsMax;
1265 }
1266 return true;
1267}
1268
reed@google.com32287892011-10-05 16:27:44 +00001269static void operatorX(SkAAClip::Builder& builder, int lastY,
1270 RowIter& iterA, RowIter& iterB,
1271 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +00001272 int leftA = iterA.left();
1273 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +00001274 int leftB = iterB.left();
1275 int riteB = iterB.right();
1276
reed@google.com1c04bf92011-10-10 12:57:12 +00001277 int prevRite = bounds.fLeft;
1278
1279 do {
reed@google.com32287892011-10-05 16:27:44 +00001280 U8CPU alphaA = 0;
1281 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +00001282 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +00001283
1284 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +00001285 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +00001286 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +00001287 if (riteA <= leftB) {
1288 rite = riteA;
1289 } else {
1290 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +00001291 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001292 } else if (leftB < leftA) {
1293 left = leftB;
1294 alphaB = iterB.alpha();
1295 if (riteB <= leftA) {
1296 rite = riteB;
1297 } else {
1298 rite = leftB = leftA;
1299 }
1300 } else {
1301 left = leftA; // or leftB, since leftA == leftB
1302 rite = leftA = leftB = SkMin32(riteA, riteB);
1303 alphaA = iterA.alpha();
1304 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +00001305 }
1306
1307 if (left >= bounds.fRight) {
1308 break;
1309 }
reed@google.com34f7e472011-10-13 15:11:59 +00001310 if (rite > bounds.fRight) {
1311 rite = bounds.fRight;
1312 }
1313
reed@google.com32287892011-10-05 16:27:44 +00001314 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +00001315 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +00001316 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +00001317 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +00001318 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001319
1320 adjust_row(iterA, leftA, riteA, rite);
1321 adjust_row(iterB, leftB, riteB, rite);
1322 } while (!iterA.done() || !iterB.done());
1323
1324 if (prevRite < bounds.fRight) {
1325 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001326 }
1327}
1328
reed@google.com1c04bf92011-10-10 12:57:12 +00001329static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1330 if (bot == botA) {
1331 iter.next();
1332 topA = botA;
1333 SkASSERT(botA == iter.top());
1334 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001335 }
1336}
1337
1338static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1339 const SkAAClip& B, SkRegion::Op op) {
1340 AlphaProc proc = find_alpha_proc(op);
1341 const SkIRect& bounds = builder.getBounds();
1342
1343 SkAAClip::Iter iterA(A);
1344 SkAAClip::Iter iterB(B);
1345
1346 SkASSERT(!iterA.done());
1347 int topA = iterA.top();
1348 int botA = iterA.bottom();
1349 SkASSERT(!iterB.done());
1350 int topB = iterB.top();
1351 int botB = iterB.bottom();
1352
reed@google.com1c04bf92011-10-10 12:57:12 +00001353 do {
1354 const uint8_t* rowA = NULL;
1355 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001356 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001357
1358 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001359 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001360 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001361 if (botA <= topB) {
1362 bot = botA;
1363 } else {
1364 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001365 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001366
1367 } else if (topB < topA) {
1368 top = topB;
1369 rowB = iterB.data();
1370 if (botB <= topA) {
1371 bot = botB;
1372 } else {
1373 bot = topB = topA;
1374 }
1375 } else {
1376 top = topA; // or topB, since topA == topB
1377 bot = topA = topB = SkMin32(botA, botB);
1378 rowA = iterA.data();
1379 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001380 }
1381
1382 if (top >= bounds.fBottom) {
1383 break;
1384 }
reed@google.com34f7e472011-10-13 15:11:59 +00001385
1386 if (bot > bounds.fBottom) {
1387 bot = bounds.fBottom;
1388 }
1389 SkASSERT(top < bot);
1390
reed@google.com1c04bf92011-10-10 12:57:12 +00001391 if (!rowA && !rowB) {
1392 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1393 } else if (top >= bounds.fTop) {
1394 SkASSERT(bot <= bounds.fBottom);
1395 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1396 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001397 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001398 }
1399
reed@google.com1c04bf92011-10-10 12:57:12 +00001400 adjust_iter(iterA, topA, botA, bot);
1401 adjust_iter(iterB, topB, botB, bot);
1402 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001403}
1404
1405bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1406 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001407 AUTO_AACLIP_VALIDATE(*this);
1408
reed@google.com32287892011-10-05 16:27:44 +00001409 if (SkRegion::kReplace_Op == op) {
1410 return this->set(clipBOrig);
1411 }
1412
1413 const SkAAClip* clipA = &clipAOrig;
1414 const SkAAClip* clipB = &clipBOrig;
1415
1416 if (SkRegion::kReverseDifference_Op == op) {
1417 SkTSwap(clipA, clipB);
1418 op = SkRegion::kDifference_Op;
1419 }
1420
1421 bool a_empty = clipA->isEmpty();
1422 bool b_empty = clipB->isEmpty();
1423
1424 SkIRect bounds;
1425 switch (op) {
1426 case SkRegion::kDifference_Op:
1427 if (a_empty) {
1428 return this->setEmpty();
1429 }
1430 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1431 return this->set(*clipA);
1432 }
1433 bounds = clipA->fBounds;
1434 break;
1435
1436 case SkRegion::kIntersect_Op:
1437 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1438 clipB->fBounds)) {
1439 return this->setEmpty();
1440 }
1441 break;
1442
1443 case SkRegion::kUnion_Op:
1444 case SkRegion::kXOR_Op:
1445 if (a_empty) {
1446 return this->set(*clipB);
1447 }
1448 if (b_empty) {
1449 return this->set(*clipA);
1450 }
1451 bounds = clipA->fBounds;
1452 bounds.join(clipB->fBounds);
1453 break;
1454
1455 default:
1456 SkASSERT(!"unknown region op");
1457 return !this->isEmpty();
1458 }
1459
reed@google.com32287892011-10-05 16:27:44 +00001460 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1461 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1462
1463 Builder builder(bounds);
1464 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001465
1466 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001467}
1468
reed@google.com045e62d2011-10-24 12:19:46 +00001469/*
1470 * It can be expensive to build a local aaclip before applying the op, so
1471 * we first see if we can restrict the bounds of new rect to our current
1472 * bounds, or note that the new rect subsumes our current clip.
1473 */
1474
1475bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1476 SkIRect rStorage;
1477 const SkIRect* r = &rOrig;
1478
1479 switch (op) {
1480 case SkRegion::kIntersect_Op:
1481 if (!rStorage.intersect(rOrig, fBounds)) {
1482 // no overlap, so we're empty
1483 return this->setEmpty();
1484 }
1485 if (rStorage == fBounds) {
1486 // we were wholly inside the rect, no change
1487 return !this->isEmpty();
1488 }
1489 if (this->quickContains(rStorage)) {
1490 // the intersection is wholly inside us, we're a rect
1491 return this->setRect(rStorage);
1492 }
1493 r = &rStorage; // use the intersected bounds
1494 break;
1495 case SkRegion::kDifference_Op:
1496 break;
1497 case SkRegion::kUnion_Op:
1498 if (rOrig.contains(fBounds)) {
1499 return this->setRect(rOrig);
1500 }
1501 break;
1502 default:
1503 break;
1504 }
1505
reed@google.com47ac84e2011-10-06 13:11:25 +00001506 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001507 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001508 return this->op(*this, clip, op);
1509}
1510
reed@google.com045e62d2011-10-24 12:19:46 +00001511bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1512 SkRect rStorage, boundsStorage;
1513 const SkRect* r = &rOrig;
1514
1515 boundsStorage.set(fBounds);
1516 switch (op) {
1517 case SkRegion::kIntersect_Op:
1518 case SkRegion::kDifference_Op:
1519 if (!rStorage.intersect(rOrig, boundsStorage)) {
1520 return this->setEmpty();
1521 }
1522 r = &rStorage; // use the intersected bounds
1523 break;
1524 case SkRegion::kUnion_Op:
1525 if (rOrig.contains(boundsStorage)) {
1526 return this->setRect(rOrig);
1527 }
1528 break;
1529 default:
1530 break;
1531 }
1532
reed@google.com47ac84e2011-10-06 13:11:25 +00001533 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001534 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001535 return this->op(*this, clip, op);
1536}
1537
1538bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1539 return this->op(*this, clip, op);
1540}
1541
reed@google.come36707a2011-10-04 21:38:55 +00001542///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001543
1544bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1545 if (NULL == dst) {
1546 return !this->isEmpty();
1547 }
1548
1549 if (this->isEmpty()) {
1550 return dst->setEmpty();
1551 }
1552
1553 if (this != dst) {
1554 sk_atomic_inc(&fRunHead->fRefCnt);
1555 dst->fRunHead = fRunHead;
1556 dst->fBounds = fBounds;
1557 }
1558 dst->fBounds.offset(dx, dy);
1559 return true;
1560}
1561
1562static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1563 const uint8_t* SK_RESTRICT row,
1564 int width) {
1565 while (width > 0) {
1566 int n = row[0];
1567 SkASSERT(width >= n);
1568 memset(mask, row[1], n);
1569 mask += n;
1570 row += 2;
1571 width -= n;
1572 }
1573}
1574
1575void SkAAClip::copyToMask(SkMask* mask) const {
1576 mask->fFormat = SkMask::kA8_Format;
1577 if (this->isEmpty()) {
1578 mask->fBounds.setEmpty();
1579 mask->fImage = NULL;
1580 mask->fRowBytes = 0;
1581 return;
1582 }
1583
1584 mask->fBounds = fBounds;
1585 mask->fRowBytes = fBounds.width();
1586 size_t size = mask->computeImageSize();
1587 mask->fImage = SkMask::AllocImage(size);
1588
1589 Iter iter(*this);
1590 uint8_t* dst = mask->fImage;
1591 const int width = fBounds.width();
1592
1593 int y = fBounds.fTop;
1594 while (!iter.done()) {
1595 do {
1596 expand_row_to_mask(dst, iter.data(), width);
1597 dst += mask->fRowBytes;
1598 } while (++y < iter.bottom());
1599 iter.next();
1600 }
1601}
1602
1603///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001604///////////////////////////////////////////////////////////////////////////////
1605
1606static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1607 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1608 // we don't read our initial n from data, since the caller may have had to
1609 // clip it, hence the initialCount parameter.
1610 int n = initialCount;
1611 for (;;) {
1612 if (n > width) {
1613 n = width;
1614 }
1615 SkASSERT(n > 0);
1616 runs[0] = n;
1617 runs += n;
1618
1619 aa[0] = data[1];
1620 aa += n;
1621
1622 data += 2;
1623 width -= n;
1624 if (0 == width) {
1625 break;
1626 }
1627 // load the next count
1628 n = data[0];
1629 }
1630 runs[0] = 0; // sentinel
1631}
1632
1633SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001634 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001635}
1636
1637void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001638 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001639 // add 1 so we can store the terminating run count of 0
1640 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001641 // we use this either for fRuns + fAA, or a scaline of a mask
1642 // which may be as deep as 32bits
1643 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1644 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001645 fAA = (SkAlpha*)(fRuns + count);
1646 }
1647}
1648
1649void SkAAClipBlitter::blitH(int x, int y, int width) {
1650 SkASSERT(width > 0);
1651 SkASSERT(fAAClipBounds.contains(x, y));
1652 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1653
1654 int lastY;
1655 const uint8_t* row = fAAClip->findRow(y, &lastY);
1656 int initialCount;
1657 row = fAAClip->findX(row, x, &initialCount);
1658
1659 if (initialCount >= width) {
1660 SkAlpha alpha = row[1];
1661 if (0 == alpha) {
1662 return;
1663 }
1664 if (0xFF == alpha) {
1665 fBlitter->blitH(x, y, width);
1666 return;
1667 }
1668 }
1669
1670 this->ensureRunsAndAA();
1671 expandToRuns(row, initialCount, width, fRuns, fAA);
1672
1673 fBlitter->blitAntiH(x, y, fAA, fRuns);
1674}
1675
1676static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1677 const SkAlpha* SK_RESTRICT srcAA,
1678 const int16_t* SK_RESTRICT srcRuns,
1679 SkAlpha* SK_RESTRICT dstAA,
1680 int16_t* SK_RESTRICT dstRuns,
1681 int width) {
1682 SkDEBUGCODE(int accumulated = 0;)
1683 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001684 // do we need this check?
1685 if (0 == srcN) {
1686 return;
1687 }
1688
reed@google.come36707a2011-10-04 21:38:55 +00001689 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001690 SkASSERT(rowN > 0);
1691 SkASSERT(srcN > 0);
1692
1693 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1694 int minN = SkMin32(srcN, rowN);
1695 dstRuns[0] = minN;
1696 dstRuns += minN;
1697 dstAA[0] = newAlpha;
1698 dstAA += minN;
1699
1700 if (0 == (srcN -= minN)) {
1701 srcN = srcRuns[0]; // refresh
1702 srcRuns += srcN;
1703 srcAA += srcN;
1704 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001705 if (0 == srcN) {
1706 break;
1707 }
reed@google.come36707a2011-10-04 21:38:55 +00001708 }
1709 if (0 == (rowN -= minN)) {
1710 row += 2;
1711 rowN = row[0]; // reload
1712 }
1713
1714 SkDEBUGCODE(accumulated += minN;)
1715 SkASSERT(accumulated <= width);
1716 }
reed@google.com34f7e472011-10-13 15:11:59 +00001717 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001718}
1719
1720void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1721 const int16_t runs[]) {
1722 int lastY;
1723 const uint8_t* row = fAAClip->findRow(y, &lastY);
1724 int initialCount;
1725 row = fAAClip->findX(row, x, &initialCount);
1726
1727 this->ensureRunsAndAA();
1728
1729 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1730 fBlitter->blitAntiH(x, y, fAA, fRuns);
1731}
1732
1733void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1734 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1735 fBlitter->blitV(x, y, height, alpha);
1736 return;
1737 }
1738
reed@google.com045e62d2011-10-24 12:19:46 +00001739 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001740 int lastY;
1741 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001742 int dy = lastY - y + 1;
1743 if (dy > height) {
1744 dy = height;
1745 }
1746 height -= dy;
1747
reed@google.come36707a2011-10-04 21:38:55 +00001748 int initialCount;
1749 row = fAAClip->findX(row, x, &initialCount);
1750 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1751 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001752 fBlitter->blitV(x, y, dy, newAlpha);
1753 }
1754 SkASSERT(height >= 0);
1755 if (height <= 0) {
1756 break;
reed@google.come36707a2011-10-04 21:38:55 +00001757 }
1758 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001759 }
reed@google.come36707a2011-10-04 21:38:55 +00001760}
1761
1762void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1763 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1764 fBlitter->blitRect(x, y, width, height);
1765 return;
1766 }
1767
1768 while (--height >= 0) {
1769 this->blitH(x, y, width);
1770 y += 1;
1771 }
1772}
1773
reed@google.com045e62d2011-10-24 12:19:46 +00001774typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1775 int initialRowCount, void* dst);
1776
1777static void small_memcpy(void* dst, const void* src, size_t n) {
1778 memcpy(dst, src, n);
1779}
1780
1781static void small_bzero(void* dst, size_t n) {
1782 sk_bzero(dst, n);
1783}
1784
1785static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1786 return SkMulDiv255Round(value, alpha);
1787}
1788static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1789 unsigned r = SkGetPackedR16(value);
1790 unsigned g = SkGetPackedG16(value);
1791 unsigned b = SkGetPackedB16(value);
1792 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1793 SkMulDiv255Round(r, alpha),
1794 SkMulDiv255Round(r, alpha));
1795}
1796static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1797 unsigned a = SkGetPackedA32(value);
1798 unsigned r = SkGetPackedR32(value);
1799 unsigned g = SkGetPackedG32(value);
1800 unsigned b = SkGetPackedB32(value);
1801 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1802 SkMulDiv255Round(r, alpha),
1803 SkMulDiv255Round(g, alpha),
1804 SkMulDiv255Round(b, alpha));
1805}
1806
1807template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1808 const uint8_t* SK_RESTRICT row, int rowN,
1809 T* SK_RESTRICT dst) {
1810 SkDEBUGCODE(int accumulated = 0;)
1811 for (;;) {
1812 SkASSERT(rowN > 0);
1813 SkASSERT(srcN > 0);
1814
1815 int n = SkMin32(rowN, srcN);
1816 unsigned rowA = row[1];
1817 if (0xFF == rowA) {
1818 small_memcpy(dst, src, n * sizeof(T));
1819 } else if (0 == rowA) {
1820 small_bzero(dst, n * sizeof(T));
1821 } else {
1822 for (int i = 0; i < n; ++i) {
1823 dst[i] = mergeOne(src[i], rowA);
1824 }
1825 }
1826
1827 if (0 == (srcN -= n)) {
1828 break;
1829 }
1830
1831 src += n;
1832 dst += n;
1833
1834 SkASSERT(rowN == n);
1835 row += 2;
1836 rowN = row[0];
1837 }
1838}
1839
1840static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
1841 switch (format) {
1842 case SkMask::kBW_Format:
1843 SkASSERT(!"unsupported");
1844 return NULL;
1845 case SkMask::kA8_Format:
1846 case SkMask::k3D_Format: {
1847 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
1848 return (MergeAAProc)proc8;
1849 }
1850 case SkMask::kLCD16_Format: {
1851 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
1852 return (MergeAAProc)proc16;
1853 }
1854 case SkMask::kLCD32_Format: {
1855 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
1856 return (MergeAAProc)proc32;
1857 }
1858 default:
1859 SkASSERT(!"unsupported");
1860 return NULL;
1861 }
1862}
1863
1864static U8CPU bit2byte(int bitInAByte) {
1865 SkASSERT(bitInAByte <= 0xFF);
1866 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
1867 // some value >= 8 to get a full FF value
1868 return -bitInAByte >> 8;
1869}
1870
1871static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
1872 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
1873 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
1874
1875 const int width = srcMask.fBounds.width();
1876 const int height = srcMask.fBounds.height();
1877
1878 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
1879 const size_t srcRB = srcMask.fRowBytes;
1880 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
1881 const size_t dstRB = dstMask->fRowBytes;
1882
1883 const int wholeBytes = width >> 3;
1884 const int leftOverBits = width & 7;
1885
1886 for (int y = 0; y < height; ++y) {
1887 uint8_t* SK_RESTRICT d = dst;
1888 for (int i = 0; i < wholeBytes; ++i) {
1889 int srcByte = src[i];
1890 d[0] = bit2byte(srcByte & (1 << 7));
1891 d[1] = bit2byte(srcByte & (1 << 6));
1892 d[2] = bit2byte(srcByte & (1 << 5));
1893 d[3] = bit2byte(srcByte & (1 << 4));
1894 d[4] = bit2byte(srcByte & (1 << 3));
1895 d[5] = bit2byte(srcByte & (1 << 2));
1896 d[6] = bit2byte(srcByte & (1 << 1));
1897 d[7] = bit2byte(srcByte & (1 << 0));
1898 d += 8;
1899 }
1900 if (leftOverBits) {
1901 int srcByte = src[wholeBytes];
1902 for (int x = 0; x < leftOverBits; ++x) {
1903 *d++ = bit2byte(srcByte & 0x80);
1904 srcByte <<= 1;
1905 }
1906 }
1907 src += srcRB;
1908 dst += dstRB;
1909 }
1910}
1911
1912void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
1913 SkASSERT(fAAClip->getBounds().contains(clip));
1914
1915 if (fAAClip->quickContains(clip)) {
1916 fBlitter->blitMask(origMask, clip);
1917 return;
1918 }
1919
1920 const SkMask* mask = &origMask;
1921
1922 // if we're BW, we need to upscale to A8 (ugh)
1923 SkMask grayMask;
1924 grayMask.fImage = NULL;
1925 if (SkMask::kBW_Format == origMask.fFormat) {
1926 grayMask.fFormat = SkMask::kA8_Format;
1927 grayMask.fBounds = origMask.fBounds;
1928 grayMask.fRowBytes = origMask.fBounds.width();
1929 size_t size = grayMask.computeImageSize();
1930 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
1931 SkAutoMalloc::kReuse_OnShrink);
1932
1933 upscaleBW2A8(&grayMask, origMask);
1934 mask = &grayMask;
1935 }
1936
1937 this->ensureRunsAndAA();
1938
1939 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
1940 // data into a temp block to support it better (ugh)
1941
1942 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
1943 const size_t srcRB = mask->fRowBytes;
1944 const int width = clip.width();
1945 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
1946
1947 SkMask rowMask;
1948 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
1949 rowMask.fBounds.fLeft = clip.fLeft;
1950 rowMask.fBounds.fRight = clip.fRight;
1951 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
1952 rowMask.fImage = (uint8_t*)fScanlineScratch;
1953
1954 int y = clip.fTop;
1955 const int stopY = y + clip.height();
1956
1957 do {
1958 int localStopY;
1959 const uint8_t* row = fAAClip->findRow(y, &localStopY);
1960 // findRow returns last Y, not stop, so we add 1
1961 localStopY = SkMin32(localStopY + 1, stopY);
1962
1963 int initialCount;
1964 row = fAAClip->findX(row, clip.fLeft, &initialCount);
1965 do {
1966 mergeProc(src, width, row, initialCount, rowMask.fImage);
1967 rowMask.fBounds.fTop = y;
1968 rowMask.fBounds.fBottom = y + 1;
1969 fBlitter->blitMask(rowMask, rowMask.fBounds);
1970 src = (const void*)((const char*)src + srcRB);
1971 } while (++y < localStopY);
1972 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00001973}
1974
1975const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1976 return NULL;
1977}
1978