blob: d9cc181f74f518f902362834873dc131e20321a5 [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;
reed@google.com209c4152011-10-26 15:03:48 +0000481 int fMinY;
reed@google.come36707a2011-10-04 21:38:55 +0000482
483public:
484 Builder(const SkIRect& bounds) : fBounds(bounds) {
485 fPrevY = -1;
486 fWidth = bounds.width();
487 fCurrRow = NULL;
reed@google.com209c4152011-10-26 15:03:48 +0000488 fMinY = bounds.fTop;
reed@google.come36707a2011-10-04 21:38:55 +0000489 }
490
491 ~Builder() {
492 Row* row = fRows.begin();
493 Row* stop = fRows.end();
494 while (row < stop) {
495 delete row->fData;
496 row += 1;
497 }
498 }
499
reed@google.com32287892011-10-05 16:27:44 +0000500 const SkIRect& getBounds() const { return fBounds; }
501
reed@google.come36707a2011-10-04 21:38:55 +0000502 void addRun(int x, int y, U8CPU alpha, int count) {
503 SkASSERT(count > 0);
504 SkASSERT(fBounds.contains(x, y));
505 SkASSERT(fBounds.contains(x + count - 1, y));
506
507 x -= fBounds.left();
508 y -= fBounds.top();
509
510 Row* row = fCurrRow;
511 if (y != fPrevY) {
512 SkASSERT(y > fPrevY);
513 fPrevY = y;
514 row = this->flushRow(true);
515 row->fY = y;
516 row->fWidth = 0;
517 SkASSERT(row->fData);
518 SkASSERT(0 == row->fData->count());
519 fCurrRow = row;
520 }
521
522 SkASSERT(row->fWidth <= x);
523 SkASSERT(row->fWidth < fBounds.width());
524
525 SkTDArray<uint8_t>& data = *row->fData;
526
527 int gap = x - row->fWidth;
528 if (gap) {
529 AppendRun(data, 0, gap);
530 row->fWidth += gap;
531 SkASSERT(row->fWidth < fBounds.width());
532 }
533
534 AppendRun(data, alpha, count);
535 row->fWidth += count;
536 SkASSERT(row->fWidth <= fBounds.width());
537 }
538
reed@google.com045e62d2011-10-24 12:19:46 +0000539 bool finish(SkAAClip* target) {
reed@google.come36707a2011-10-04 21:38:55 +0000540 this->flushRow(false);
541
542 const Row* row = fRows.begin();
543 const Row* stop = fRows.end();
544
545 size_t dataSize = 0;
546 while (row < stop) {
547 dataSize += row->fData->count();
548 row += 1;
549 }
550
reed@google.com045e62d2011-10-24 12:19:46 +0000551 if (0 == dataSize) {
552 return target->setEmpty();
553 }
554
reed@google.com209c4152011-10-26 15:03:48 +0000555 SkASSERT(fMinY >= fBounds.fTop);
556 SkASSERT(fMinY < fBounds.fBottom);
557 int adjustY = fMinY - fBounds.fTop;
558 fBounds.fTop = fMinY;
559
reed@google.come36707a2011-10-04 21:38:55 +0000560 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
561 YOffset* yoffset = head->yoffsets();
562 uint8_t* data = head->data();
563 uint8_t* baseData = data;
564
565 row = fRows.begin();
566 while (row < stop) {
reed@google.com209c4152011-10-26 15:03:48 +0000567 yoffset->fY = row->fY - adjustY;
reed@google.come36707a2011-10-04 21:38:55 +0000568 yoffset->fOffset = data - baseData;
569 yoffset += 1;
570
571 size_t n = row->fData->count();
572 memcpy(data, row->fData->begin(), n);
573 data += n;
574
575 row += 1;
576 }
577
reed@google.com045e62d2011-10-24 12:19:46 +0000578 target->freeRuns();
579 target->fBounds = fBounds;
580 target->fRunHead = head;
581 return target->trimBounds();
reed@google.come36707a2011-10-04 21:38:55 +0000582 }
583
584 void dump() {
585 this->validate();
586 int y;
587 for (y = 0; y < fRows.count(); ++y) {
588 const Row& row = fRows[y];
589 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
590 const SkTDArray<uint8_t>& data = *row.fData;
591 int count = data.count();
592 SkASSERT(!(count & 1));
593 const uint8_t* ptr = data.begin();
594 for (int x = 0; x < count; x += 2) {
595 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
596 ptr += 2;
597 }
598 SkDebugf("\n");
599 }
reed@google.come36707a2011-10-04 21:38:55 +0000600 }
601
602 void validate() {
603#ifdef SK_DEBUG
604 int prevY = -1;
605 for (int i = 0; i < fRows.count(); ++i) {
606 const Row& row = fRows[i];
607 SkASSERT(prevY < row.fY);
608 SkASSERT(fWidth == row.fWidth);
609 int count = row.fData->count();
610 const uint8_t* ptr = row.fData->begin();
611 SkASSERT(!(count & 1));
612 int w = 0;
613 for (int x = 0; x < count; x += 2) {
614 w += ptr[0];
615 SkASSERT(w <= fWidth);
616 ptr += 2;
617 }
618 SkASSERT(w == fWidth);
619 prevY = row.fY;
620 }
621#endif
622 }
623
reed@google.com209c4152011-10-26 15:03:48 +0000624 // only called by BuilderBlitter
625 void setMinY(int y) {
626 fMinY = y;
627 }
628
reed@google.come36707a2011-10-04 21:38:55 +0000629private:
reed@google.com209c4152011-10-26 15:03:48 +0000630
reed@google.come36707a2011-10-04 21:38:55 +0000631 Row* flushRow(bool readyForAnother) {
632 Row* next = NULL;
633 int count = fRows.count();
634 if (count > 0) {
635 // flush current row if needed
636 Row* curr = &fRows[count - 1];
637 if (curr->fWidth < fWidth) {
638 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
reed@google.com045e62d2011-10-24 12:19:46 +0000639 curr->fWidth = fWidth;
reed@google.come36707a2011-10-04 21:38:55 +0000640 }
641 }
642 if (count > 1) {
643 // are our last two runs the same?
644 Row* prev = &fRows[count - 2];
645 Row* curr = &fRows[count - 1];
646 SkASSERT(prev->fWidth == fWidth);
647 SkASSERT(curr->fWidth == fWidth);
648 if (*prev->fData == *curr->fData) {
649 prev->fY = curr->fY;
650 if (readyForAnother) {
651 curr->fData->rewind();
652 next = curr;
653 } else {
654 delete curr->fData;
655 fRows.removeShuffle(count - 1);
656 }
657 } else {
658 if (readyForAnother) {
659 next = fRows.append();
660 next->fData = new SkTDArray<uint8_t>;
661 }
662 }
663 } else {
664 if (readyForAnother) {
665 next = fRows.append();
666 next->fData = new SkTDArray<uint8_t>;
667 }
668 }
669 return next;
670 }
671
672 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
673 do {
674 int n = count;
675 if (n > 255) {
676 n = 255;
677 }
678 uint8_t* ptr = data.append(2);
679 ptr[0] = n;
680 ptr[1] = alpha;
681 count -= n;
682 } while (count > 0);
683 }
684};
685
686class SkAAClip::BuilderBlitter : public SkBlitter {
687public:
688 BuilderBlitter(Builder* builder) {
689 fBuilder = builder;
reed@google.com17785642011-10-12 20:23:55 +0000690 fLeft = builder->getBounds().fLeft;
691 fRight = builder->getBounds().fRight;
reed@google.com209c4152011-10-26 15:03:48 +0000692 fMinY = SK_MaxS32;
693 }
694
695 void finish() {
696 if (fMinY < SK_MaxS32) {
697 fBuilder->setMinY(fMinY);
698 }
reed@google.come36707a2011-10-04 21:38:55 +0000699 }
700
701 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
702 { unexpected(); }
reed@google.com045e62d2011-10-24 12:19:46 +0000703
704 // let the default impl call blitH
705// virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
706
reed@google.come36707a2011-10-04 21:38:55 +0000707 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
708 { unexpected(); }
709
710 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +0000711 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000712 }
713
714 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +0000715 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +0000716 fBuilder->addRun(x, y, 0xFF, width);
717 }
718
719 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
720 const int16_t runs[]) SK_OVERRIDE {
reed@google.com209c4152011-10-26 15:03:48 +0000721 this->recordMinY(y);
reed@google.come36707a2011-10-04 21:38:55 +0000722 for (;;) {
723 int count = *runs;
724 if (count <= 0) {
725 return;
726 }
reed@google.com17785642011-10-12 20:23:55 +0000727
728 // The supersampler's buffer can be the width of the device, so
729 // we may have to trim the run to our bounds. If so, we assert that
730 // the extra spans are always alpha==0
731 int localX = x;
732 int localCount = count;
733 if (x < fLeft) {
734 SkASSERT(0 == *alpha);
735 int gap = fLeft - x;
736 SkASSERT(gap <= count);
737 localX += gap;
738 localCount -= gap;
739 }
740 int right = x + count;
741 if (right > fRight) {
742 SkASSERT(0 == *alpha);
743 localCount -= right - fRight;
744 SkASSERT(localCount >= 0);
745 }
746
747 if (localCount) {
748 fBuilder->addRun(localX, y, *alpha, localCount);
749 }
bsalomon@google.com820e80a2011-10-24 21:09:40 +0000750 // Next run
reed@google.come36707a2011-10-04 21:38:55 +0000751 runs += count;
752 alpha += count;
753 x += count;
754 }
755 }
756
757private:
758 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +0000759 int fLeft; // cache of builder's bounds' left edge
760 int fRight;
reed@google.com209c4152011-10-26 15:03:48 +0000761 int fMinY;
762
763 /*
764 * We track this, in case the scan converter skipped some number of
765 * scanlines at the (relative to the bounds it was given). This allows
766 * the builder, during its finish, to trip its bounds down to the "real"
767 * top.
768 */
769 void recordMinY(int y) {
770 if (y < fMinY) {
771 fMinY = y;
772 }
773 }
reed@google.come36707a2011-10-04 21:38:55 +0000774
775 void unexpected() {
776 SkDebugf("---- did not expect to get called here");
777 sk_throw();
778 }
779};
780
reed@google.comf3c1da12011-10-10 19:35:47 +0000781bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com045e62d2011-10-24 12:19:46 +0000782 AUTO_AACLIP_VALIDATE(*this);
783
reed@google.com32287892011-10-05 16:27:44 +0000784 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000785 return this->setEmpty();
786 }
787
788 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +0000789 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +0000790
reed@google.com32287892011-10-05 16:27:44 +0000791 SkRegion tmpClip;
792 if (NULL == clip) {
793 tmpClip.setRect(ibounds);
794 clip = &tmpClip;
795 }
796
reed@google.com045e62d2011-10-24 12:19:46 +0000797 if (path.isInverseFillType()) {
798 ibounds = clip->getBounds();
799 } else {
reed@google.com32287892011-10-05 16:27:44 +0000800 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +0000801 return this->setEmpty();
802 }
reed@google.come36707a2011-10-04 21:38:55 +0000803 }
804
805 Builder builder(ibounds);
806 BuilderBlitter blitter(&builder);
807
reed@google.comf3c1da12011-10-10 19:35:47 +0000808 if (doAA) {
809 SkScan::AntiFillPath(path, *clip, &blitter, true);
810 } else {
811 SkScan::FillPath(path, *clip, &blitter);
812 }
reed@google.come36707a2011-10-04 21:38:55 +0000813
reed@google.com209c4152011-10-26 15:03:48 +0000814 blitter.finish();
reed@google.com045e62d2011-10-24 12:19:46 +0000815 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +0000816}
817
818///////////////////////////////////////////////////////////////////////////////
819
reed@google.com32287892011-10-05 16:27:44 +0000820typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
821 const uint8_t* rowA, const SkIRect& rectA,
822 const uint8_t* rowB, const SkIRect& rectB);
823
824static void sectRowProc(SkAAClip::Builder& builder, int bottom,
825 const uint8_t* rowA, const SkIRect& rectA,
826 const uint8_t* rowB, const SkIRect& rectB) {
827
828}
829
830typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
831
832static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
833 // Multiply
834 return SkMulDiv255Round(alphaA, alphaB);
835}
836
837static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
838 // SrcOver
839 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
840}
841
842static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
843 // SrcOut
844 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
845}
846
847static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
848 // XOR
849 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
850}
851
852static AlphaProc find_alpha_proc(SkRegion::Op op) {
853 switch (op) {
854 case SkRegion::kIntersect_Op:
855 return sectAlphaProc;
856 case SkRegion::kDifference_Op:
857 return diffAlphaProc;
858 case SkRegion::kUnion_Op:
859 return unionAlphaProc;
860 case SkRegion::kXOR_Op:
861 return xorAlphaProc;
862 default:
863 SkASSERT(!"unexpected region op");
864 return sectAlphaProc;
865 }
866}
867
868static const uint8_t gEmptyRow[] = {
869 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
870 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
871 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
872 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
873 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
874 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
875 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
876 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
877};
878
879class RowIter {
880public:
881 RowIter(const uint8_t* row, const SkIRect& bounds) {
882 fRow = row;
883 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +0000884 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000885 if (row) {
886 fRight = bounds.fLeft + row[0];
887 SkASSERT(fRight <= fBoundsRight);
888 fAlpha = row[1];
889 fDone = false;
890 } else {
891 fDone = true;
892 fRight = kMaxInt32;
893 fAlpha = 0;
894 }
reed@google.com32287892011-10-05 16:27:44 +0000895 }
896
897 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000898 int left() const { return fLeft; }
899 int right() const { return fRight; }
900 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +0000901 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000902 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +0000903 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000904 if (fRight == fBoundsRight) {
905 fDone = true;
906 fRight = kMaxInt32;
907 fAlpha = 0;
908 } else {
909 fRow += 2;
910 fRight += fRow[0];
911 fAlpha = fRow[1];
912 SkASSERT(fRight <= fBoundsRight);
913 }
reed@google.com32287892011-10-05 16:27:44 +0000914 }
915 }
916
917private:
918 const uint8_t* fRow;
919 int fLeft;
920 int fRight;
921 int fBoundsRight;
922 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +0000923 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +0000924};
925
reed@google.com1c04bf92011-10-10 12:57:12 +0000926static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
927 if (rite == riteA) {
928 iter.next();
929 leftA = iter.left();
930 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +0000931 }
932}
933
reed@google.com1c04bf92011-10-10 12:57:12 +0000934static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
935 SkASSERT(min < max);
936 SkASSERT(boundsMin < boundsMax);
937 if (min >= boundsMax || max <= boundsMin) {
938 return false;
939 }
940 if (min < boundsMin) {
941 min = boundsMin;
942 }
943 if (max > boundsMax) {
944 max = boundsMax;
945 }
946 return true;
947}
948
reed@google.com32287892011-10-05 16:27:44 +0000949static void operatorX(SkAAClip::Builder& builder, int lastY,
950 RowIter& iterA, RowIter& iterB,
951 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +0000952 int leftA = iterA.left();
953 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +0000954 int leftB = iterB.left();
955 int riteB = iterB.right();
956
reed@google.com1c04bf92011-10-10 12:57:12 +0000957 int prevRite = bounds.fLeft;
958
959 do {
reed@google.com32287892011-10-05 16:27:44 +0000960 U8CPU alphaA = 0;
961 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +0000962 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +0000963
964 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +0000965 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +0000966 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +0000967 if (riteA <= leftB) {
968 rite = riteA;
969 } else {
970 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +0000971 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000972 } else if (leftB < leftA) {
973 left = leftB;
974 alphaB = iterB.alpha();
975 if (riteB <= leftA) {
976 rite = riteB;
977 } else {
978 rite = leftB = leftA;
979 }
980 } else {
981 left = leftA; // or leftB, since leftA == leftB
982 rite = leftA = leftB = SkMin32(riteA, riteB);
983 alphaA = iterA.alpha();
984 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +0000985 }
986
987 if (left >= bounds.fRight) {
988 break;
989 }
reed@google.com34f7e472011-10-13 15:11:59 +0000990 if (rite > bounds.fRight) {
991 rite = bounds.fRight;
992 }
993
reed@google.com32287892011-10-05 16:27:44 +0000994 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +0000995 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +0000996 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +0000997 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +0000998 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000999
1000 adjust_row(iterA, leftA, riteA, rite);
1001 adjust_row(iterB, leftB, riteB, rite);
1002 } while (!iterA.done() || !iterB.done());
1003
1004 if (prevRite < bounds.fRight) {
1005 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +00001006 }
1007}
1008
reed@google.com1c04bf92011-10-10 12:57:12 +00001009static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
1010 if (bot == botA) {
1011 iter.next();
1012 topA = botA;
1013 SkASSERT(botA == iter.top());
1014 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +00001015 }
1016}
1017
1018static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
1019 const SkAAClip& B, SkRegion::Op op) {
1020 AlphaProc proc = find_alpha_proc(op);
1021 const SkIRect& bounds = builder.getBounds();
1022
1023 SkAAClip::Iter iterA(A);
1024 SkAAClip::Iter iterB(B);
1025
1026 SkASSERT(!iterA.done());
1027 int topA = iterA.top();
1028 int botA = iterA.bottom();
1029 SkASSERT(!iterB.done());
1030 int topB = iterB.top();
1031 int botB = iterB.bottom();
1032
reed@google.com1c04bf92011-10-10 12:57:12 +00001033 do {
1034 const uint8_t* rowA = NULL;
1035 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +00001036 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +00001037
1038 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +00001039 top = topA;
reed@google.com32287892011-10-05 16:27:44 +00001040 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +00001041 if (botA <= topB) {
1042 bot = botA;
1043 } else {
1044 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +00001045 }
reed@google.com1c04bf92011-10-10 12:57:12 +00001046
1047 } else if (topB < topA) {
1048 top = topB;
1049 rowB = iterB.data();
1050 if (botB <= topA) {
1051 bot = botB;
1052 } else {
1053 bot = topB = topA;
1054 }
1055 } else {
1056 top = topA; // or topB, since topA == topB
1057 bot = topA = topB = SkMin32(botA, botB);
1058 rowA = iterA.data();
1059 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +00001060 }
1061
1062 if (top >= bounds.fBottom) {
1063 break;
1064 }
reed@google.com34f7e472011-10-13 15:11:59 +00001065
1066 if (bot > bounds.fBottom) {
1067 bot = bounds.fBottom;
1068 }
1069 SkASSERT(top < bot);
1070
reed@google.com1c04bf92011-10-10 12:57:12 +00001071 if (!rowA && !rowB) {
1072 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
1073 } else if (top >= bounds.fTop) {
1074 SkASSERT(bot <= bounds.fBottom);
1075 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
1076 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +00001077 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +00001078 }
1079
reed@google.com1c04bf92011-10-10 12:57:12 +00001080 adjust_iter(iterA, topA, botA, bot);
1081 adjust_iter(iterB, topB, botB, bot);
1082 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +00001083}
1084
1085bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
1086 SkRegion::Op op) {
reed@google.com045e62d2011-10-24 12:19:46 +00001087 AUTO_AACLIP_VALIDATE(*this);
1088
reed@google.com32287892011-10-05 16:27:44 +00001089 if (SkRegion::kReplace_Op == op) {
1090 return this->set(clipBOrig);
1091 }
1092
1093 const SkAAClip* clipA = &clipAOrig;
1094 const SkAAClip* clipB = &clipBOrig;
1095
1096 if (SkRegion::kReverseDifference_Op == op) {
1097 SkTSwap(clipA, clipB);
1098 op = SkRegion::kDifference_Op;
1099 }
1100
1101 bool a_empty = clipA->isEmpty();
1102 bool b_empty = clipB->isEmpty();
1103
1104 SkIRect bounds;
1105 switch (op) {
1106 case SkRegion::kDifference_Op:
1107 if (a_empty) {
1108 return this->setEmpty();
1109 }
1110 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
1111 return this->set(*clipA);
1112 }
1113 bounds = clipA->fBounds;
1114 break;
1115
1116 case SkRegion::kIntersect_Op:
1117 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
1118 clipB->fBounds)) {
1119 return this->setEmpty();
1120 }
1121 break;
1122
1123 case SkRegion::kUnion_Op:
1124 case SkRegion::kXOR_Op:
1125 if (a_empty) {
1126 return this->set(*clipB);
1127 }
1128 if (b_empty) {
1129 return this->set(*clipA);
1130 }
1131 bounds = clipA->fBounds;
1132 bounds.join(clipB->fBounds);
1133 break;
1134
1135 default:
1136 SkASSERT(!"unknown region op");
1137 return !this->isEmpty();
1138 }
1139
reed@google.com32287892011-10-05 16:27:44 +00001140 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1141 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
1142
1143 Builder builder(bounds);
1144 operateY(builder, *clipA, *clipB, op);
reed@google.com045e62d2011-10-24 12:19:46 +00001145
1146 return builder.finish(this);
reed@google.come36707a2011-10-04 21:38:55 +00001147}
1148
reed@google.com045e62d2011-10-24 12:19:46 +00001149/*
1150 * It can be expensive to build a local aaclip before applying the op, so
1151 * we first see if we can restrict the bounds of new rect to our current
1152 * bounds, or note that the new rect subsumes our current clip.
1153 */
1154
1155bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) {
1156 SkIRect rStorage;
1157 const SkIRect* r = &rOrig;
1158
1159 switch (op) {
1160 case SkRegion::kIntersect_Op:
1161 if (!rStorage.intersect(rOrig, fBounds)) {
1162 // no overlap, so we're empty
1163 return this->setEmpty();
1164 }
1165 if (rStorage == fBounds) {
1166 // we were wholly inside the rect, no change
1167 return !this->isEmpty();
1168 }
1169 if (this->quickContains(rStorage)) {
1170 // the intersection is wholly inside us, we're a rect
1171 return this->setRect(rStorage);
1172 }
1173 r = &rStorage; // use the intersected bounds
1174 break;
1175 case SkRegion::kDifference_Op:
1176 break;
1177 case SkRegion::kUnion_Op:
1178 if (rOrig.contains(fBounds)) {
1179 return this->setRect(rOrig);
1180 }
1181 break;
1182 default:
1183 break;
1184 }
1185
reed@google.com47ac84e2011-10-06 13:11:25 +00001186 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001187 clip.setRect(*r);
reed@google.com47ac84e2011-10-06 13:11:25 +00001188 return this->op(*this, clip, op);
1189}
1190
reed@google.com045e62d2011-10-24 12:19:46 +00001191bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) {
1192 SkRect rStorage, boundsStorage;
1193 const SkRect* r = &rOrig;
1194
1195 boundsStorage.set(fBounds);
1196 switch (op) {
1197 case SkRegion::kIntersect_Op:
1198 case SkRegion::kDifference_Op:
1199 if (!rStorage.intersect(rOrig, boundsStorage)) {
1200 return this->setEmpty();
1201 }
1202 r = &rStorage; // use the intersected bounds
1203 break;
1204 case SkRegion::kUnion_Op:
1205 if (rOrig.contains(boundsStorage)) {
1206 return this->setRect(rOrig);
1207 }
1208 break;
1209 default:
1210 break;
1211 }
1212
reed@google.com47ac84e2011-10-06 13:11:25 +00001213 SkAAClip clip;
reed@google.com045e62d2011-10-24 12:19:46 +00001214 clip.setRect(*r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +00001215 return this->op(*this, clip, op);
1216}
1217
1218bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
1219 return this->op(*this, clip, op);
1220}
1221
reed@google.come36707a2011-10-04 21:38:55 +00001222///////////////////////////////////////////////////////////////////////////////
reed@google.com045e62d2011-10-24 12:19:46 +00001223
1224bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const {
1225 if (NULL == dst) {
1226 return !this->isEmpty();
1227 }
1228
1229 if (this->isEmpty()) {
1230 return dst->setEmpty();
1231 }
1232
1233 if (this != dst) {
1234 sk_atomic_inc(&fRunHead->fRefCnt);
1235 dst->fRunHead = fRunHead;
1236 dst->fBounds = fBounds;
1237 }
1238 dst->fBounds.offset(dx, dy);
1239 return true;
1240}
1241
1242static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1243 const uint8_t* SK_RESTRICT row,
1244 int width) {
1245 while (width > 0) {
1246 int n = row[0];
1247 SkASSERT(width >= n);
1248 memset(mask, row[1], n);
1249 mask += n;
1250 row += 2;
1251 width -= n;
1252 }
1253}
1254
1255void SkAAClip::copyToMask(SkMask* mask) const {
1256 mask->fFormat = SkMask::kA8_Format;
1257 if (this->isEmpty()) {
1258 mask->fBounds.setEmpty();
1259 mask->fImage = NULL;
1260 mask->fRowBytes = 0;
1261 return;
1262 }
1263
1264 mask->fBounds = fBounds;
1265 mask->fRowBytes = fBounds.width();
1266 size_t size = mask->computeImageSize();
1267 mask->fImage = SkMask::AllocImage(size);
1268
1269 Iter iter(*this);
1270 uint8_t* dst = mask->fImage;
1271 const int width = fBounds.width();
1272
1273 int y = fBounds.fTop;
1274 while (!iter.done()) {
1275 do {
1276 expand_row_to_mask(dst, iter.data(), width);
1277 dst += mask->fRowBytes;
1278 } while (++y < iter.bottom());
1279 iter.next();
1280 }
1281}
1282
1283///////////////////////////////////////////////////////////////////////////////
reed@google.come36707a2011-10-04 21:38:55 +00001284///////////////////////////////////////////////////////////////////////////////
1285
1286static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
1287 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
1288 // we don't read our initial n from data, since the caller may have had to
1289 // clip it, hence the initialCount parameter.
1290 int n = initialCount;
1291 for (;;) {
1292 if (n > width) {
1293 n = width;
1294 }
1295 SkASSERT(n > 0);
1296 runs[0] = n;
1297 runs += n;
1298
1299 aa[0] = data[1];
1300 aa += n;
1301
1302 data += 2;
1303 width -= n;
1304 if (0 == width) {
1305 break;
1306 }
1307 // load the next count
1308 n = data[0];
1309 }
1310 runs[0] = 0; // sentinel
1311}
1312
1313SkAAClipBlitter::~SkAAClipBlitter() {
reed@google.com045e62d2011-10-24 12:19:46 +00001314 sk_free(fScanlineScratch);
reed@google.come36707a2011-10-04 21:38:55 +00001315}
1316
1317void SkAAClipBlitter::ensureRunsAndAA() {
reed@google.com045e62d2011-10-24 12:19:46 +00001318 if (NULL == fScanlineScratch) {
reed@google.come36707a2011-10-04 21:38:55 +00001319 // add 1 so we can store the terminating run count of 0
1320 int count = fAAClipBounds.width() + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001321 // we use this either for fRuns + fAA, or a scaline of a mask
1322 // which may be as deep as 32bits
1323 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor));
1324 fRuns = (int16_t*)fScanlineScratch;
reed@google.come36707a2011-10-04 21:38:55 +00001325 fAA = (SkAlpha*)(fRuns + count);
1326 }
1327}
1328
1329void SkAAClipBlitter::blitH(int x, int y, int width) {
1330 SkASSERT(width > 0);
1331 SkASSERT(fAAClipBounds.contains(x, y));
1332 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1333
1334 int lastY;
1335 const uint8_t* row = fAAClip->findRow(y, &lastY);
1336 int initialCount;
1337 row = fAAClip->findX(row, x, &initialCount);
1338
1339 if (initialCount >= width) {
1340 SkAlpha alpha = row[1];
1341 if (0 == alpha) {
1342 return;
1343 }
1344 if (0xFF == alpha) {
1345 fBlitter->blitH(x, y, width);
1346 return;
1347 }
1348 }
1349
1350 this->ensureRunsAndAA();
1351 expandToRuns(row, initialCount, width, fRuns, fAA);
1352
1353 fBlitter->blitAntiH(x, y, fAA, fRuns);
1354}
1355
1356static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1357 const SkAlpha* SK_RESTRICT srcAA,
1358 const int16_t* SK_RESTRICT srcRuns,
1359 SkAlpha* SK_RESTRICT dstAA,
1360 int16_t* SK_RESTRICT dstRuns,
1361 int width) {
1362 SkDEBUGCODE(int accumulated = 0;)
1363 int srcN = srcRuns[0];
reed@google.com045e62d2011-10-24 12:19:46 +00001364 // do we need this check?
1365 if (0 == srcN) {
1366 return;
1367 }
1368
reed@google.come36707a2011-10-04 21:38:55 +00001369 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001370 SkASSERT(rowN > 0);
1371 SkASSERT(srcN > 0);
1372
1373 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1374 int minN = SkMin32(srcN, rowN);
1375 dstRuns[0] = minN;
1376 dstRuns += minN;
1377 dstAA[0] = newAlpha;
1378 dstAA += minN;
1379
1380 if (0 == (srcN -= minN)) {
1381 srcN = srcRuns[0]; // refresh
1382 srcRuns += srcN;
1383 srcAA += srcN;
1384 srcN = srcRuns[0]; // reload
reed@google.com045e62d2011-10-24 12:19:46 +00001385 if (0 == srcN) {
1386 break;
1387 }
reed@google.come36707a2011-10-04 21:38:55 +00001388 }
1389 if (0 == (rowN -= minN)) {
1390 row += 2;
1391 rowN = row[0]; // reload
1392 }
1393
1394 SkDEBUGCODE(accumulated += minN;)
1395 SkASSERT(accumulated <= width);
1396 }
reed@google.com34f7e472011-10-13 15:11:59 +00001397 dstRuns[0] = 0;
reed@google.come36707a2011-10-04 21:38:55 +00001398}
1399
1400void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1401 const int16_t runs[]) {
1402 int lastY;
1403 const uint8_t* row = fAAClip->findRow(y, &lastY);
1404 int initialCount;
1405 row = fAAClip->findX(row, x, &initialCount);
1406
1407 this->ensureRunsAndAA();
1408
1409 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1410 fBlitter->blitAntiH(x, y, fAA, fRuns);
1411}
1412
1413void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1414 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1415 fBlitter->blitV(x, y, height, alpha);
1416 return;
1417 }
1418
reed@google.com045e62d2011-10-24 12:19:46 +00001419 for (;;) {
reed@google.come36707a2011-10-04 21:38:55 +00001420 int lastY;
1421 const uint8_t* row = fAAClip->findRow(y, &lastY);
reed@google.com045e62d2011-10-24 12:19:46 +00001422 int dy = lastY - y + 1;
1423 if (dy > height) {
1424 dy = height;
1425 }
1426 height -= dy;
1427
reed@google.come36707a2011-10-04 21:38:55 +00001428 int initialCount;
1429 row = fAAClip->findX(row, x, &initialCount);
1430 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1431 if (newAlpha) {
reed@google.com045e62d2011-10-24 12:19:46 +00001432 fBlitter->blitV(x, y, dy, newAlpha);
1433 }
1434 SkASSERT(height >= 0);
1435 if (height <= 0) {
1436 break;
reed@google.come36707a2011-10-04 21:38:55 +00001437 }
1438 y = lastY + 1;
reed@google.com045e62d2011-10-24 12:19:46 +00001439 }
reed@google.come36707a2011-10-04 21:38:55 +00001440}
1441
1442void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1443 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1444 fBlitter->blitRect(x, y, width, height);
1445 return;
1446 }
1447
1448 while (--height >= 0) {
1449 this->blitH(x, y, width);
1450 y += 1;
1451 }
1452}
1453
reed@google.com045e62d2011-10-24 12:19:46 +00001454typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row,
1455 int initialRowCount, void* dst);
1456
1457static void small_memcpy(void* dst, const void* src, size_t n) {
1458 memcpy(dst, src, n);
1459}
1460
1461static void small_bzero(void* dst, size_t n) {
1462 sk_bzero(dst, n);
1463}
1464
1465static inline uint8_t mergeOne(uint8_t value, unsigned alpha) {
1466 return SkMulDiv255Round(value, alpha);
1467}
1468static inline uint16_t mergeOne(uint16_t value, unsigned alpha) {
1469 unsigned r = SkGetPackedR16(value);
1470 unsigned g = SkGetPackedG16(value);
1471 unsigned b = SkGetPackedB16(value);
1472 return SkPackRGB16(SkMulDiv255Round(r, alpha),
1473 SkMulDiv255Round(r, alpha),
1474 SkMulDiv255Round(r, alpha));
1475}
1476static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) {
1477 unsigned a = SkGetPackedA32(value);
1478 unsigned r = SkGetPackedR32(value);
1479 unsigned g = SkGetPackedG32(value);
1480 unsigned b = SkGetPackedB32(value);
1481 return SkPackARGB32(SkMulDiv255Round(a, alpha),
1482 SkMulDiv255Round(r, alpha),
1483 SkMulDiv255Round(g, alpha),
1484 SkMulDiv255Round(b, alpha));
1485}
1486
1487template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN,
1488 const uint8_t* SK_RESTRICT row, int rowN,
1489 T* SK_RESTRICT dst) {
1490 SkDEBUGCODE(int accumulated = 0;)
1491 for (;;) {
1492 SkASSERT(rowN > 0);
1493 SkASSERT(srcN > 0);
1494
1495 int n = SkMin32(rowN, srcN);
1496 unsigned rowA = row[1];
1497 if (0xFF == rowA) {
1498 small_memcpy(dst, src, n * sizeof(T));
1499 } else if (0 == rowA) {
1500 small_bzero(dst, n * sizeof(T));
1501 } else {
1502 for (int i = 0; i < n; ++i) {
1503 dst[i] = mergeOne(src[i], rowA);
1504 }
1505 }
1506
1507 if (0 == (srcN -= n)) {
1508 break;
1509 }
1510
1511 src += n;
1512 dst += n;
1513
1514 SkASSERT(rowN == n);
1515 row += 2;
1516 rowN = row[0];
1517 }
1518}
1519
1520static MergeAAProc find_merge_aa_proc(SkMask::Format format) {
1521 switch (format) {
1522 case SkMask::kBW_Format:
1523 SkASSERT(!"unsupported");
1524 return NULL;
1525 case SkMask::kA8_Format:
1526 case SkMask::k3D_Format: {
1527 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT;
1528 return (MergeAAProc)proc8;
1529 }
1530 case SkMask::kLCD16_Format: {
1531 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT;
1532 return (MergeAAProc)proc16;
1533 }
1534 case SkMask::kLCD32_Format: {
1535 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT;
1536 return (MergeAAProc)proc32;
1537 }
1538 default:
1539 SkASSERT(!"unsupported");
1540 return NULL;
1541 }
1542}
1543
1544static U8CPU bit2byte(int bitInAByte) {
1545 SkASSERT(bitInAByte <= 0xFF);
1546 // negation turns any non-zero into 0xFFFFFF??, so we just shift down
1547 // some value >= 8 to get a full FF value
1548 return -bitInAByte >> 8;
1549}
1550
1551static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) {
1552 SkASSERT(SkMask::kBW_Format == srcMask.fFormat);
1553 SkASSERT(SkMask::kA8_Format == dstMask->fFormat);
1554
1555 const int width = srcMask.fBounds.width();
1556 const int height = srcMask.fBounds.height();
1557
1558 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage;
1559 const size_t srcRB = srcMask.fRowBytes;
1560 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage;
1561 const size_t dstRB = dstMask->fRowBytes;
1562
1563 const int wholeBytes = width >> 3;
1564 const int leftOverBits = width & 7;
1565
1566 for (int y = 0; y < height; ++y) {
1567 uint8_t* SK_RESTRICT d = dst;
1568 for (int i = 0; i < wholeBytes; ++i) {
1569 int srcByte = src[i];
1570 d[0] = bit2byte(srcByte & (1 << 7));
1571 d[1] = bit2byte(srcByte & (1 << 6));
1572 d[2] = bit2byte(srcByte & (1 << 5));
1573 d[3] = bit2byte(srcByte & (1 << 4));
1574 d[4] = bit2byte(srcByte & (1 << 3));
1575 d[5] = bit2byte(srcByte & (1 << 2));
1576 d[6] = bit2byte(srcByte & (1 << 1));
1577 d[7] = bit2byte(srcByte & (1 << 0));
1578 d += 8;
1579 }
1580 if (leftOverBits) {
1581 int srcByte = src[wholeBytes];
1582 for (int x = 0; x < leftOverBits; ++x) {
1583 *d++ = bit2byte(srcByte & 0x80);
1584 srcByte <<= 1;
1585 }
1586 }
1587 src += srcRB;
1588 dst += dstRB;
1589 }
1590}
1591
1592void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) {
1593 SkASSERT(fAAClip->getBounds().contains(clip));
1594
1595 if (fAAClip->quickContains(clip)) {
1596 fBlitter->blitMask(origMask, clip);
1597 return;
1598 }
1599
1600 const SkMask* mask = &origMask;
1601
1602 // if we're BW, we need to upscale to A8 (ugh)
1603 SkMask grayMask;
1604 grayMask.fImage = NULL;
1605 if (SkMask::kBW_Format == origMask.fFormat) {
1606 grayMask.fFormat = SkMask::kA8_Format;
1607 grayMask.fBounds = origMask.fBounds;
1608 grayMask.fRowBytes = origMask.fBounds.width();
1609 size_t size = grayMask.computeImageSize();
1610 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size,
1611 SkAutoMalloc::kReuse_OnShrink);
1612
1613 upscaleBW2A8(&grayMask, origMask);
1614 mask = &grayMask;
1615 }
1616
1617 this->ensureRunsAndAA();
1618
1619 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D
1620 // data into a temp block to support it better (ugh)
1621
1622 const void* src = mask->getAddr(clip.fLeft, clip.fTop);
1623 const size_t srcRB = mask->fRowBytes;
1624 const int width = clip.width();
1625 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat);
1626
1627 SkMask rowMask;
1628 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat;
1629 rowMask.fBounds.fLeft = clip.fLeft;
1630 rowMask.fBounds.fRight = clip.fRight;
1631 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1
1632 rowMask.fImage = (uint8_t*)fScanlineScratch;
1633
1634 int y = clip.fTop;
1635 const int stopY = y + clip.height();
1636
1637 do {
1638 int localStopY;
1639 const uint8_t* row = fAAClip->findRow(y, &localStopY);
1640 // findRow returns last Y, not stop, so we add 1
1641 localStopY = SkMin32(localStopY + 1, stopY);
1642
1643 int initialCount;
1644 row = fAAClip->findX(row, clip.fLeft, &initialCount);
1645 do {
1646 mergeProc(src, width, row, initialCount, rowMask.fImage);
1647 rowMask.fBounds.fTop = y;
1648 rowMask.fBounds.fBottom = y + 1;
1649 fBlitter->blitMask(rowMask, rowMask.fBounds);
1650 src = (const void*)((const char*)src + srcRB);
1651 } while (++y < localStopY);
1652 } while (y < stopY);
reed@google.come36707a2011-10-04 21:38:55 +00001653}
1654
1655const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1656 return NULL;
1657}
1658