blob: 0dbdd0fbd89c3517bd89cb2cb03a42deca757800 [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"
11#include "SkPath.h"
12#include "SkScan.h"
13#include "SkThread.h"
14
reed@google.com1c04bf92011-10-10 12:57:12 +000015#define kMaxInt32 0x7FFFFFFF
16
reed@google.come36707a2011-10-04 21:38:55 +000017static inline bool x_in_rect(int x, const SkIRect& rect) {
18 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
19}
20
21static inline bool y_in_rect(int y, const SkIRect& rect) {
22 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
23}
24
25/*
26 * Data runs are packed [count, alpha]
27 */
28
29struct SkAAClip::YOffset {
30 int32_t fY;
31 uint32_t fOffset;
32};
33
34struct SkAAClip::RunHead {
35 int32_t fRefCnt;
36 int32_t fRowCount;
37 int32_t fDataSize;
38
39 YOffset* yoffsets() {
40 return (YOffset*)((char*)this + sizeof(RunHead));
41 }
42 const YOffset* yoffsets() const {
43 return (const YOffset*)((const char*)this + sizeof(RunHead));
44 }
45 uint8_t* data() {
46 return (uint8_t*)(this->yoffsets() + fRowCount);
47 }
48 const uint8_t* data() const {
49 return (const uint8_t*)(this->yoffsets() + fRowCount);
50 }
51
52 static RunHead* Alloc(int rowCount, size_t dataSize) {
53 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
54 RunHead* head = (RunHead*)sk_malloc_throw(size);
55 head->fRefCnt = 1;
56 head->fRowCount = rowCount;
57 head->fDataSize = dataSize;
58 return head;
59 }
60};
61
reed@google.com32287892011-10-05 16:27:44 +000062class SkAAClip::Iter {
63public:
64 Iter(const SkAAClip&);
65
66 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +000067 int top() const { return fTop; }
68 int bottom() const { return fBottom; }
69 const uint8_t* data() const { return fData; }
reed@google.com32287892011-10-05 16:27:44 +000070 void next();
71
72private:
73 const YOffset* fCurrYOff;
74 const YOffset* fStopYOff;
75 const uint8_t* fData;
76
77 int fTop, fBottom;
78 bool fDone;
79};
80
81SkAAClip::Iter::Iter(const SkAAClip& clip) {
82 if (clip.isEmpty()) {
83 fDone = true;
reed@google.com1c04bf92011-10-10 12:57:12 +000084 fTop = fBottom = clip.fBounds.fBottom;
85 fData = NULL;
reed@google.com32287892011-10-05 16:27:44 +000086 return;
87 }
88
89 const RunHead* head = clip.fRunHead;
90 fCurrYOff = head->yoffsets();
91 fStopYOff = fCurrYOff + head->fRowCount;
92 fData = head->data() + fCurrYOff->fOffset;
93
94 // setup first value
95 fTop = clip.fBounds.fTop;
96 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1;
97 fDone = false;
98}
99
100void SkAAClip::Iter::next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000101 if (!fDone) {
102 const YOffset* prev = fCurrYOff;
103 const YOffset* curr = prev + 1;
104 SkASSERT(curr <= fStopYOff);
reed@google.com32287892011-10-05 16:27:44 +0000105
reed@google.com32287892011-10-05 16:27:44 +0000106 fTop = fBottom;
reed@google.com1c04bf92011-10-10 12:57:12 +0000107 if (curr >= fStopYOff) {
108 fDone = true;
109 fBottom = kMaxInt32;
110 fData = NULL;
111 } else {
112 fBottom += curr->fY - prev->fY;
113 fData += curr->fOffset - prev->fOffset;
114 fCurrYOff = curr;
115 }
reed@google.com32287892011-10-05 16:27:44 +0000116 }
117}
118
reed@google.come36707a2011-10-04 21:38:55 +0000119///////////////////////////////////////////////////////////////////////////////
120
121void SkAAClip::freeRuns() {
reed@google.com47ac84e2011-10-06 13:11:25 +0000122 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000123 SkASSERT(fRunHead->fRefCnt >= 1);
124 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
125 sk_free(fRunHead);
126 }
127 }
128}
129
130SkAAClip::SkAAClip() {
131 fBounds.setEmpty();
reed@google.com47ac84e2011-10-06 13:11:25 +0000132 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000133}
134
135SkAAClip::SkAAClip(const SkAAClip& src) {
reed@google.com47ac84e2011-10-06 13:11:25 +0000136 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000137 *this = src;
138}
139
140SkAAClip::~SkAAClip() {
141 this->freeRuns();
142}
143
144SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
145 if (this != &src) {
146 this->freeRuns();
147 fBounds = src.fBounds;
148 fRunHead = src.fRunHead;
reed@google.com47ac84e2011-10-06 13:11:25 +0000149 if (fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000150 sk_atomic_inc(&fRunHead->fRefCnt);
151 }
152 }
153 return *this;
154}
155
156bool operator==(const SkAAClip& a, const SkAAClip& b) {
157 if (&a == &b) {
158 return true;
159 }
160 if (a.fBounds != b.fBounds) {
161 return false;
162 }
163
164 const SkAAClip::RunHead* ah = a.fRunHead;
165 const SkAAClip::RunHead* bh = b.fRunHead;
166
167 // this catches empties and rects being equal
168 if (ah == bh) {
169 return true;
170 }
171
172 // now we insist that both are complex (but different ptrs)
reed@google.com47ac84e2011-10-06 13:11:25 +0000173 if (!a.fRunHead || !b.fRunHead) {
reed@google.come36707a2011-10-04 21:38:55 +0000174 return false;
175 }
176
177 return ah->fRowCount == bh->fRowCount &&
178 ah->fDataSize == bh->fDataSize &&
179 !memcmp(ah->data(), bh->data(), ah->fDataSize);
180}
181
182void SkAAClip::swap(SkAAClip& other) {
183 SkTSwap(fBounds, other.fBounds);
184 SkTSwap(fRunHead, other.fRunHead);
185}
186
reed@google.com32287892011-10-05 16:27:44 +0000187bool SkAAClip::set(const SkAAClip& src) {
188 *this = src;
189 return !this->isEmpty();
190}
191
reed@google.come36707a2011-10-04 21:38:55 +0000192bool SkAAClip::setEmpty() {
193 this->freeRuns();
194 fBounds.setEmpty();
reed@google.com47ac84e2011-10-06 13:11:25 +0000195 fRunHead = NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000196 return false;
197}
198
199bool SkAAClip::setRect(const SkIRect& bounds) {
200 if (bounds.isEmpty()) {
201 return this->setEmpty();
202 }
reed@google.com47ac84e2011-10-06 13:11:25 +0000203
204 // TODO: special case this
205
206 SkRect r;
207 r.set(bounds);
208 SkPath path;
209 path.addRect(r);
210 return this->setPath(path);
reed@google.come36707a2011-10-04 21:38:55 +0000211}
212
reed@google.comf3c1da12011-10-10 19:35:47 +0000213bool SkAAClip::setRect(const SkRect& r, bool doAA) {
reed@google.come36707a2011-10-04 21:38:55 +0000214 if (r.isEmpty()) {
215 return this->setEmpty();
216 }
217
reed@google.come36707a2011-10-04 21:38:55 +0000218 SkPath path;
219 path.addRect(r);
reed@google.comf3c1da12011-10-10 19:35:47 +0000220 return this->setPath(path, NULL, doAA);
221}
222
223bool SkAAClip::setRegion(const SkRegion& rgn) {
224 if (rgn.isEmpty()) {
225 return this->setEmpty();
226 }
227 if (rgn.isRect()) {
228 return this->setRect(rgn.getBounds());
229 }
230
231 SkAAClip clip;
232 SkRegion::Iterator iter(rgn);
233 for (; !iter.done(); iter.next()) {
234 clip.op(iter.rect(), SkRegion::kUnion_Op);
235 }
236 this->swap(clip);
reed@google.come36707a2011-10-04 21:38:55 +0000237}
238
239///////////////////////////////////////////////////////////////////////////////
240
241const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000242 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000243
244 if (!y_in_rect(y, fBounds)) {
245 return NULL;
246 }
247 y -= fBounds.y(); // our yoffs values are relative to the top
248
249 const YOffset* yoff = fRunHead->yoffsets();
250 while (yoff->fY < y) {
251 yoff += 1;
252 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
253 }
254
255 if (lastYForRow) {
256 *lastYForRow = yoff->fY;
257 }
258 return fRunHead->data() + yoff->fOffset;
259}
260
261const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
262 SkASSERT(x_in_rect(x, fBounds));
263 x -= fBounds.x();
264
265 // first skip up to X
266 for (;;) {
267 int n = data[0];
268 if (x < n) {
269 *initialCount = n - x;
270 break;
271 }
272 data += 2;
273 x -= n;
274 }
275 return data;
276}
277
278bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
279 if (this->isEmpty()) {
280 return false;
281 }
282 if (!fBounds.contains(left, top, right, bottom)) {
283 return false;
284 }
reed@google.com32287892011-10-05 16:27:44 +0000285#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000286 if (this->isRect()) {
287 return true;
288 }
reed@google.com32287892011-10-05 16:27:44 +0000289#endif
reed@google.come36707a2011-10-04 21:38:55 +0000290
291 int lastY;
292 const uint8_t* row = this->findRow(top, &lastY);
293 if (lastY < bottom) {
294 return false;
295 }
296 // now just need to check in X
297 int initialCount;
298 row = this->findX(row, left, &initialCount);
299 return initialCount >= (right - left) && 0xFF == row[1];
300}
301
302///////////////////////////////////////////////////////////////////////////////
303
304class SkAAClip::Builder {
305 SkIRect fBounds;
306 struct Row {
307 int fY;
308 int fWidth;
309 SkTDArray<uint8_t>* fData;
310 };
311 SkTDArray<Row> fRows;
312 Row* fCurrRow;
313 int fPrevY;
314 int fWidth;
315
316public:
317 Builder(const SkIRect& bounds) : fBounds(bounds) {
318 fPrevY = -1;
319 fWidth = bounds.width();
320 fCurrRow = NULL;
321 }
322
323 ~Builder() {
324 Row* row = fRows.begin();
325 Row* stop = fRows.end();
326 while (row < stop) {
327 delete row->fData;
328 row += 1;
329 }
330 }
331
reed@google.com32287892011-10-05 16:27:44 +0000332 const SkIRect& getBounds() const { return fBounds; }
333
reed@google.come36707a2011-10-04 21:38:55 +0000334 void addRun(int x, int y, U8CPU alpha, int count) {
335 SkASSERT(count > 0);
336 SkASSERT(fBounds.contains(x, y));
337 SkASSERT(fBounds.contains(x + count - 1, y));
338
339 x -= fBounds.left();
340 y -= fBounds.top();
341
342 Row* row = fCurrRow;
343 if (y != fPrevY) {
344 SkASSERT(y > fPrevY);
345 fPrevY = y;
346 row = this->flushRow(true);
347 row->fY = y;
348 row->fWidth = 0;
349 SkASSERT(row->fData);
350 SkASSERT(0 == row->fData->count());
351 fCurrRow = row;
352 }
353
354 SkASSERT(row->fWidth <= x);
355 SkASSERT(row->fWidth < fBounds.width());
356
357 SkTDArray<uint8_t>& data = *row->fData;
358
359 int gap = x - row->fWidth;
360 if (gap) {
361 AppendRun(data, 0, gap);
362 row->fWidth += gap;
363 SkASSERT(row->fWidth < fBounds.width());
364 }
365
366 AppendRun(data, alpha, count);
367 row->fWidth += count;
368 SkASSERT(row->fWidth <= fBounds.width());
369 }
370
371 RunHead* finish() {
372 this->flushRow(false);
373
374 const Row* row = fRows.begin();
375 const Row* stop = fRows.end();
376
377 size_t dataSize = 0;
378 while (row < stop) {
379 dataSize += row->fData->count();
380 row += 1;
381 }
382
383 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
384 YOffset* yoffset = head->yoffsets();
385 uint8_t* data = head->data();
386 uint8_t* baseData = data;
387
388 row = fRows.begin();
389 while (row < stop) {
390 yoffset->fY = row->fY;
391 yoffset->fOffset = data - baseData;
392 yoffset += 1;
393
394 size_t n = row->fData->count();
395 memcpy(data, row->fData->begin(), n);
396 data += n;
397
398 row += 1;
399 }
400
401 return head;
402 }
403
404 void dump() {
405 this->validate();
406 int y;
407 for (y = 0; y < fRows.count(); ++y) {
408 const Row& row = fRows[y];
409 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
410 const SkTDArray<uint8_t>& data = *row.fData;
411 int count = data.count();
412 SkASSERT(!(count & 1));
413 const uint8_t* ptr = data.begin();
414 for (int x = 0; x < count; x += 2) {
415 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
416 ptr += 2;
417 }
418 SkDebugf("\n");
419 }
420
reed@google.com1c04bf92011-10-10 12:57:12 +0000421#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000422 int prevY = -1;
423 for (y = 0; y < fRows.count(); ++y) {
424 const Row& row = fRows[y];
425 const SkTDArray<uint8_t>& data = *row.fData;
426 int count = data.count();
427 for (int n = prevY; n < row.fY; ++n) {
428 const uint8_t* ptr = data.begin();
429 for (int x = 0; x < count; x += 2) {
430 for (int i = 0; i < ptr[0]; ++i) {
431 SkDebugf("%02X", ptr[1]);
432 }
433 ptr += 2;
434 }
435 SkDebugf("\n");
436 }
437 prevY = row.fY;
438 }
439#endif
440 }
441
442 void validate() {
443#ifdef SK_DEBUG
444 int prevY = -1;
445 for (int i = 0; i < fRows.count(); ++i) {
446 const Row& row = fRows[i];
447 SkASSERT(prevY < row.fY);
448 SkASSERT(fWidth == row.fWidth);
449 int count = row.fData->count();
450 const uint8_t* ptr = row.fData->begin();
451 SkASSERT(!(count & 1));
452 int w = 0;
453 for (int x = 0; x < count; x += 2) {
454 w += ptr[0];
455 SkASSERT(w <= fWidth);
456 ptr += 2;
457 }
458 SkASSERT(w == fWidth);
459 prevY = row.fY;
460 }
461#endif
462 }
463
464private:
465 Row* flushRow(bool readyForAnother) {
466 Row* next = NULL;
467 int count = fRows.count();
468 if (count > 0) {
469 // flush current row if needed
470 Row* curr = &fRows[count - 1];
471 if (curr->fWidth < fWidth) {
472 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
473 }
474 }
475 if (count > 1) {
476 // are our last two runs the same?
477 Row* prev = &fRows[count - 2];
478 Row* curr = &fRows[count - 1];
479 SkASSERT(prev->fWidth == fWidth);
480 SkASSERT(curr->fWidth == fWidth);
481 if (*prev->fData == *curr->fData) {
482 prev->fY = curr->fY;
483 if (readyForAnother) {
484 curr->fData->rewind();
485 next = curr;
486 } else {
487 delete curr->fData;
488 fRows.removeShuffle(count - 1);
489 }
490 } else {
491 if (readyForAnother) {
492 next = fRows.append();
493 next->fData = new SkTDArray<uint8_t>;
494 }
495 }
496 } else {
497 if (readyForAnother) {
498 next = fRows.append();
499 next->fData = new SkTDArray<uint8_t>;
500 }
501 }
502 return next;
503 }
504
505 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
506 do {
507 int n = count;
508 if (n > 255) {
509 n = 255;
510 }
511 uint8_t* ptr = data.append(2);
512 ptr[0] = n;
513 ptr[1] = alpha;
514 count -= n;
515 } while (count > 0);
516 }
517};
518
519class SkAAClip::BuilderBlitter : public SkBlitter {
520public:
521 BuilderBlitter(Builder* builder) {
522 fBuilder = builder;
523 }
524
525 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
526 { unexpected(); }
527 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
528 { unexpected(); }
529 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
530 { unexpected(); }
531
532 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
533 return false;
534 }
535
536 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
537 fBuilder->addRun(x, y, 0xFF, width);
538 }
539
540 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
541 const int16_t runs[]) SK_OVERRIDE {
542 for (;;) {
543 int count = *runs;
544 if (count <= 0) {
545 return;
546 }
547 fBuilder->addRun(x, y, *alpha, count);
548 runs += count;
549 alpha += count;
550 x += count;
551 }
552 }
553
554private:
555 Builder* fBuilder;
556
557 void unexpected() {
558 SkDebugf("---- did not expect to get called here");
559 sk_throw();
560 }
561};
562
reed@google.comf3c1da12011-10-10 19:35:47 +0000563bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com32287892011-10-05 16:27:44 +0000564 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000565 return this->setEmpty();
566 }
567
568 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +0000569 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +0000570
reed@google.com32287892011-10-05 16:27:44 +0000571 SkRegion tmpClip;
572 if (NULL == clip) {
573 tmpClip.setRect(ibounds);
574 clip = &tmpClip;
575 }
576
reed@google.come36707a2011-10-04 21:38:55 +0000577 if (!path.isInverseFillType()) {
reed@google.com32287892011-10-05 16:27:44 +0000578 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +0000579 return this->setEmpty();
580 }
reed@google.come36707a2011-10-04 21:38:55 +0000581 }
582
583 Builder builder(ibounds);
584 BuilderBlitter blitter(&builder);
585
reed@google.comf3c1da12011-10-10 19:35:47 +0000586 if (doAA) {
587 SkScan::AntiFillPath(path, *clip, &blitter, true);
588 } else {
589 SkScan::FillPath(path, *clip, &blitter);
590 }
reed@google.come36707a2011-10-04 21:38:55 +0000591
592 this->freeRuns();
593 fBounds = ibounds;
594 fRunHead = builder.finish();
595
596 builder.dump();
597}
598
599///////////////////////////////////////////////////////////////////////////////
600
reed@google.com32287892011-10-05 16:27:44 +0000601typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
602 const uint8_t* rowA, const SkIRect& rectA,
603 const uint8_t* rowB, const SkIRect& rectB);
604
605static void sectRowProc(SkAAClip::Builder& builder, int bottom,
606 const uint8_t* rowA, const SkIRect& rectA,
607 const uint8_t* rowB, const SkIRect& rectB) {
608
609}
610
611typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
612
613static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
614 // Multiply
615 return SkMulDiv255Round(alphaA, alphaB);
616}
617
618static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
619 // SrcOver
620 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
621}
622
623static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
624 // SrcOut
625 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
626}
627
628static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
629 // XOR
630 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
631}
632
633static AlphaProc find_alpha_proc(SkRegion::Op op) {
634 switch (op) {
635 case SkRegion::kIntersect_Op:
636 return sectAlphaProc;
637 case SkRegion::kDifference_Op:
638 return diffAlphaProc;
639 case SkRegion::kUnion_Op:
640 return unionAlphaProc;
641 case SkRegion::kXOR_Op:
642 return xorAlphaProc;
643 default:
644 SkASSERT(!"unexpected region op");
645 return sectAlphaProc;
646 }
647}
648
649static const uint8_t gEmptyRow[] = {
650 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
651 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
652 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
653 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
654 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
655 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
656 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
657 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
658};
659
660class RowIter {
661public:
662 RowIter(const uint8_t* row, const SkIRect& bounds) {
663 fRow = row;
664 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +0000665 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000666 if (row) {
667 fRight = bounds.fLeft + row[0];
668 SkASSERT(fRight <= fBoundsRight);
669 fAlpha = row[1];
670 fDone = false;
671 } else {
672 fDone = true;
673 fRight = kMaxInt32;
674 fAlpha = 0;
675 }
reed@google.com32287892011-10-05 16:27:44 +0000676 }
677
678 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000679 int left() const { return fLeft; }
680 int right() const { return fRight; }
681 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +0000682 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000683 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +0000684 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000685 if (fRight == fBoundsRight) {
686 fDone = true;
687 fRight = kMaxInt32;
688 fAlpha = 0;
689 } else {
690 fRow += 2;
691 fRight += fRow[0];
692 fAlpha = fRow[1];
693 SkASSERT(fRight <= fBoundsRight);
694 }
reed@google.com32287892011-10-05 16:27:44 +0000695 }
696 }
697
698private:
699 const uint8_t* fRow;
700 int fLeft;
701 int fRight;
702 int fBoundsRight;
703 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +0000704 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +0000705};
706
reed@google.com1c04bf92011-10-10 12:57:12 +0000707static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
708 if (rite == riteA) {
709 iter.next();
710 leftA = iter.left();
711 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +0000712 }
713}
714
reed@google.com1c04bf92011-10-10 12:57:12 +0000715static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
716 SkASSERT(min < max);
717 SkASSERT(boundsMin < boundsMax);
718 if (min >= boundsMax || max <= boundsMin) {
719 return false;
720 }
721 if (min < boundsMin) {
722 min = boundsMin;
723 }
724 if (max > boundsMax) {
725 max = boundsMax;
726 }
727 return true;
728}
729
reed@google.com32287892011-10-05 16:27:44 +0000730static void operatorX(SkAAClip::Builder& builder, int lastY,
731 RowIter& iterA, RowIter& iterB,
732 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +0000733 int leftA = iterA.left();
734 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +0000735 int leftB = iterB.left();
736 int riteB = iterB.right();
737
reed@google.com1c04bf92011-10-10 12:57:12 +0000738 int prevRite = bounds.fLeft;
739
740 do {
reed@google.com32287892011-10-05 16:27:44 +0000741 U8CPU alphaA = 0;
742 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +0000743 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +0000744
745 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +0000746 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +0000747 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +0000748 if (riteA <= leftB) {
749 rite = riteA;
750 } else {
751 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +0000752 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000753 } else if (leftB < leftA) {
754 left = leftB;
755 alphaB = iterB.alpha();
756 if (riteB <= leftA) {
757 rite = riteB;
758 } else {
759 rite = leftB = leftA;
760 }
761 } else {
762 left = leftA; // or leftB, since leftA == leftB
763 rite = leftA = leftB = SkMin32(riteA, riteB);
764 alphaA = iterA.alpha();
765 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +0000766 }
767
768 if (left >= bounds.fRight) {
769 break;
770 }
reed@google.com32287892011-10-05 16:27:44 +0000771 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +0000772 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +0000773 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +0000774 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +0000775 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000776
777 adjust_row(iterA, leftA, riteA, rite);
778 adjust_row(iterB, leftB, riteB, rite);
779 } while (!iterA.done() || !iterB.done());
780
781 if (prevRite < bounds.fRight) {
782 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +0000783 }
784}
785
reed@google.com1c04bf92011-10-10 12:57:12 +0000786static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
787 if (bot == botA) {
788 iter.next();
789 topA = botA;
790 SkASSERT(botA == iter.top());
791 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +0000792 }
793}
794
795static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
796 const SkAAClip& B, SkRegion::Op op) {
797 AlphaProc proc = find_alpha_proc(op);
798 const SkIRect& bounds = builder.getBounds();
799
800 SkAAClip::Iter iterA(A);
801 SkAAClip::Iter iterB(B);
802
803 SkASSERT(!iterA.done());
804 int topA = iterA.top();
805 int botA = iterA.bottom();
806 SkASSERT(!iterB.done());
807 int topB = iterB.top();
808 int botB = iterB.bottom();
809
reed@google.com1c04bf92011-10-10 12:57:12 +0000810 do {
811 const uint8_t* rowA = NULL;
812 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +0000813 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +0000814
815 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +0000816 top = topA;
reed@google.com32287892011-10-05 16:27:44 +0000817 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +0000818 if (botA <= topB) {
819 bot = botA;
820 } else {
821 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +0000822 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000823
824 } else if (topB < topA) {
825 top = topB;
826 rowB = iterB.data();
827 if (botB <= topA) {
828 bot = botB;
829 } else {
830 bot = topB = topA;
831 }
832 } else {
833 top = topA; // or topB, since topA == topB
834 bot = topA = topB = SkMin32(botA, botB);
835 rowA = iterA.data();
836 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +0000837 }
838
839 if (top >= bounds.fBottom) {
840 break;
841 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000842 if (!rowA && !rowB) {
843 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
844 } else if (top >= bounds.fTop) {
845 SkASSERT(bot <= bounds.fBottom);
846 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
847 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +0000848 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +0000849 }
850
reed@google.com1c04bf92011-10-10 12:57:12 +0000851 adjust_iter(iterA, topA, botA, bot);
852 adjust_iter(iterB, topB, botB, bot);
853 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +0000854}
855
856bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
857 SkRegion::Op op) {
858 if (SkRegion::kReplace_Op == op) {
859 return this->set(clipBOrig);
860 }
861
862 const SkAAClip* clipA = &clipAOrig;
863 const SkAAClip* clipB = &clipBOrig;
864
865 if (SkRegion::kReverseDifference_Op == op) {
866 SkTSwap(clipA, clipB);
867 op = SkRegion::kDifference_Op;
868 }
869
870 bool a_empty = clipA->isEmpty();
871 bool b_empty = clipB->isEmpty();
872
873 SkIRect bounds;
874 switch (op) {
875 case SkRegion::kDifference_Op:
876 if (a_empty) {
877 return this->setEmpty();
878 }
879 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
880 return this->set(*clipA);
881 }
882 bounds = clipA->fBounds;
883 break;
884
885 case SkRegion::kIntersect_Op:
886 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
887 clipB->fBounds)) {
888 return this->setEmpty();
889 }
890 break;
891
892 case SkRegion::kUnion_Op:
893 case SkRegion::kXOR_Op:
894 if (a_empty) {
895 return this->set(*clipB);
896 }
897 if (b_empty) {
898 return this->set(*clipA);
899 }
900 bounds = clipA->fBounds;
901 bounds.join(clipB->fBounds);
902 break;
903
904 default:
905 SkASSERT(!"unknown region op");
906 return !this->isEmpty();
907 }
908
reed@google.com32287892011-10-05 16:27:44 +0000909 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
910 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
911
912 Builder builder(bounds);
913 operateY(builder, *clipA, *clipB, op);
914 // don't free us until now, since we might be clipA or clipB
915 this->freeRuns();
916 fBounds = bounds;
917 fRunHead = builder.finish();
918
919 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000920}
921
reed@google.com47ac84e2011-10-06 13:11:25 +0000922bool SkAAClip::op(const SkIRect& r, SkRegion::Op op) {
923 SkAAClip clip;
924 clip.setRect(r);
925 return this->op(*this, clip, op);
926}
927
928bool SkAAClip::op(const SkRect& r, SkRegion::Op op) {
929 SkAAClip clip;
930 clip.setRect(r);
931 return this->op(*this, clip, op);
932}
933
934bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
935 return this->op(*this, clip, op);
936}
937
reed@google.come36707a2011-10-04 21:38:55 +0000938///////////////////////////////////////////////////////////////////////////////
939///////////////////////////////////////////////////////////////////////////////
940
941static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
942 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
943 // we don't read our initial n from data, since the caller may have had to
944 // clip it, hence the initialCount parameter.
945 int n = initialCount;
946 for (;;) {
947 if (n > width) {
948 n = width;
949 }
950 SkASSERT(n > 0);
951 runs[0] = n;
952 runs += n;
953
954 aa[0] = data[1];
955 aa += n;
956
957 data += 2;
958 width -= n;
959 if (0 == width) {
960 break;
961 }
962 // load the next count
963 n = data[0];
964 }
965 runs[0] = 0; // sentinel
966}
967
968SkAAClipBlitter::~SkAAClipBlitter() {
969 sk_free(fRuns);
970}
971
972void SkAAClipBlitter::ensureRunsAndAA() {
973 if (NULL == fRuns) {
974 // add 1 so we can store the terminating run count of 0
975 int count = fAAClipBounds.width() + 1;
976 fRuns = (int16_t*)sk_malloc_throw(count * sizeof(int16_t) +
977 count * sizeof(SkAlpha));
978 fAA = (SkAlpha*)(fRuns + count);
979 }
980}
981
982void SkAAClipBlitter::blitH(int x, int y, int width) {
983 SkASSERT(width > 0);
984 SkASSERT(fAAClipBounds.contains(x, y));
985 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
986
987 int lastY;
988 const uint8_t* row = fAAClip->findRow(y, &lastY);
989 int initialCount;
990 row = fAAClip->findX(row, x, &initialCount);
991
992 if (initialCount >= width) {
993 SkAlpha alpha = row[1];
994 if (0 == alpha) {
995 return;
996 }
997 if (0xFF == alpha) {
998 fBlitter->blitH(x, y, width);
999 return;
1000 }
1001 }
1002
1003 this->ensureRunsAndAA();
1004 expandToRuns(row, initialCount, width, fRuns, fAA);
1005
1006 fBlitter->blitAntiH(x, y, fAA, fRuns);
1007}
1008
1009static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1010 const SkAlpha* SK_RESTRICT srcAA,
1011 const int16_t* SK_RESTRICT srcRuns,
1012 SkAlpha* SK_RESTRICT dstAA,
1013 int16_t* SK_RESTRICT dstRuns,
1014 int width) {
1015 SkDEBUGCODE(int accumulated = 0;)
1016 int srcN = srcRuns[0];
1017 for (;;) {
1018 if (0 == srcN) {
1019 break;
1020 }
1021 SkASSERT(rowN > 0);
1022 SkASSERT(srcN > 0);
1023
1024 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1025 int minN = SkMin32(srcN, rowN);
1026 dstRuns[0] = minN;
1027 dstRuns += minN;
1028 dstAA[0] = newAlpha;
1029 dstAA += minN;
1030
1031 if (0 == (srcN -= minN)) {
1032 srcN = srcRuns[0]; // refresh
1033 srcRuns += srcN;
1034 srcAA += srcN;
1035 srcN = srcRuns[0]; // reload
1036 }
1037 if (0 == (rowN -= minN)) {
1038 row += 2;
1039 rowN = row[0]; // reload
1040 }
1041
1042 SkDEBUGCODE(accumulated += minN;)
1043 SkASSERT(accumulated <= width);
1044 }
1045}
1046
1047void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1048 const int16_t runs[]) {
1049 int lastY;
1050 const uint8_t* row = fAAClip->findRow(y, &lastY);
1051 int initialCount;
1052 row = fAAClip->findX(row, x, &initialCount);
1053
1054 this->ensureRunsAndAA();
1055
1056 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1057 fBlitter->blitAntiH(x, y, fAA, fRuns);
1058}
1059
1060void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1061 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1062 fBlitter->blitV(x, y, height, alpha);
1063 return;
1064 }
1065
1066 int stopY = y + height;
1067 do {
1068 int lastY;
1069 const uint8_t* row = fAAClip->findRow(y, &lastY);
1070 int initialCount;
1071 row = fAAClip->findX(row, x, &initialCount);
1072 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1073 if (newAlpha) {
1074 fBlitter->blitV(x, y, lastY - y + 1, newAlpha);
1075 }
1076 y = lastY + 1;
1077 } while (y < stopY);
1078}
1079
1080void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1081 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1082 fBlitter->blitRect(x, y, width, height);
1083 return;
1084 }
1085
1086 while (--height >= 0) {
1087 this->blitH(x, y, width);
1088 y += 1;
1089 }
1090}
1091
1092void SkAAClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
1093 fBlitter->blitMask(mask, clip);
1094}
1095
1096const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1097 return NULL;
1098}
1099
reed@google.com32287892011-10-05 16:27:44 +00001100///////////////////////////////////////////////////////////////////////////////
1101
reed@google.com1c04bf92011-10-10 12:57:12 +00001102bool SkAAClip::offset(int dx, int dy) {
1103 if (this->isEmpty()) {
1104 return false;
1105 }
1106
1107 fBounds.offset(dx, dy);
1108 return true;
1109}
1110
1111bool SkAAClip::offset(int dx, int dy, SkAAClip* dst) const {
1112 if (this == dst) {
1113 return dst->offset(dx, dy);
1114 }
1115
1116 dst->setEmpty();
1117 if (this->isEmpty()) {
1118 return false;
1119 }
1120
1121 sk_atomic_inc(&fRunHead->fRefCnt);
1122 dst->fRunHead = fRunHead;
1123 dst->fBounds = fBounds;
1124 dst->fBounds.offset(dx, dy);
1125 return true;
1126}
1127
reed@google.com32287892011-10-05 16:27:44 +00001128static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1129 const uint8_t* SK_RESTRICT row,
1130 int width) {
1131 while (width > 0) {
1132 int n = row[0];
1133 SkASSERT(width >= n);
1134 memset(mask, row[1], n);
1135 mask += n;
1136 row += 2;
1137 width -= n;
1138 }
1139}
1140
1141void SkAAClip::copyToMask(SkMask* mask) const {
1142 mask->fFormat = SkMask::kA8_Format;
1143 if (this->isEmpty()) {
1144 mask->fBounds.setEmpty();
1145 mask->fImage = NULL;
1146 mask->fRowBytes = 0;
1147 return;
1148 }
1149
1150 mask->fBounds = fBounds;
1151 mask->fRowBytes = fBounds.width();
1152 size_t size = mask->computeImageSize();
1153 mask->fImage = SkMask::AllocImage(size);
1154
1155 Iter iter(*this);
1156 uint8_t* dst = mask->fImage;
1157 const int width = fBounds.width();
1158
1159 int y = fBounds.fTop;
1160 while (!iter.done()) {
1161 do {
1162 expand_row_to_mask(dst, iter.data(), width);
1163 dst += mask->fRowBytes;
1164 } while (++y < iter.bottom());
1165 iter.next();
1166 }
1167}
1168