blob: 2955b61070ce16bbcf53054f690c8612f632fd22 [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.com3771a032011-10-11 17:18:04 +0000237 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000238}
239
240///////////////////////////////////////////////////////////////////////////////
241
242const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000243 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000244
245 if (!y_in_rect(y, fBounds)) {
246 return NULL;
247 }
248 y -= fBounds.y(); // our yoffs values are relative to the top
249
250 const YOffset* yoff = fRunHead->yoffsets();
251 while (yoff->fY < y) {
252 yoff += 1;
253 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
254 }
255
256 if (lastYForRow) {
257 *lastYForRow = yoff->fY;
258 }
259 return fRunHead->data() + yoff->fOffset;
260}
261
262const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
263 SkASSERT(x_in_rect(x, fBounds));
264 x -= fBounds.x();
265
266 // first skip up to X
267 for (;;) {
268 int n = data[0];
269 if (x < n) {
270 *initialCount = n - x;
271 break;
272 }
273 data += 2;
274 x -= n;
275 }
276 return data;
277}
278
279bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
280 if (this->isEmpty()) {
281 return false;
282 }
283 if (!fBounds.contains(left, top, right, bottom)) {
284 return false;
285 }
reed@google.com32287892011-10-05 16:27:44 +0000286#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000287 if (this->isRect()) {
288 return true;
289 }
reed@google.com32287892011-10-05 16:27:44 +0000290#endif
reed@google.come36707a2011-10-04 21:38:55 +0000291
292 int lastY;
293 const uint8_t* row = this->findRow(top, &lastY);
294 if (lastY < bottom) {
295 return false;
296 }
297 // now just need to check in X
298 int initialCount;
299 row = this->findX(row, left, &initialCount);
300 return initialCount >= (right - left) && 0xFF == row[1];
301}
302
303///////////////////////////////////////////////////////////////////////////////
304
305class SkAAClip::Builder {
306 SkIRect fBounds;
307 struct Row {
308 int fY;
309 int fWidth;
310 SkTDArray<uint8_t>* fData;
311 };
312 SkTDArray<Row> fRows;
313 Row* fCurrRow;
314 int fPrevY;
315 int fWidth;
316
317public:
318 Builder(const SkIRect& bounds) : fBounds(bounds) {
319 fPrevY = -1;
320 fWidth = bounds.width();
321 fCurrRow = NULL;
322 }
323
324 ~Builder() {
325 Row* row = fRows.begin();
326 Row* stop = fRows.end();
327 while (row < stop) {
328 delete row->fData;
329 row += 1;
330 }
331 }
332
reed@google.com32287892011-10-05 16:27:44 +0000333 const SkIRect& getBounds() const { return fBounds; }
334
reed@google.come36707a2011-10-04 21:38:55 +0000335 void addRun(int x, int y, U8CPU alpha, int count) {
336 SkASSERT(count > 0);
337 SkASSERT(fBounds.contains(x, y));
338 SkASSERT(fBounds.contains(x + count - 1, y));
339
340 x -= fBounds.left();
341 y -= fBounds.top();
342
343 Row* row = fCurrRow;
344 if (y != fPrevY) {
345 SkASSERT(y > fPrevY);
346 fPrevY = y;
347 row = this->flushRow(true);
348 row->fY = y;
349 row->fWidth = 0;
350 SkASSERT(row->fData);
351 SkASSERT(0 == row->fData->count());
352 fCurrRow = row;
353 }
354
355 SkASSERT(row->fWidth <= x);
356 SkASSERT(row->fWidth < fBounds.width());
357
358 SkTDArray<uint8_t>& data = *row->fData;
359
360 int gap = x - row->fWidth;
361 if (gap) {
362 AppendRun(data, 0, gap);
363 row->fWidth += gap;
364 SkASSERT(row->fWidth < fBounds.width());
365 }
366
367 AppendRun(data, alpha, count);
368 row->fWidth += count;
369 SkASSERT(row->fWidth <= fBounds.width());
370 }
371
372 RunHead* finish() {
373 this->flushRow(false);
374
375 const Row* row = fRows.begin();
376 const Row* stop = fRows.end();
377
378 size_t dataSize = 0;
379 while (row < stop) {
380 dataSize += row->fData->count();
381 row += 1;
382 }
383
384 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
385 YOffset* yoffset = head->yoffsets();
386 uint8_t* data = head->data();
387 uint8_t* baseData = data;
388
389 row = fRows.begin();
390 while (row < stop) {
391 yoffset->fY = row->fY;
392 yoffset->fOffset = data - baseData;
393 yoffset += 1;
394
395 size_t n = row->fData->count();
396 memcpy(data, row->fData->begin(), n);
397 data += n;
398
399 row += 1;
400 }
401
402 return head;
403 }
404
405 void dump() {
406 this->validate();
407 int y;
408 for (y = 0; y < fRows.count(); ++y) {
409 const Row& row = fRows[y];
410 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
411 const SkTDArray<uint8_t>& data = *row.fData;
412 int count = data.count();
413 SkASSERT(!(count & 1));
414 const uint8_t* ptr = data.begin();
415 for (int x = 0; x < count; x += 2) {
416 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
417 ptr += 2;
418 }
419 SkDebugf("\n");
420 }
421
reed@google.com1c04bf92011-10-10 12:57:12 +0000422#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000423 int prevY = -1;
424 for (y = 0; y < fRows.count(); ++y) {
425 const Row& row = fRows[y];
426 const SkTDArray<uint8_t>& data = *row.fData;
427 int count = data.count();
428 for (int n = prevY; n < row.fY; ++n) {
429 const uint8_t* ptr = data.begin();
430 for (int x = 0; x < count; x += 2) {
431 for (int i = 0; i < ptr[0]; ++i) {
432 SkDebugf("%02X", ptr[1]);
433 }
434 ptr += 2;
435 }
436 SkDebugf("\n");
437 }
438 prevY = row.fY;
439 }
440#endif
441 }
442
443 void validate() {
444#ifdef SK_DEBUG
445 int prevY = -1;
446 for (int i = 0; i < fRows.count(); ++i) {
447 const Row& row = fRows[i];
448 SkASSERT(prevY < row.fY);
449 SkASSERT(fWidth == row.fWidth);
450 int count = row.fData->count();
451 const uint8_t* ptr = row.fData->begin();
452 SkASSERT(!(count & 1));
453 int w = 0;
454 for (int x = 0; x < count; x += 2) {
455 w += ptr[0];
456 SkASSERT(w <= fWidth);
457 ptr += 2;
458 }
459 SkASSERT(w == fWidth);
460 prevY = row.fY;
461 }
462#endif
463 }
464
465private:
466 Row* flushRow(bool readyForAnother) {
467 Row* next = NULL;
468 int count = fRows.count();
469 if (count > 0) {
470 // flush current row if needed
471 Row* curr = &fRows[count - 1];
472 if (curr->fWidth < fWidth) {
473 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
474 }
475 }
476 if (count > 1) {
477 // are our last two runs the same?
478 Row* prev = &fRows[count - 2];
479 Row* curr = &fRows[count - 1];
480 SkASSERT(prev->fWidth == fWidth);
481 SkASSERT(curr->fWidth == fWidth);
482 if (*prev->fData == *curr->fData) {
483 prev->fY = curr->fY;
484 if (readyForAnother) {
485 curr->fData->rewind();
486 next = curr;
487 } else {
488 delete curr->fData;
489 fRows.removeShuffle(count - 1);
490 }
491 } else {
492 if (readyForAnother) {
493 next = fRows.append();
494 next->fData = new SkTDArray<uint8_t>;
495 }
496 }
497 } else {
498 if (readyForAnother) {
499 next = fRows.append();
500 next->fData = new SkTDArray<uint8_t>;
501 }
502 }
503 return next;
504 }
505
506 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
507 do {
508 int n = count;
509 if (n > 255) {
510 n = 255;
511 }
512 uint8_t* ptr = data.append(2);
513 ptr[0] = n;
514 ptr[1] = alpha;
515 count -= n;
516 } while (count > 0);
517 }
518};
519
520class SkAAClip::BuilderBlitter : public SkBlitter {
521public:
522 BuilderBlitter(Builder* builder) {
523 fBuilder = builder;
524 }
525
526 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
527 { unexpected(); }
528 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
529 { unexpected(); }
530 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
531 { unexpected(); }
532
533 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +0000534 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000535 }
536
537 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
538 fBuilder->addRun(x, y, 0xFF, width);
539 }
540
541 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
542 const int16_t runs[]) SK_OVERRIDE {
543 for (;;) {
544 int count = *runs;
545 if (count <= 0) {
546 return;
547 }
548 fBuilder->addRun(x, y, *alpha, count);
549 runs += count;
550 alpha += count;
551 x += count;
552 }
553 }
554
555private:
556 Builder* fBuilder;
557
558 void unexpected() {
559 SkDebugf("---- did not expect to get called here");
560 sk_throw();
561 }
562};
563
reed@google.comf3c1da12011-10-10 19:35:47 +0000564bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com32287892011-10-05 16:27:44 +0000565 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000566 return this->setEmpty();
567 }
568
569 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +0000570 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +0000571
reed@google.com32287892011-10-05 16:27:44 +0000572 SkRegion tmpClip;
573 if (NULL == clip) {
574 tmpClip.setRect(ibounds);
575 clip = &tmpClip;
576 }
577
reed@google.come36707a2011-10-04 21:38:55 +0000578 if (!path.isInverseFillType()) {
reed@google.com32287892011-10-05 16:27:44 +0000579 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +0000580 return this->setEmpty();
581 }
reed@google.come36707a2011-10-04 21:38:55 +0000582 }
583
584 Builder builder(ibounds);
585 BuilderBlitter blitter(&builder);
586
reed@google.comf3c1da12011-10-10 19:35:47 +0000587 if (doAA) {
588 SkScan::AntiFillPath(path, *clip, &blitter, true);
589 } else {
590 SkScan::FillPath(path, *clip, &blitter);
591 }
reed@google.come36707a2011-10-04 21:38:55 +0000592
593 this->freeRuns();
594 fBounds = ibounds;
595 fRunHead = builder.finish();
596
reed@google.com3771a032011-10-11 17:18:04 +0000597 //builder.dump();
598 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000599}
600
601///////////////////////////////////////////////////////////////////////////////
602
reed@google.com32287892011-10-05 16:27:44 +0000603typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
604 const uint8_t* rowA, const SkIRect& rectA,
605 const uint8_t* rowB, const SkIRect& rectB);
606
607static void sectRowProc(SkAAClip::Builder& builder, int bottom,
608 const uint8_t* rowA, const SkIRect& rectA,
609 const uint8_t* rowB, const SkIRect& rectB) {
610
611}
612
613typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
614
615static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
616 // Multiply
617 return SkMulDiv255Round(alphaA, alphaB);
618}
619
620static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
621 // SrcOver
622 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
623}
624
625static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
626 // SrcOut
627 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
628}
629
630static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
631 // XOR
632 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
633}
634
635static AlphaProc find_alpha_proc(SkRegion::Op op) {
636 switch (op) {
637 case SkRegion::kIntersect_Op:
638 return sectAlphaProc;
639 case SkRegion::kDifference_Op:
640 return diffAlphaProc;
641 case SkRegion::kUnion_Op:
642 return unionAlphaProc;
643 case SkRegion::kXOR_Op:
644 return xorAlphaProc;
645 default:
646 SkASSERT(!"unexpected region op");
647 return sectAlphaProc;
648 }
649}
650
651static const uint8_t gEmptyRow[] = {
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 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
659 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
660};
661
662class RowIter {
663public:
664 RowIter(const uint8_t* row, const SkIRect& bounds) {
665 fRow = row;
666 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +0000667 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000668 if (row) {
669 fRight = bounds.fLeft + row[0];
670 SkASSERT(fRight <= fBoundsRight);
671 fAlpha = row[1];
672 fDone = false;
673 } else {
674 fDone = true;
675 fRight = kMaxInt32;
676 fAlpha = 0;
677 }
reed@google.com32287892011-10-05 16:27:44 +0000678 }
679
680 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000681 int left() const { return fLeft; }
682 int right() const { return fRight; }
683 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +0000684 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000685 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +0000686 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000687 if (fRight == fBoundsRight) {
688 fDone = true;
689 fRight = kMaxInt32;
690 fAlpha = 0;
691 } else {
692 fRow += 2;
693 fRight += fRow[0];
694 fAlpha = fRow[1];
695 SkASSERT(fRight <= fBoundsRight);
696 }
reed@google.com32287892011-10-05 16:27:44 +0000697 }
698 }
699
700private:
701 const uint8_t* fRow;
702 int fLeft;
703 int fRight;
704 int fBoundsRight;
705 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +0000706 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +0000707};
708
reed@google.com1c04bf92011-10-10 12:57:12 +0000709static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
710 if (rite == riteA) {
711 iter.next();
712 leftA = iter.left();
713 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +0000714 }
715}
716
reed@google.com1c04bf92011-10-10 12:57:12 +0000717static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
718 SkASSERT(min < max);
719 SkASSERT(boundsMin < boundsMax);
720 if (min >= boundsMax || max <= boundsMin) {
721 return false;
722 }
723 if (min < boundsMin) {
724 min = boundsMin;
725 }
726 if (max > boundsMax) {
727 max = boundsMax;
728 }
729 return true;
730}
731
reed@google.com32287892011-10-05 16:27:44 +0000732static void operatorX(SkAAClip::Builder& builder, int lastY,
733 RowIter& iterA, RowIter& iterB,
734 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +0000735 int leftA = iterA.left();
736 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +0000737 int leftB = iterB.left();
738 int riteB = iterB.right();
739
reed@google.com1c04bf92011-10-10 12:57:12 +0000740 int prevRite = bounds.fLeft;
741
742 do {
reed@google.com32287892011-10-05 16:27:44 +0000743 U8CPU alphaA = 0;
744 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +0000745 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +0000746
747 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +0000748 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +0000749 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +0000750 if (riteA <= leftB) {
751 rite = riteA;
752 } else {
753 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +0000754 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000755 } else if (leftB < leftA) {
756 left = leftB;
757 alphaB = iterB.alpha();
758 if (riteB <= leftA) {
759 rite = riteB;
760 } else {
761 rite = leftB = leftA;
762 }
763 } else {
764 left = leftA; // or leftB, since leftA == leftB
765 rite = leftA = leftB = SkMin32(riteA, riteB);
766 alphaA = iterA.alpha();
767 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +0000768 }
769
770 if (left >= bounds.fRight) {
771 break;
772 }
reed@google.com32287892011-10-05 16:27:44 +0000773 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +0000774 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +0000775 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +0000776 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +0000777 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000778
779 adjust_row(iterA, leftA, riteA, rite);
780 adjust_row(iterB, leftB, riteB, rite);
781 } while (!iterA.done() || !iterB.done());
782
783 if (prevRite < bounds.fRight) {
784 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +0000785 }
786}
787
reed@google.com1c04bf92011-10-10 12:57:12 +0000788static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
789 if (bot == botA) {
790 iter.next();
791 topA = botA;
792 SkASSERT(botA == iter.top());
793 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +0000794 }
795}
796
797static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
798 const SkAAClip& B, SkRegion::Op op) {
799 AlphaProc proc = find_alpha_proc(op);
800 const SkIRect& bounds = builder.getBounds();
801
802 SkAAClip::Iter iterA(A);
803 SkAAClip::Iter iterB(B);
804
805 SkASSERT(!iterA.done());
806 int topA = iterA.top();
807 int botA = iterA.bottom();
808 SkASSERT(!iterB.done());
809 int topB = iterB.top();
810 int botB = iterB.bottom();
811
reed@google.com1c04bf92011-10-10 12:57:12 +0000812 do {
813 const uint8_t* rowA = NULL;
814 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +0000815 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +0000816
817 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +0000818 top = topA;
reed@google.com32287892011-10-05 16:27:44 +0000819 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +0000820 if (botA <= topB) {
821 bot = botA;
822 } else {
823 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +0000824 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000825
826 } else if (topB < topA) {
827 top = topB;
828 rowB = iterB.data();
829 if (botB <= topA) {
830 bot = botB;
831 } else {
832 bot = topB = topA;
833 }
834 } else {
835 top = topA; // or topB, since topA == topB
836 bot = topA = topB = SkMin32(botA, botB);
837 rowA = iterA.data();
838 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +0000839 }
840
841 if (top >= bounds.fBottom) {
842 break;
843 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000844 if (!rowA && !rowB) {
845 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
846 } else if (top >= bounds.fTop) {
847 SkASSERT(bot <= bounds.fBottom);
848 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
849 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +0000850 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +0000851 }
852
reed@google.com1c04bf92011-10-10 12:57:12 +0000853 adjust_iter(iterA, topA, botA, bot);
854 adjust_iter(iterB, topB, botB, bot);
855 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +0000856}
857
858bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
859 SkRegion::Op op) {
860 if (SkRegion::kReplace_Op == op) {
861 return this->set(clipBOrig);
862 }
863
864 const SkAAClip* clipA = &clipAOrig;
865 const SkAAClip* clipB = &clipBOrig;
866
867 if (SkRegion::kReverseDifference_Op == op) {
868 SkTSwap(clipA, clipB);
869 op = SkRegion::kDifference_Op;
870 }
871
872 bool a_empty = clipA->isEmpty();
873 bool b_empty = clipB->isEmpty();
874
875 SkIRect bounds;
876 switch (op) {
877 case SkRegion::kDifference_Op:
878 if (a_empty) {
879 return this->setEmpty();
880 }
881 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
882 return this->set(*clipA);
883 }
884 bounds = clipA->fBounds;
885 break;
886
887 case SkRegion::kIntersect_Op:
888 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
889 clipB->fBounds)) {
890 return this->setEmpty();
891 }
892 break;
893
894 case SkRegion::kUnion_Op:
895 case SkRegion::kXOR_Op:
896 if (a_empty) {
897 return this->set(*clipB);
898 }
899 if (b_empty) {
900 return this->set(*clipA);
901 }
902 bounds = clipA->fBounds;
903 bounds.join(clipB->fBounds);
904 break;
905
906 default:
907 SkASSERT(!"unknown region op");
908 return !this->isEmpty();
909 }
910
reed@google.com32287892011-10-05 16:27:44 +0000911 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
912 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
913
914 Builder builder(bounds);
915 operateY(builder, *clipA, *clipB, op);
916 // don't free us until now, since we might be clipA or clipB
917 this->freeRuns();
918 fBounds = bounds;
919 fRunHead = builder.finish();
920
921 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000922}
923
reed@google.com47ac84e2011-10-06 13:11:25 +0000924bool SkAAClip::op(const SkIRect& r, SkRegion::Op op) {
925 SkAAClip clip;
926 clip.setRect(r);
927 return this->op(*this, clip, op);
928}
929
930bool SkAAClip::op(const SkRect& r, SkRegion::Op op) {
931 SkAAClip clip;
932 clip.setRect(r);
933 return this->op(*this, clip, op);
934}
935
936bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
937 return this->op(*this, clip, op);
938}
939
reed@google.come36707a2011-10-04 21:38:55 +0000940///////////////////////////////////////////////////////////////////////////////
941///////////////////////////////////////////////////////////////////////////////
942
943static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
944 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
945 // we don't read our initial n from data, since the caller may have had to
946 // clip it, hence the initialCount parameter.
947 int n = initialCount;
948 for (;;) {
949 if (n > width) {
950 n = width;
951 }
952 SkASSERT(n > 0);
953 runs[0] = n;
954 runs += n;
955
956 aa[0] = data[1];
957 aa += n;
958
959 data += 2;
960 width -= n;
961 if (0 == width) {
962 break;
963 }
964 // load the next count
965 n = data[0];
966 }
967 runs[0] = 0; // sentinel
968}
969
970SkAAClipBlitter::~SkAAClipBlitter() {
971 sk_free(fRuns);
972}
973
974void SkAAClipBlitter::ensureRunsAndAA() {
975 if (NULL == fRuns) {
976 // add 1 so we can store the terminating run count of 0
977 int count = fAAClipBounds.width() + 1;
978 fRuns = (int16_t*)sk_malloc_throw(count * sizeof(int16_t) +
979 count * sizeof(SkAlpha));
980 fAA = (SkAlpha*)(fRuns + count);
981 }
982}
983
984void SkAAClipBlitter::blitH(int x, int y, int width) {
985 SkASSERT(width > 0);
986 SkASSERT(fAAClipBounds.contains(x, y));
987 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
988
989 int lastY;
990 const uint8_t* row = fAAClip->findRow(y, &lastY);
991 int initialCount;
992 row = fAAClip->findX(row, x, &initialCount);
993
994 if (initialCount >= width) {
995 SkAlpha alpha = row[1];
996 if (0 == alpha) {
997 return;
998 }
999 if (0xFF == alpha) {
1000 fBlitter->blitH(x, y, width);
1001 return;
1002 }
1003 }
1004
1005 this->ensureRunsAndAA();
1006 expandToRuns(row, initialCount, width, fRuns, fAA);
1007
1008 fBlitter->blitAntiH(x, y, fAA, fRuns);
1009}
1010
1011static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1012 const SkAlpha* SK_RESTRICT srcAA,
1013 const int16_t* SK_RESTRICT srcRuns,
1014 SkAlpha* SK_RESTRICT dstAA,
1015 int16_t* SK_RESTRICT dstRuns,
1016 int width) {
1017 SkDEBUGCODE(int accumulated = 0;)
1018 int srcN = srcRuns[0];
1019 for (;;) {
1020 if (0 == srcN) {
1021 break;
1022 }
1023 SkASSERT(rowN > 0);
1024 SkASSERT(srcN > 0);
1025
1026 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1027 int minN = SkMin32(srcN, rowN);
1028 dstRuns[0] = minN;
1029 dstRuns += minN;
1030 dstAA[0] = newAlpha;
1031 dstAA += minN;
1032
1033 if (0 == (srcN -= minN)) {
1034 srcN = srcRuns[0]; // refresh
1035 srcRuns += srcN;
1036 srcAA += srcN;
1037 srcN = srcRuns[0]; // reload
1038 }
1039 if (0 == (rowN -= minN)) {
1040 row += 2;
1041 rowN = row[0]; // reload
1042 }
1043
1044 SkDEBUGCODE(accumulated += minN;)
1045 SkASSERT(accumulated <= width);
1046 }
1047}
1048
1049void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1050 const int16_t runs[]) {
1051 int lastY;
1052 const uint8_t* row = fAAClip->findRow(y, &lastY);
1053 int initialCount;
1054 row = fAAClip->findX(row, x, &initialCount);
1055
1056 this->ensureRunsAndAA();
1057
1058 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1059 fBlitter->blitAntiH(x, y, fAA, fRuns);
1060}
1061
1062void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1063 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1064 fBlitter->blitV(x, y, height, alpha);
1065 return;
1066 }
1067
1068 int stopY = y + height;
1069 do {
1070 int lastY;
1071 const uint8_t* row = fAAClip->findRow(y, &lastY);
1072 int initialCount;
1073 row = fAAClip->findX(row, x, &initialCount);
1074 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1075 if (newAlpha) {
1076 fBlitter->blitV(x, y, lastY - y + 1, newAlpha);
1077 }
1078 y = lastY + 1;
1079 } while (y < stopY);
1080}
1081
1082void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1083 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1084 fBlitter->blitRect(x, y, width, height);
1085 return;
1086 }
1087
1088 while (--height >= 0) {
1089 this->blitH(x, y, width);
1090 y += 1;
1091 }
1092}
1093
1094void SkAAClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
1095 fBlitter->blitMask(mask, clip);
1096}
1097
1098const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1099 return NULL;
1100}
1101
reed@google.com32287892011-10-05 16:27:44 +00001102///////////////////////////////////////////////////////////////////////////////
1103
reed@google.com1c04bf92011-10-10 12:57:12 +00001104bool SkAAClip::offset(int dx, int dy) {
1105 if (this->isEmpty()) {
1106 return false;
1107 }
1108
1109 fBounds.offset(dx, dy);
1110 return true;
1111}
1112
1113bool SkAAClip::offset(int dx, int dy, SkAAClip* dst) const {
1114 if (this == dst) {
1115 return dst->offset(dx, dy);
1116 }
1117
1118 dst->setEmpty();
1119 if (this->isEmpty()) {
1120 return false;
1121 }
1122
1123 sk_atomic_inc(&fRunHead->fRefCnt);
1124 dst->fRunHead = fRunHead;
1125 dst->fBounds = fBounds;
1126 dst->fBounds.offset(dx, dy);
1127 return true;
1128}
1129
reed@google.com32287892011-10-05 16:27:44 +00001130static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1131 const uint8_t* SK_RESTRICT row,
1132 int width) {
1133 while (width > 0) {
1134 int n = row[0];
1135 SkASSERT(width >= n);
1136 memset(mask, row[1], n);
1137 mask += n;
1138 row += 2;
1139 width -= n;
1140 }
1141}
1142
1143void SkAAClip::copyToMask(SkMask* mask) const {
1144 mask->fFormat = SkMask::kA8_Format;
1145 if (this->isEmpty()) {
1146 mask->fBounds.setEmpty();
1147 mask->fImage = NULL;
1148 mask->fRowBytes = 0;
1149 return;
1150 }
1151
1152 mask->fBounds = fBounds;
1153 mask->fRowBytes = fBounds.width();
1154 size_t size = mask->computeImageSize();
1155 mask->fImage = SkMask::AllocImage(size);
1156
1157 Iter iter(*this);
1158 uint8_t* dst = mask->fImage;
1159 const int width = fBounds.width();
1160
1161 int y = fBounds.fTop;
1162 while (!iter.done()) {
1163 do {
1164 expand_row_to_mask(dst, iter.data(), width);
1165 dst += mask->fRowBytes;
1166 } while (++y < iter.bottom());
1167 iter.next();
1168 }
1169}
1170