blob: dd388950a9afcf57ebc66863b3d0c2cf17c037f4 [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
172static size_t compute_row_length(const uint8_t row[], int width) {
173 const uint8_t* origRow = row;
174 while (width > 0) {
175 int n = row[0];
176 SkASSERT(n <= width);
177 row += 2;
178 width -= n;
179 }
180 SkASSERT(0 == width);
181 return row - origRow;
182}
183
184void SkAAClip::validate() const {
185 if (NULL == fRunHead) {
186 SkASSERT(fBounds.isEmpty());
187 return;
188 }
189
190 const RunHead* head = fRunHead;
191 SkASSERT(head->fRefCnt > 0);
192 SkASSERT(head->fRowCount > 0);
193 SkASSERT(head->fDataSize > 0);
194
195 const YOffset* yoff = head->yoffsets();
196 const YOffset* ystop = yoff + head->fRowCount;
197 const uint8_t* row = head->data();
198 SkASSERT(0 == yoff->fOffset);
199 // y values must be monotonic
200 int y = -1;
201 int32_t offset = -1;
202 size_t computedOffset = 0;
203 while (yoff < ystop) {
204 SkASSERT(y < yoff->fY);
205 y = yoff->fY;
206 SkASSERT(offset < (int32_t)yoff->fOffset);
207 offset = yoff->fOffset;
208 SkASSERT(yoff->fOffset == computedOffset);
209 yoff += 1;
210
211 size_t rowLength = compute_row_length(row, fBounds.width());
212 row += rowLength;
213 computedOffset += rowLength;
214 }
215 SkASSERT(head->fDataSize == computedOffset);
216 // check the last entry;
217 --yoff;
218 SkASSERT(yoff->fY == fBounds.height() - 1);
219
220}
221#endif
222
223///////////////////////////////////////////////////////////////////////////////
224
225// can't validate before we're done, since trimming is part of the process of
226// making us valid after the Builder. Since we build from top to bottom, its
227// possible our fBounds.fBottom is bigger than our last scanline of data, so
228// we trim fBounds.fBottom back up.
229//
230// TODO: look to trim our bounds on top, left, right.
231// TODO: check for duplicates in X and Y to further compress our data
232//
233bool SkAAClip::trimBounds() {
234 if (this->isEmpty()) {
235 return false;
236 }
237
238 const RunHead* head = fRunHead;
239 const YOffset* yoff = head->yoffsets();
240
241 SkASSERT(head->fRowCount > 0);
242 const YOffset& lastY = yoff[head->fRowCount - 1];
243 SkASSERT(lastY.fY + 1 <= fBounds.height());
244 fBounds.fBottom = fBounds.fTop + lastY.fY + 1;
245 SkASSERT(lastY.fY + 1 == fBounds.height());
246 return true;
247}
248
reed@google.come36707a2011-10-04 21:38:55 +0000249///////////////////////////////////////////////////////////////////////////////
250
251void SkAAClip::freeRuns() {
reed@google.com47ac84e2011-10-06 13:11:25 +0000252 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000253 SkASSERT(fRunHead->fRefCnt >= 1);
254 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
255 sk_free(fRunHead);
256 }
257 }
258}
259
260SkAAClip::SkAAClip() {
261 fBounds.setEmpty();
reed@google.com47ac84e2011-10-06 13:11:25 +0000262 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000263}
264
265SkAAClip::SkAAClip(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000266 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate
reed@google.com47ac84e2011-10-06 13:11:25 +0000267 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000268 *this = src;
269}
270
271SkAAClip::~SkAAClip() {
272 this->freeRuns();
273}
274
275SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
reed@google.com045e62d2011-10-24 12:19:46 +0000276 AUTO_AACLIP_VALIDATE(*this);
277 src.validate();
278
reed@google.come36707a2011-10-04 21:38:55 +0000279 if (this != &src) {
280 this->freeRuns();
281 fBounds = src.fBounds;
282 fRunHead = src.fRunHead;
reed@google.com47ac84e2011-10-06 13:11:25 +0000283 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000284 sk_atomic_inc(&fRunHead->fRefCnt);
285 }
286 }
287 return *this;
288}
289
290bool operator==(const SkAAClip& a, const SkAAClip& b) {
reed@google.com045e62d2011-10-24 12:19:46 +0000291 a.validate();
292 b.validate();
293
reed@google.come36707a2011-10-04 21:38:55 +0000294 if (&a == &b) {
295 return true;
296 }
297 if (a.fBounds != b.fBounds) {
298 return false;
299 }
300
301 const SkAAClip::RunHead* ah = a.fRunHead;
302 const SkAAClip::RunHead* bh = b.fRunHead;
303
304 // this catches empties and rects being equal
305 if (ah == bh) {
306 return true;
307 }
308
309 // now we insist that both are complex (but different ptrs)
reed@google.com47ac84e2011-10-06 13:11:25 +0000310 if (!a.fRunHead || !b.fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000311 return false;
312 }
313
314 return ah->fRowCount == bh->fRowCount &&
315 ah->fDataSize == bh->fDataSize &&
316 !memcmp(ah->data(), bh->data(), ah->fDataSize);
317}
318
319void SkAAClip::swap(SkAAClip& other) {
reed@google.com045e62d2011-10-24 12:19:46 +0000320 AUTO_AACLIP_VALIDATE(*this);
321 other.validate();
322
reed@google.come36707a2011-10-04 21:38:55 +0000323 SkTSwap(fBounds, other.fBounds);
324 SkTSwap(fRunHead, other.fRunHead);
325}
326
reed@google.com32287892011-10-05 16:27:44 +0000327bool SkAAClip::set(const SkAAClip& src) {
328 *this = src;
329 return !this->isEmpty();
330}
331
reed@google.come36707a2011-10-04 21:38:55 +0000332bool SkAAClip::setEmpty() {
333 this->freeRuns();
334 fBounds.setEmpty();
reed@google.com47ac84e2011-10-06 13:11:25 +0000335 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000336 return false;
337}
338
339bool SkAAClip::setRect(const SkIRect& bounds) {
340 if (bounds.isEmpty()) {
341 return this->setEmpty();
342 }
reed@google.com47ac84e2011-10-06 13:11:25 +0000343
reed@google.com045e62d2011-10-24 12:19:46 +0000344 AUTO_AACLIP_VALIDATE(*this);
reed@google.com47ac84e2011-10-06 13:11:25 +0000345
reed@google.com045e62d2011-10-24 12:19:46 +0000346#if 0
reed@google.com47ac84e2011-10-06 13:11:25 +0000347 SkRect r;
348 r.set(bounds);
349 SkPath path;
350 path.addRect(r);
351 return this->setPath(path);
reed@google.com045e62d2011-10-24 12:19:46 +0000352#else
353 this->freeRuns();
354 fBounds = bounds;
355 fRunHead = RunHead::AllocRect(bounds);
356 SkASSERT(!this->isEmpty());
357 return true;
358#endif
reed@google.come36707a2011-10-04 21:38:55 +0000359}
360
reed@google.comf3c1da12011-10-10 19:35:47 +0000361bool SkAAClip::setRect(const SkRect& r, bool doAA) {
reed@google.come36707a2011-10-04 21:38:55 +0000362 if (r.isEmpty()) {
363 return this->setEmpty();
364 }
365
reed@google.com045e62d2011-10-24 12:19:46 +0000366 AUTO_AACLIP_VALIDATE(*this);
367
368 // TODO: special case this
369
reed@google.come36707a2011-10-04 21:38:55 +0000370 SkPath path;
371 path.addRect(r);
reed@google.comf3c1da12011-10-10 19:35:47 +0000372 return this->setPath(path, NULL, doAA);
373}
374
375bool SkAAClip::setRegion(const SkRegion& rgn) {
376 if (rgn.isEmpty()) {
377 return this->setEmpty();
378 }
379 if (rgn.isRect()) {
380 return this->setRect(rgn.getBounds());
381 }
382
383 SkAAClip clip;
384 SkRegion::Iterator iter(rgn);
385 for (; !iter.done(); iter.next()) {
386 clip.op(iter.rect(), SkRegion::kUnion_Op);
387 }
388 this->swap(clip);
reed@google.com3771a032011-10-11 17:18:04 +0000389 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000390}
391
392///////////////////////////////////////////////////////////////////////////////
393
394const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000395 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000396
397 if (!y_in_rect(y, fBounds)) {
398 return NULL;
399 }
400 y -= fBounds.y(); // our yoffs values are relative to the top
401
402 const YOffset* yoff = fRunHead->yoffsets();
403 while (yoff->fY < y) {
404 yoff += 1;
405 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
406 }
407
408 if (lastYForRow) {
reed@google.com045e62d2011-10-24 12:19:46 +0000409 *lastYForRow = fBounds.y() + yoff->fY;
reed@google.come36707a2011-10-04 21:38:55 +0000410 }
411 return fRunHead->data() + yoff->fOffset;
412}
413
414const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
415 SkASSERT(x_in_rect(x, fBounds));
416 x -= fBounds.x();
417
418 // first skip up to X
419 for (;;) {
420 int n = data[0];
421 if (x < n) {
422 *initialCount = n - x;
423 break;
424 }
425 data += 2;
426 x -= n;
427 }
428 return data;
429}
430
431bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
432 if (this->isEmpty()) {
433 return false;
434 }
435 if (!fBounds.contains(left, top, right, bottom)) {
436 return false;
437 }
reed@google.com32287892011-10-05 16:27:44 +0000438#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000439 if (this->isRect()) {
440 return true;
441 }
reed@google.com32287892011-10-05 16:27:44 +0000442#endif
reed@google.come36707a2011-10-04 21:38:55 +0000443
444 int lastY;
445 const uint8_t* row = this->findRow(top, &lastY);
446 if (lastY < bottom) {
447 return false;
448 }
449 // now just need to check in X
reed@google.com045e62d2011-10-24 12:19:46 +0000450 int count;
451 row = this->findX(row, left, &count);
452#if 0
453 return count >= (right - left) && 0xFF == row[1];
454#else
455 int rectWidth = right - left;
456 while (0xFF == row[1]) {
457 if (count >= rectWidth) {
458 return true;
459 }
460 rectWidth -= count;
461 row += 2;
462 count = row[0];
463 }
464 return false;
465#endif
reed@google.come36707a2011-10-04 21:38:55 +0000466}
467
468///////////////////////////////////////////////////////////////////////////////
469
470class SkAAClip::Builder {
471 SkIRect fBounds;
472 struct Row {
473 int fY;
474 int fWidth;
475 SkTDArray<uint8_t>* fData;
476 };
477 SkTDArray<Row> fRows;
478 Row* fCurrRow;
479 int fPrevY;
480 int fWidth;
481
482public:
483 Builder(const SkIRect& bounds) : fBounds(bounds) {
484 fPrevY = -1;
485 fWidth = bounds.width();
486 fCurrRow = NULL;
487 }
488
489 ~Builder() {
490 Row* row = fRows.begin();
491 Row* stop = fRows.end();
492 while (row < stop) {
493 delete row->fData;
494 row += 1;
495 }
496 }
497
reed@google.com32287892011-10-05 16:27:44 +0000498 const SkIRect& getBounds() const { return fBounds; }
499
reed@google.come36707a2011-10-04 21:38:55 +0000500 void addRun(int x, int y, U8CPU alpha, int count) {
501 SkASSERT(count > 0);
502 SkASSERT(fBounds.contains(x, y));
503 SkASSERT(fBounds.contains(x + count - 1, y));
504
505 x -= fBounds.left();
506 y -= fBounds.top();
507
508 Row* row = fCurrRow;
509 if (y != fPrevY) {
510 SkASSERT(y > fPrevY);
511 fPrevY = y;
512 row = this->flushRow(true);
513 row->fY = y;
514 row->fWidth = 0;
515 SkASSERT(row->fData);
516 SkASSERT(0 == row->fData->count());
517 fCurrRow = row;
518 }
519
520 SkASSERT(row->fWidth <= x);
521 SkASSERT(row->fWidth < fBounds.width());
522
523 SkTDArray<uint8_t>& data = *row->fData;
524
525 int gap = x - row->fWidth;
526 if (gap) {
527 AppendRun(data, 0, gap);
528 row->fWidth += gap;
529 SkASSERT(row->fWidth < fBounds.width());
530 }
531
532 AppendRun(data, alpha, count);
533 row->fWidth += count;
534 SkASSERT(row->fWidth <= fBounds.width());
535 }
536
reed@google.com045e62d2011-10-24 12:19:46 +0000537 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +0000538 this->flushRow(false);
539
540 const Row* row = fRows.begin();
541 const Row* stop = fRows.end();
542
543 size_t dataSize = 0;
544 while (row < stop) {
545 dataSize += row->fData->count();
546 row += 1;
547 }
548
reed@google.com045e62d2011-10-24 12:19:46 +0000549 if (0 == dataSize) {
550 return target->setEmpty();
551 }
552
reed@google.come36707a2011-10-04 21:38:55 +0000553 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
554 YOffset* yoffset = head->yoffsets();
555 uint8_t* data = head->data();
556 uint8_t* baseData = data;
557
558 row = fRows.begin();
559 while (row < stop) {
560 yoffset->fY = row->fY;
561 yoffset->fOffset = data - baseData;
562 yoffset += 1;
563
564 size_t n = row->fData->count();
565 memcpy(data, row->fData->begin(), n);
566 data += n;
567
568 row += 1;
569 }
570
reed@google.com045e62d2011-10-24 12:19:46 +0000571 target->freeRuns();
572 target->fBounds = fBounds;
573 target->fRunHead = head;
574 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +0000575 }
576
577 void dump() {
578 this->validate();
579 int y;
580 for (y = 0; y < fRows.count(); ++y) {
581 const Row& row = fRows[y];
582 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
583 const SkTDArray<uint8_t>& data = *row.fData;
584 int count = data.count();
585 SkASSERT(!(count & 1));
586 const uint8_t* ptr = data.begin();
587 for (int x = 0; x < count; x += 2) {
588 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
589 ptr += 2;
590 }
591 SkDebugf("\n");
592 }
reed@google.come36707a2011-10-04 21:38:55 +0000593 }
594
595 void validate() {
596#ifdef SK_DEBUG
597 int prevY = -1;
598 for (int i = 0; i < fRows.count(); ++i) {
599 const Row& row = fRows[i];
600 SkASSERT(prevY < row.fY);
601 SkASSERT(fWidth == row.fWidth);
602 int count = row.fData->count();
603 const uint8_t* ptr = row.fData->begin();
604 SkASSERT(!(count & 1));
605 int w = 0;
606 for (int x = 0; x < count; x += 2) {
607 w += ptr[0];
608 SkASSERT(w <= fWidth);
609 ptr += 2;
610 }
611 SkASSERT(w == fWidth);
612 prevY = row.fY;
613 }
614#endif
615 }
616
617private:
618 Row* flushRow(bool readyForAnother) {
619 Row* next = NULL;
620 int count = fRows.count();
621 if (count > 0) {
622 // flush current row if needed
623 Row* curr = &fRows[count - 1];
624 if (curr->fWidth < fWidth) {
625 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
reed@google.com045e62d2011-10-24 12:19:46 +0000626 curr->fWidth = fWidth;
reed@google.come36707a2011-10-04 21:38:55 +0000627 }
628 }
629 if (count > 1) {
630 // are our last two runs the same?
631 Row* prev = &fRows[count - 2];
632 Row* curr = &fRows[count - 1];
633 SkASSERT(prev->fWidth == fWidth);
634 SkASSERT(curr->fWidth == fWidth);
635 if (*prev->fData == *curr->fData) {
636 prev->fY = curr->fY;
637 if (readyForAnother) {
638 curr->fData->rewind();
639 next = curr;
640 } else {
641 delete curr->fData;
642 fRows.removeShuffle(count - 1);
643 }
644 } else {
645 if (readyForAnother) {
646 next = fRows.append();
647 next->fData = new SkTDArray<uint8_t>;
648 }
649 }
650 } else {
651 if (readyForAnother) {
652 next = fRows.append();
653 next->fData = new SkTDArray<uint8_t>;
654 }
655 }
656 return next;
657 }
658
659 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
660 do {
661 int n = count;
662 if (n > 255) {
663 n = 255;
664 }
665 uint8_t* ptr = data.append(2);
666 ptr[0] = n;
667 ptr[1] = alpha;
668 count -= n;
669 } while (count > 0);
670 }
671};
672
673class SkAAClip::BuilderBlitter : public SkBlitter {
674public:
675 BuilderBlitter(Builder* builder) {
676 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +0000677 fLeft = builder->getBounds().fLeft;
678 fRight = builder->getBounds().fRight;
reed@google.come36707a2011-10-04 21:38:55 +0000679 }
680
681 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
682 { unexpected(); }
reed@google.com045e62d2011-10-24 12:19:46 +0000683
684 // let the default impl call blitH
685// virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
686
reed@google.come36707a2011-10-04 21:38:55 +0000687 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
688 { unexpected(); }
689
690 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +0000691 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000692 }
693
694 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
695 fBuilder->addRun(x, y, 0xFF, width);
696 }
697
698 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
699 const int16_t runs[]) SK_OVERRIDE {
700 for (;;) {
701 int count = *runs;
702 if (count <= 0) {
703 return;
704 }
reed@google.com17785642011-10-12 20:23:55 +0000705
706 // The supersampler's buffer can be the width of the device, so
707 // we may have to trim the run to our bounds. If so, we assert that
708 // the extra spans are always alpha==0
709 int localX = x;
710 int localCount = count;
711 if (x < fLeft) {
712 SkASSERT(0 == *alpha);
713 int gap = fLeft - x;
714 SkASSERT(gap <= count);
715 localX += gap;
716 localCount -= gap;
717 }
718 int right = x + count;
719 if (right > fRight) {
720 SkASSERT(0 == *alpha);
721 localCount -= right - fRight;
722 SkASSERT(localCount >= 0);
723 }
724
725 if (localCount) {
726 fBuilder->addRun(localX, y, *alpha, localCount);
727 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +0000728 // Next run
reed@google.come36707a2011-10-04 21:38:55 +0000729 runs += count;
730 alpha += count;
731 x += count;
732 }
733 }
734
735private:
736 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +0000737 int fLeft; // cache of builder's bounds' left edge
738 int fRight;
reed@google.come36707a2011-10-04 21:38:55 +0000739
740 void unexpected() {
741 SkDebugf("---- did not expect to get called here");
742 sk_throw();
743 }
744};
745
reed@google.comf3c1da12011-10-10 19:35:47 +0000746bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000747 AUTO_AACLIP_VALIDATE(*this);
748
reed@google.com32287892011-10-05 16:27:44 +0000749 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000750 return this->setEmpty();
751 }
752
753 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +0000754 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +0000755
reed@google.com32287892011-10-05 16:27:44 +0000756 SkRegion tmpClip;
757 if (NULL == clip) {
758 tmpClip.setRect(ibounds);
759 clip = &tmpClip;
760 }
761
reed@google.com045e62d2011-10-24 12:19:46 +0000762 if (path.isInverseFillType()) {
763 ibounds = clip->getBounds();
764 } else {
reed@google.com32287892011-10-05 16:27:44 +0000765 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +0000766 return this->setEmpty();
767 }
reed@google.come36707a2011-10-04 21:38:55 +0000768 }
769
770 Builder builder(ibounds);
771 BuilderBlitter blitter(&builder);
772
reed@google.comf3c1da12011-10-10 19:35:47 +0000773 if (doAA) {
774 SkScan::AntiFillPath(path, *clip, &blitter, true);
775 } else {
776 SkScan::FillPath(path, *clip, &blitter);
777 }
reed@google.come36707a2011-10-04 21:38:55 +0000778
reed@google.com045e62d2011-10-24 12:19:46 +0000779 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +0000780}
781
782///////////////////////////////////////////////////////////////////////////////
783
reed@google.com32287892011-10-05 16:27:44 +0000784typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
785 const uint8_t* rowA, const SkIRect& rectA,
786 const uint8_t* rowB, const SkIRect& rectB);
787
788static void sectRowProc(SkAAClip::Builder& builder, int bottom,
789 const uint8_t* rowA, const SkIRect& rectA,
790 const uint8_t* rowB, const SkIRect& rectB) {
791
792}
793
794typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
795
796static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
797 // Multiply
798 return SkMulDiv255Round(alphaA, alphaB);
799}
800
801static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
802 // SrcOver
803 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
804}
805
806static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
807 // SrcOut
808 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
809}
810
811static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
812 // XOR
813 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
814}
815
816static AlphaProc find_alpha_proc(SkRegion::Op op) {
817 switch (op) {
818 case SkRegion::kIntersect_Op:
819 return sectAlphaProc;
820 case SkRegion::kDifference_Op:
821 return diffAlphaProc;
822 case SkRegion::kUnion_Op:
823 return unionAlphaProc;
824 case SkRegion::kXOR_Op:
825 return xorAlphaProc;
826 default:
827 SkASSERT(!"unexpected region op");
828 return sectAlphaProc;
829 }
830}
831
832static const uint8_t gEmptyRow[] = {
833 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
834 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
835 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
836 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
837 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
838 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
839 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
840 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
841};
842
843class RowIter {
844public:
845 RowIter(const uint8_t* row, const SkIRect& bounds) {
846 fRow = row;
847 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +0000848 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000849 if (row) {
850 fRight = bounds.fLeft + row[0];
851 SkASSERT(fRight <= fBoundsRight);
852 fAlpha = row[1];
853 fDone = false;
854 } else {
855 fDone = true;
856 fRight = kMaxInt32;
857 fAlpha = 0;
858 }
reed@google.com32287892011-10-05 16:27:44 +0000859 }
860
861 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000862 int left() const { return fLeft; }
863 int right() const { return fRight; }
864 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +0000865 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000866 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +0000867 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000868 if (fRight == fBoundsRight) {
869 fDone = true;
870 fRight = kMaxInt32;
871 fAlpha = 0;
872 } else {
873 fRow += 2;
874 fRight += fRow[0];
875 fAlpha = fRow[1];
876 SkASSERT(fRight <= fBoundsRight);
877 }
reed@google.com32287892011-10-05 16:27:44 +0000878 }
879 }
880
881private:
882 const uint8_t* fRow;
883 int fLeft;
884 int fRight;
885 int fBoundsRight;
886 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +0000887 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +0000888};
889
reed@google.com1c04bf92011-10-10 12:57:12 +0000890static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
891 if (rite == riteA) {
892 iter.next();
893 leftA = iter.left();
894 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +0000895 }
896}
897
reed@google.com1c04bf92011-10-10 12:57:12 +0000898static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
899 SkASSERT(min < max);
900 SkASSERT(boundsMin < boundsMax);
901 if (min >= boundsMax || max <= boundsMin) {
902 return false;
903 }
904 if (min < boundsMin) {
905 min = boundsMin;
906 }
907 if (max > boundsMax) {
908 max = boundsMax;
909 }
910 return true;
911}
912
reed@google.com32287892011-10-05 16:27:44 +0000913static void operatorX(SkAAClip::Builder& builder, int lastY,
914 RowIter& iterA, RowIter& iterB,
915 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +0000916 int leftA = iterA.left();
917 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +0000918 int leftB = iterB.left();
919 int riteB = iterB.right();
920
reed@google.com1c04bf92011-10-10 12:57:12 +0000921 int prevRite = bounds.fLeft;
922
923 do {
reed@google.com32287892011-10-05 16:27:44 +0000924 U8CPU alphaA = 0;
925 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +0000926 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +0000927
928 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +0000929 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +0000930 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +0000931 if (riteA <= leftB) {
932 rite = riteA;
933 } else {
934 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +0000935 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000936 } else if (leftB < leftA) {
937 left = leftB;
938 alphaB = iterB.alpha();
939 if (riteB <= leftA) {
940 rite = riteB;
941 } else {
942 rite = leftB = leftA;
943 }
944 } else {
945 left = leftA; // or leftB, since leftA == leftB
946 rite = leftA = leftB = SkMin32(riteA, riteB);
947 alphaA = iterA.alpha();
948 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +0000949 }
950
951 if (left >= bounds.fRight) {
952 break;
953 }
reed@google.com34f7e472011-10-13 15:11:59 +0000954 if (rite > bounds.fRight) {
955 rite = bounds.fRight;
956 }
957
reed@google.com32287892011-10-05 16:27:44 +0000958 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +0000959 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +0000960 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +0000961 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +0000962 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000963
964 adjust_row(iterA, leftA, riteA, rite);
965 adjust_row(iterB, leftB, riteB, rite);
966 } while (!iterA.done() || !iterB.done());
967
968 if (prevRite < bounds.fRight) {
969 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +0000970 }
971}
972
reed@google.com1c04bf92011-10-10 12:57:12 +0000973static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
974 if (bot == botA) {
975 iter.next();
976 topA = botA;
977 SkASSERT(botA == iter.top());
978 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +0000979 }
980}
981
982static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
983 const SkAAClip& B, SkRegion::Op op) {
984 AlphaProc proc = find_alpha_proc(op);
985 const SkIRect& bounds = builder.getBounds();
986
987 SkAAClip::Iter iterA(A);
988 SkAAClip::Iter iterB(B);
989
990 SkASSERT(!iterA.done());
991 int topA = iterA.top();
992 int botA = iterA.bottom();
993 SkASSERT(!iterB.done());
994 int topB = iterB.top();
995 int botB = iterB.bottom();
996
reed@google.com1c04bf92011-10-10 12:57:12 +0000997 do {
998 const uint8_t* rowA = NULL;
999 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001000 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001001
1002 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001003 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001004 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001005 if (botA <= topB) {
1006 bot = botA;
1007 } else {
1008 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001009 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001010
1011 } else if (topB < topA) {
1012 top = topB;
1013 rowB = iterB.data();
1014 if (botB <= topA) {
1015 bot = botB;
1016 } else {
1017 bot = topB = topA;
1018 }
1019 } else {
1020 top = topA; // or topB, since topA == topB
1021 bot = topA = topB = SkMin32(botA, botB);
1022 rowA = iterA.data();
1023 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001024 }
1025
1026 if (top >= bounds.fBottom) {
1027 break;
1028 }
reed@google.com34f7e472011-10-13 15:11:59 +00001029
1030 if (bot > bounds.fBottom) {
1031 bot = bounds.fBottom;
1032 }
1033 SkASSERT(top < bot);
1034
reed@google.com1c04bf92011-10-10 12:57:12 +00001035 if (!rowA && !rowB) {
1036 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1037 } else if (top >= bounds.fTop) {
1038 SkASSERT(bot <= bounds.fBottom);
1039 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1040 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001041 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001042 }
1043
reed@google.com1c04bf92011-10-10 12:57:12 +00001044 adjust_iter(iterA, topA, botA, bot);
1045 adjust_iter(iterB, topB, botB, bot);
1046 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001047}
1048
1049bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1050 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001051 AUTO_AACLIP_VALIDATE(*this);
1052
reed@google.com32287892011-10-05 16:27:44 +00001053 if (SkRegion::kReplace_Op == op) {
1054 return this->set(clipBOrig);
1055 }
1056
1057 const SkAAClip* clipA = &clipAOrig;
1058 const SkAAClip* clipB = &clipBOrig;
1059
1060 if (SkRegion::kReverseDifference_Op == op) {
1061 SkTSwap(clipA, clipB);
1062 op = SkRegion::kDifference_Op;
1063 }
1064
1065 bool a_empty = clipA->isEmpty();
1066 bool b_empty = clipB->isEmpty();
1067
1068 SkIRect bounds;
1069 switch (op) {
1070 case SkRegion::kDifference_Op:
1071 if (a_empty) {
1072 return this->setEmpty();
1073 }
1074 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1075 return this->set(*clipA);
1076 }
1077 bounds = clipA->fBounds;
1078 break;
1079
1080 case SkRegion::kIntersect_Op:
1081 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1082 clipB->fBounds)) {
1083 return this->setEmpty();
1084 }
1085 break;
1086
1087 case SkRegion::kUnion_Op:
1088 case SkRegion::kXOR_Op:
1089 if (a_empty) {
1090 return this->set(*clipB);
1091 }
1092 if (b_empty) {
1093 return this->set(*clipA);
1094 }
1095 bounds = clipA->fBounds;
1096 bounds.join(clipB->fBounds);
1097 break;
1098
1099 default:
1100 SkASSERT(!"unknown region op");
1101 return !this->isEmpty();
1102 }
1103
reed@google.com32287892011-10-05 16:27:44 +00001104 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1105 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1106
1107 Builder builder(bounds);
1108 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001109
1110 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001111}
1112
reed@google.com045e62d2011-10-24 12:19:46 +00001113/*
1114 * It can be expensive to build a local aaclip before applying the op, so
1115 * we first see if we can restrict the bounds of new rect to our current
1116 * bounds, or note that the new rect subsumes our current clip.
1117 */
1118
1119bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1120 SkIRect rStorage;
1121 const SkIRect* r = &rOrig;
1122
1123 switch (op) {
1124 case SkRegion::kIntersect_Op:
1125 if (!rStorage.intersect(rOrig, fBounds)) {
1126 // no overlap, so we're empty
1127 return this->setEmpty();
1128 }
1129 if (rStorage == fBounds) {
1130 // we were wholly inside the rect, no change
1131 return !this->isEmpty();
1132 }
1133 if (this->quickContains(rStorage)) {
1134 // the intersection is wholly inside us, we're a rect
1135 return this->setRect(rStorage);
1136 }
1137 r = &rStorage; // use the intersected bounds
1138 break;
1139 case SkRegion::kDifference_Op:
1140 break;
1141 case SkRegion::kUnion_Op:
1142 if (rOrig.contains(fBounds)) {
1143 return this->setRect(rOrig);
1144 }
1145 break;
1146 default:
1147 break;
1148 }
1149
reed@google.com47ac84e2011-10-06 13:11:25 +00001150 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001151 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001152 return this->op(*this, clip, op);
1153}
1154
reed@google.com045e62d2011-10-24 12:19:46 +00001155bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1156 SkRect rStorage, boundsStorage;
1157 const SkRect* r = &rOrig;
1158
1159 boundsStorage.set(fBounds);
1160 switch (op) {
1161 case SkRegion::kIntersect_Op:
1162 case SkRegion::kDifference_Op:
1163 if (!rStorage.intersect(rOrig, boundsStorage)) {
1164 return this->setEmpty();
1165 }
1166 r = &rStorage; // use the intersected bounds
1167 break;
1168 case SkRegion::kUnion_Op:
1169 if (rOrig.contains(boundsStorage)) {
1170 return this->setRect(rOrig);
1171 }
1172 break;
1173 default:
1174 break;
1175 }
1176
reed@google.com47ac84e2011-10-06 13:11:25 +00001177 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001178 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001179 return this->op(*this, clip, op);
1180}
1181
1182bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1183 return this->op(*this, clip, op);
1184}
1185
reed@google.come36707a2011-10-04 21:38:55 +00001186///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001187
1188bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1189 if (NULL == dst) {
1190 return !this->isEmpty();
1191 }
1192
1193 if (this->isEmpty()) {
1194 return dst->setEmpty();
1195 }
1196
1197 if (this != dst) {
1198 sk_atomic_inc(&fRunHead->fRefCnt);
1199 dst->fRunHead = fRunHead;
1200 dst->fBounds = fBounds;
1201 }
1202 dst->fBounds.offset(dx, dy);
1203 return true;
1204}
1205
1206static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1207 const uint8_t* SK_RESTRICT row,
1208 int width) {
1209 while (width > 0) {
1210 int n = row[0];
1211 SkASSERT(width >= n);
1212 memset(mask, row[1], n);
1213 mask += n;
1214 row += 2;
1215 width -= n;
1216 }
1217}
1218
1219void SkAAClip::copyToMask(SkMask* mask) const {
1220 mask->fFormat = SkMask::kA8_Format;
1221 if (this->isEmpty()) {
1222 mask->fBounds.setEmpty();
1223 mask->fImage = NULL;
1224 mask->fRowBytes = 0;
1225 return;
1226 }
1227
1228 mask->fBounds = fBounds;
1229 mask->fRowBytes = fBounds.width();
1230 size_t size = mask->computeImageSize();
1231 mask->fImage = SkMask::AllocImage(size);
1232
1233 Iter iter(*this);
1234 uint8_t* dst = mask->fImage;
1235 const int width = fBounds.width();
1236
1237 int y = fBounds.fTop;
1238 while (!iter.done()) {
1239 do {
1240 expand_row_to_mask(dst, iter.data(), width);
1241 dst += mask->fRowBytes;
1242 } while (++y < iter.bottom());
1243 iter.next();
1244 }
1245}
1246
1247///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001248///////////////////////////////////////////////////////////////////////////////
1249
1250static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1251 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1252 // we don't read our initial n from data, since the caller may have had to
1253 // clip it, hence the initialCount parameter.
1254 int n = initialCount;
1255 for (;;) {
1256 if (n > width) {
1257 n = width;
1258 }
1259 SkASSERT(n > 0);
1260 runs[0] = n;
1261 runs += n;
1262
1263 aa[0] = data[1];
1264 aa += n;
1265
1266 data += 2;
1267 width -= n;
1268 if (0 == width) {
1269 break;
1270 }
1271 // load the next count
1272 n = data[0];
1273 }
1274 runs[0] = 0; // sentinel
1275}
1276
1277SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001278 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001279}
1280
1281void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001282 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001283 // add 1 so we can store the terminating run count of 0
1284 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001285 // we use this either for fRuns + fAA, or a scaline of a mask
1286 // which may be as deep as 32bits
1287 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1288 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001289 fAA = (SkAlpha*)(fRuns + count);
1290 }
1291}
1292
1293void SkAAClipBlitter::blitH(int x, int y, int width) {
1294 SkASSERT(width > 0);
1295 SkASSERT(fAAClipBounds.contains(x, y));
1296 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1297
1298 int lastY;
1299 const uint8_t* row = fAAClip->findRow(y, &lastY);
1300 int initialCount;
1301 row = fAAClip->findX(row, x, &initialCount);
1302
1303 if (initialCount >= width) {
1304 SkAlpha alpha = row[1];
1305 if (0 == alpha) {
1306 return;
1307 }
1308 if (0xFF == alpha) {
1309 fBlitter->blitH(x, y, width);
1310 return;
1311 }
1312 }
1313
1314 this->ensureRunsAndAA();
1315 expandToRuns(row, initialCount, width, fRuns, fAA);
1316
1317 fBlitter->blitAntiH(x, y, fAA, fRuns);
1318}
1319
1320static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1321 const SkAlpha* SK_RESTRICT srcAA,
1322 const int16_t* SK_RESTRICT srcRuns,
1323 SkAlpha* SK_RESTRICT dstAA,
1324 int16_t* SK_RESTRICT dstRuns,
1325 int width) {
1326 SkDEBUGCODE(int accumulated = 0;)
1327 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001328 // do we need this check?
1329 if (0 == srcN) {
1330 return;
1331 }
1332
reed@google.come36707a2011-10-04 21:38:55 +00001333 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001334 SkASSERT(rowN > 0);
1335 SkASSERT(srcN > 0);
1336
1337 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1338 int minN = SkMin32(srcN, rowN);
1339 dstRuns[0] = minN;
1340 dstRuns += minN;
1341 dstAA[0] = newAlpha;
1342 dstAA += minN;
1343
1344 if (0 == (srcN -= minN)) {
1345 srcN = srcRuns[0]; // refresh
1346 srcRuns += srcN;
1347 srcAA += srcN;
1348 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001349 if (0 == srcN) {
1350 break;
1351 }
reed@google.come36707a2011-10-04 21:38:55 +00001352 }
1353 if (0 == (rowN -= minN)) {
1354 row += 2;
1355 rowN = row[0]; // reload
1356 }
1357
1358 SkDEBUGCODE(accumulated += minN;)
1359 SkASSERT(accumulated <= width);
1360 }
reed@google.com34f7e472011-10-13 15:11:59 +00001361 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001362}
1363
1364void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1365 const int16_t runs[]) {
1366 int lastY;
1367 const uint8_t* row = fAAClip->findRow(y, &lastY);
1368 int initialCount;
1369 row = fAAClip->findX(row, x, &initialCount);
1370
1371 this->ensureRunsAndAA();
1372
1373 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1374 fBlitter->blitAntiH(x, y, fAA, fRuns);
1375}
1376
1377void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1378 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1379 fBlitter->blitV(x, y, height, alpha);
1380 return;
1381 }
1382
reed@google.com045e62d2011-10-24 12:19:46 +00001383 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001384 int lastY;
1385 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001386 int dy = lastY - y + 1;
1387 if (dy > height) {
1388 dy = height;
1389 }
1390 height -= dy;
1391
reed@google.come36707a2011-10-04 21:38:55 +00001392 int initialCount;
1393 row = fAAClip->findX(row, x, &initialCount);
1394 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1395 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001396 fBlitter->blitV(x, y, dy, newAlpha);
1397 }
1398 SkASSERT(height >= 0);
1399 if (height <= 0) {
1400 break;
reed@google.come36707a2011-10-04 21:38:55 +00001401 }
1402 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001403 }
reed@google.come36707a2011-10-04 21:38:55 +00001404}
1405
1406void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1407 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1408 fBlitter->blitRect(x, y, width, height);
1409 return;
1410 }
1411
1412 while (--height >= 0) {
1413 this->blitH(x, y, width);
1414 y += 1;
1415 }
1416}
1417
reed@google.com045e62d2011-10-24 12:19:46 +00001418typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1419 int initialRowCount, void* dst);
1420
1421static void small_memcpy(void* dst, const void* src, size_t n) {
1422 memcpy(dst, src, n);
1423}
1424
1425static void small_bzero(void* dst, size_t n) {
1426 sk_bzero(dst, n);
1427}
1428
1429static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1430 return SkMulDiv255Round(value, alpha);
1431}
1432static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1433 unsigned r = SkGetPackedR16(value);
1434 unsigned g = SkGetPackedG16(value);
1435 unsigned b = SkGetPackedB16(value);
1436 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1437 SkMulDiv255Round(r, alpha),
1438 SkMulDiv255Round(r, alpha));
1439}
1440static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1441 unsigned a = SkGetPackedA32(value);
1442 unsigned r = SkGetPackedR32(value);
1443 unsigned g = SkGetPackedG32(value);
1444 unsigned b = SkGetPackedB32(value);
1445 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1446 SkMulDiv255Round(r, alpha),
1447 SkMulDiv255Round(g, alpha),
1448 SkMulDiv255Round(b, alpha));
1449}
1450
1451template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1452 const uint8_t* SK_RESTRICT row, int rowN,
1453 T* SK_RESTRICT dst) {
1454 SkDEBUGCODE(int accumulated = 0;)
1455 for (;;) {
1456 SkASSERT(rowN > 0);
1457 SkASSERT(srcN > 0);
1458
1459 int n = SkMin32(rowN, srcN);
1460 unsigned rowA = row[1];
1461 if (0xFF == rowA) {
1462 small_memcpy(dst, src, n * sizeof(T));
1463 } else if (0 == rowA) {
1464 small_bzero(dst, n * sizeof(T));
1465 } else {
1466 for (int i = 0; i < n; ++i) {
1467 dst[i] = mergeOne(src[i], rowA);
1468 }
1469 }
1470
1471 if (0 == (srcN -= n)) {
1472 break;
1473 }
1474
1475 src += n;
1476 dst += n;
1477
1478 SkASSERT(rowN == n);
1479 row += 2;
1480 rowN = row[0];
1481 }
1482}
1483
1484static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
1485 switch (format) {
1486 case SkMask::kBW_Format:
1487 SkASSERT(!"unsupported");
1488 return NULL;
1489 case SkMask::kA8_Format:
1490 case SkMask::k3D_Format: {
1491 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
1492 return (MergeAAProc)proc8;
1493 }
1494 case SkMask::kLCD16_Format: {
1495 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
1496 return (MergeAAProc)proc16;
1497 }
1498 case SkMask::kLCD32_Format: {
1499 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
1500 return (MergeAAProc)proc32;
1501 }
1502 default:
1503 SkASSERT(!"unsupported");
1504 return NULL;
1505 }
1506}
1507
1508static U8CPU bit2byte(int bitInAByte) {
1509 SkASSERT(bitInAByte <= 0xFF);
1510 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
1511 // some value >= 8 to get a full FF value
1512 return -bitInAByte >> 8;
1513}
1514
1515static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
1516 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
1517 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
1518
1519 const int width = srcMask.fBounds.width();
1520 const int height = srcMask.fBounds.height();
1521
1522 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
1523 const size_t srcRB = srcMask.fRowBytes;
1524 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
1525 const size_t dstRB = dstMask->fRowBytes;
1526
1527 const int wholeBytes = width >> 3;
1528 const int leftOverBits = width & 7;
1529
1530 for (int y = 0; y < height; ++y) {
1531 uint8_t* SK_RESTRICT d = dst;
1532 for (int i = 0; i < wholeBytes; ++i) {
1533 int srcByte = src[i];
1534 d[0] = bit2byte(srcByte & (1 << 7));
1535 d[1] = bit2byte(srcByte & (1 << 6));
1536 d[2] = bit2byte(srcByte & (1 << 5));
1537 d[3] = bit2byte(srcByte & (1 << 4));
1538 d[4] = bit2byte(srcByte & (1 << 3));
1539 d[5] = bit2byte(srcByte & (1 << 2));
1540 d[6] = bit2byte(srcByte & (1 << 1));
1541 d[7] = bit2byte(srcByte & (1 << 0));
1542 d += 8;
1543 }
1544 if (leftOverBits) {
1545 int srcByte = src[wholeBytes];
1546 for (int x = 0; x < leftOverBits; ++x) {
1547 *d++ = bit2byte(srcByte & 0x80);
1548 srcByte <<= 1;
1549 }
1550 }
1551 src += srcRB;
1552 dst += dstRB;
1553 }
1554}
1555
1556void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
1557 SkASSERT(fAAClip->getBounds().contains(clip));
1558
1559 if (fAAClip->quickContains(clip)) {
1560 fBlitter->blitMask(origMask, clip);
1561 return;
1562 }
1563
1564 const SkMask* mask = &origMask;
1565
1566 // if we're BW, we need to upscale to A8 (ugh)
1567 SkMask grayMask;
1568 grayMask.fImage = NULL;
1569 if (SkMask::kBW_Format == origMask.fFormat) {
1570 grayMask.fFormat = SkMask::kA8_Format;
1571 grayMask.fBounds = origMask.fBounds;
1572 grayMask.fRowBytes = origMask.fBounds.width();
1573 size_t size = grayMask.computeImageSize();
1574 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
1575 SkAutoMalloc::kReuse_OnShrink);
1576
1577 upscaleBW2A8(&grayMask, origMask);
1578 mask = &grayMask;
1579 }
1580
1581 this->ensureRunsAndAA();
1582
1583 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
1584 // data into a temp block to support it better (ugh)
1585
1586 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
1587 const size_t srcRB = mask->fRowBytes;
1588 const int width = clip.width();
1589 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
1590
1591 SkMask rowMask;
1592 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
1593 rowMask.fBounds.fLeft = clip.fLeft;
1594 rowMask.fBounds.fRight = clip.fRight;
1595 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
1596 rowMask.fImage = (uint8_t*)fScanlineScratch;
1597
1598 int y = clip.fTop;
1599 const int stopY = y + clip.height();
1600
1601 do {
1602 int localStopY;
1603 const uint8_t* row = fAAClip->findRow(y, &localStopY);
1604 // findRow returns last Y, not stop, so we add 1
1605 localStopY = SkMin32(localStopY + 1, stopY);
1606
1607 int initialCount;
1608 row = fAAClip->findX(row, clip.fLeft, &initialCount);
1609 do {
1610 mergeProc(src, width, row, initialCount, rowMask.fImage);
1611 rowMask.fBounds.fTop = y;
1612 rowMask.fBounds.fBottom = y + 1;
1613 fBlitter->blitMask(rowMask, rowMask.fBounds);
1614 src = (const void*)((const char*)src + srcRB);
1615 } while (++y < localStopY);
1616 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00001617}
1618
1619const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1620 return NULL;
1621}
1622