blob: 3f38ddd4db2c67fb7e92479a1c4058a17e09292f [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;
reed@google.com17785642011-10-12 20:23:55 +0000524 fLeft = builder->getBounds().fLeft;
525 fRight = builder->getBounds().fRight;
reed@google.come36707a2011-10-04 21:38:55 +0000526 }
527
528 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
529 { unexpected(); }
530 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
531 { unexpected(); }
532 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
533 { unexpected(); }
534
535 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
reed@google.com3771a032011-10-11 17:18:04 +0000536 return NULL;
reed@google.come36707a2011-10-04 21:38:55 +0000537 }
538
539 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
540 fBuilder->addRun(x, y, 0xFF, width);
541 }
542
543 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
544 const int16_t runs[]) SK_OVERRIDE {
545 for (;;) {
546 int count = *runs;
547 if (count <= 0) {
548 return;
549 }
reed@google.com17785642011-10-12 20:23:55 +0000550
551 // The supersampler's buffer can be the width of the device, so
552 // we may have to trim the run to our bounds. If so, we assert that
553 // the extra spans are always alpha==0
554 int localX = x;
555 int localCount = count;
556 if (x < fLeft) {
557 SkASSERT(0 == *alpha);
558 int gap = fLeft - x;
559 SkASSERT(gap <= count);
560 localX += gap;
561 localCount -= gap;
562 }
563 int right = x + count;
564 if (right > fRight) {
565 SkASSERT(0 == *alpha);
566 localCount -= right - fRight;
567 SkASSERT(localCount >= 0);
568 }
569
570 if (localCount) {
571 fBuilder->addRun(localX, y, *alpha, localCount);
572 }
573 NEXT_RUN:
reed@google.come36707a2011-10-04 21:38:55 +0000574 runs += count;
575 alpha += count;
576 x += count;
577 }
578 }
579
580private:
581 Builder* fBuilder;
reed@google.com17785642011-10-12 20:23:55 +0000582 int fLeft; // cache of builder's bounds' left edge
583 int fRight;
reed@google.come36707a2011-10-04 21:38:55 +0000584
585 void unexpected() {
586 SkDebugf("---- did not expect to get called here");
587 sk_throw();
588 }
589};
590
reed@google.comf3c1da12011-10-10 19:35:47 +0000591bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) {
reed@google.com32287892011-10-05 16:27:44 +0000592 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000593 return this->setEmpty();
594 }
595
596 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +0000597 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +0000598
reed@google.com32287892011-10-05 16:27:44 +0000599 SkRegion tmpClip;
600 if (NULL == clip) {
601 tmpClip.setRect(ibounds);
602 clip = &tmpClip;
603 }
604
reed@google.come36707a2011-10-04 21:38:55 +0000605 if (!path.isInverseFillType()) {
reed@google.com32287892011-10-05 16:27:44 +0000606 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +0000607 return this->setEmpty();
608 }
reed@google.come36707a2011-10-04 21:38:55 +0000609 }
610
611 Builder builder(ibounds);
612 BuilderBlitter blitter(&builder);
613
reed@google.comf3c1da12011-10-10 19:35:47 +0000614 if (doAA) {
615 SkScan::AntiFillPath(path, *clip, &blitter, true);
616 } else {
617 SkScan::FillPath(path, *clip, &blitter);
618 }
reed@google.come36707a2011-10-04 21:38:55 +0000619
620 this->freeRuns();
621 fBounds = ibounds;
622 fRunHead = builder.finish();
623
reed@google.com3771a032011-10-11 17:18:04 +0000624 //builder.dump();
625 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000626}
627
628///////////////////////////////////////////////////////////////////////////////
629
reed@google.com32287892011-10-05 16:27:44 +0000630typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
631 const uint8_t* rowA, const SkIRect& rectA,
632 const uint8_t* rowB, const SkIRect& rectB);
633
634static void sectRowProc(SkAAClip::Builder& builder, int bottom,
635 const uint8_t* rowA, const SkIRect& rectA,
636 const uint8_t* rowB, const SkIRect& rectB) {
637
638}
639
640typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
641
642static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
643 // Multiply
644 return SkMulDiv255Round(alphaA, alphaB);
645}
646
647static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
648 // SrcOver
649 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
650}
651
652static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
653 // SrcOut
654 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
655}
656
657static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
658 // XOR
659 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
660}
661
662static AlphaProc find_alpha_proc(SkRegion::Op op) {
663 switch (op) {
664 case SkRegion::kIntersect_Op:
665 return sectAlphaProc;
666 case SkRegion::kDifference_Op:
667 return diffAlphaProc;
668 case SkRegion::kUnion_Op:
669 return unionAlphaProc;
670 case SkRegion::kXOR_Op:
671 return xorAlphaProc;
672 default:
673 SkASSERT(!"unexpected region op");
674 return sectAlphaProc;
675 }
676}
677
678static const uint8_t gEmptyRow[] = {
679 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
680 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
681 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
682 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
683 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
684 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
685 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
686 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
687};
688
689class RowIter {
690public:
691 RowIter(const uint8_t* row, const SkIRect& bounds) {
692 fRow = row;
693 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +0000694 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000695 if (row) {
696 fRight = bounds.fLeft + row[0];
697 SkASSERT(fRight <= fBoundsRight);
698 fAlpha = row[1];
699 fDone = false;
700 } else {
701 fDone = true;
702 fRight = kMaxInt32;
703 fAlpha = 0;
704 }
reed@google.com32287892011-10-05 16:27:44 +0000705 }
706
707 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000708 int left() const { return fLeft; }
709 int right() const { return fRight; }
710 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +0000711 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000712 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +0000713 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000714 if (fRight == fBoundsRight) {
715 fDone = true;
716 fRight = kMaxInt32;
717 fAlpha = 0;
718 } else {
719 fRow += 2;
720 fRight += fRow[0];
721 fAlpha = fRow[1];
722 SkASSERT(fRight <= fBoundsRight);
723 }
reed@google.com32287892011-10-05 16:27:44 +0000724 }
725 }
726
727private:
728 const uint8_t* fRow;
729 int fLeft;
730 int fRight;
731 int fBoundsRight;
732 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +0000733 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +0000734};
735
reed@google.com1c04bf92011-10-10 12:57:12 +0000736static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
737 if (rite == riteA) {
738 iter.next();
739 leftA = iter.left();
740 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +0000741 }
742}
743
reed@google.com1c04bf92011-10-10 12:57:12 +0000744static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
745 SkASSERT(min < max);
746 SkASSERT(boundsMin < boundsMax);
747 if (min >= boundsMax || max <= boundsMin) {
748 return false;
749 }
750 if (min < boundsMin) {
751 min = boundsMin;
752 }
753 if (max > boundsMax) {
754 max = boundsMax;
755 }
756 return true;
757}
758
reed@google.com32287892011-10-05 16:27:44 +0000759static void operatorX(SkAAClip::Builder& builder, int lastY,
760 RowIter& iterA, RowIter& iterB,
761 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +0000762 int leftA = iterA.left();
763 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +0000764 int leftB = iterB.left();
765 int riteB = iterB.right();
766
reed@google.com1c04bf92011-10-10 12:57:12 +0000767 int prevRite = bounds.fLeft;
768
769 do {
reed@google.com32287892011-10-05 16:27:44 +0000770 U8CPU alphaA = 0;
771 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +0000772 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +0000773
774 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +0000775 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +0000776 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +0000777 if (riteA <= leftB) {
778 rite = riteA;
779 } else {
780 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +0000781 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000782 } else if (leftB < leftA) {
783 left = leftB;
784 alphaB = iterB.alpha();
785 if (riteB <= leftA) {
786 rite = riteB;
787 } else {
788 rite = leftB = leftA;
789 }
790 } else {
791 left = leftA; // or leftB, since leftA == leftB
792 rite = leftA = leftB = SkMin32(riteA, riteB);
793 alphaA = iterA.alpha();
794 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +0000795 }
796
797 if (left >= bounds.fRight) {
798 break;
799 }
reed@google.com32287892011-10-05 16:27:44 +0000800 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +0000801 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +0000802 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +0000803 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +0000804 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000805
806 adjust_row(iterA, leftA, riteA, rite);
807 adjust_row(iterB, leftB, riteB, rite);
808 } while (!iterA.done() || !iterB.done());
809
810 if (prevRite < bounds.fRight) {
811 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +0000812 }
813}
814
reed@google.com1c04bf92011-10-10 12:57:12 +0000815static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
816 if (bot == botA) {
817 iter.next();
818 topA = botA;
819 SkASSERT(botA == iter.top());
820 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +0000821 }
822}
823
824static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
825 const SkAAClip& B, SkRegion::Op op) {
826 AlphaProc proc = find_alpha_proc(op);
827 const SkIRect& bounds = builder.getBounds();
828
829 SkAAClip::Iter iterA(A);
830 SkAAClip::Iter iterB(B);
831
832 SkASSERT(!iterA.done());
833 int topA = iterA.top();
834 int botA = iterA.bottom();
835 SkASSERT(!iterB.done());
836 int topB = iterB.top();
837 int botB = iterB.bottom();
838
reed@google.com1c04bf92011-10-10 12:57:12 +0000839 do {
840 const uint8_t* rowA = NULL;
841 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +0000842 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +0000843
844 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +0000845 top = topA;
reed@google.com32287892011-10-05 16:27:44 +0000846 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +0000847 if (botA <= topB) {
848 bot = botA;
849 } else {
850 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +0000851 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000852
853 } else if (topB < topA) {
854 top = topB;
855 rowB = iterB.data();
856 if (botB <= topA) {
857 bot = botB;
858 } else {
859 bot = topB = topA;
860 }
861 } else {
862 top = topA; // or topB, since topA == topB
863 bot = topA = topB = SkMin32(botA, botB);
864 rowA = iterA.data();
865 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +0000866 }
867
868 if (top >= bounds.fBottom) {
869 break;
870 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000871 if (!rowA && !rowB) {
872 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
873 } else if (top >= bounds.fTop) {
874 SkASSERT(bot <= bounds.fBottom);
875 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
876 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +0000877 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +0000878 }
879
reed@google.com1c04bf92011-10-10 12:57:12 +0000880 adjust_iter(iterA, topA, botA, bot);
881 adjust_iter(iterB, topB, botB, bot);
882 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +0000883}
884
885bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
886 SkRegion::Op op) {
887 if (SkRegion::kReplace_Op == op) {
888 return this->set(clipBOrig);
889 }
890
891 const SkAAClip* clipA = &clipAOrig;
892 const SkAAClip* clipB = &clipBOrig;
893
894 if (SkRegion::kReverseDifference_Op == op) {
895 SkTSwap(clipA, clipB);
896 op = SkRegion::kDifference_Op;
897 }
898
899 bool a_empty = clipA->isEmpty();
900 bool b_empty = clipB->isEmpty();
901
902 SkIRect bounds;
903 switch (op) {
904 case SkRegion::kDifference_Op:
905 if (a_empty) {
906 return this->setEmpty();
907 }
908 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
909 return this->set(*clipA);
910 }
911 bounds = clipA->fBounds;
912 break;
913
914 case SkRegion::kIntersect_Op:
915 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
916 clipB->fBounds)) {
917 return this->setEmpty();
918 }
919 break;
920
921 case SkRegion::kUnion_Op:
922 case SkRegion::kXOR_Op:
923 if (a_empty) {
924 return this->set(*clipB);
925 }
926 if (b_empty) {
927 return this->set(*clipA);
928 }
929 bounds = clipA->fBounds;
930 bounds.join(clipB->fBounds);
931 break;
932
933 default:
934 SkASSERT(!"unknown region op");
935 return !this->isEmpty();
936 }
937
reed@google.com32287892011-10-05 16:27:44 +0000938 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
939 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
940
941 Builder builder(bounds);
942 operateY(builder, *clipA, *clipB, op);
943 // don't free us until now, since we might be clipA or clipB
944 this->freeRuns();
945 fBounds = bounds;
946 fRunHead = builder.finish();
947
948 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000949}
950
reed@google.com47ac84e2011-10-06 13:11:25 +0000951bool SkAAClip::op(const SkIRect& r, SkRegion::Op op) {
952 SkAAClip clip;
953 clip.setRect(r);
954 return this->op(*this, clip, op);
955}
956
reed@google.com00177082011-10-12 14:34:30 +0000957bool SkAAClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
reed@google.com47ac84e2011-10-06 13:11:25 +0000958 SkAAClip clip;
reed@google.com00177082011-10-12 14:34:30 +0000959 clip.setRect(r, doAA);
reed@google.com47ac84e2011-10-06 13:11:25 +0000960 return this->op(*this, clip, op);
961}
962
963bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
964 return this->op(*this, clip, op);
965}
966
reed@google.come36707a2011-10-04 21:38:55 +0000967///////////////////////////////////////////////////////////////////////////////
968///////////////////////////////////////////////////////////////////////////////
969
970static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
971 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
972 // we don't read our initial n from data, since the caller may have had to
973 // clip it, hence the initialCount parameter.
974 int n = initialCount;
975 for (;;) {
976 if (n > width) {
977 n = width;
978 }
979 SkASSERT(n > 0);
980 runs[0] = n;
981 runs += n;
982
983 aa[0] = data[1];
984 aa += n;
985
986 data += 2;
987 width -= n;
988 if (0 == width) {
989 break;
990 }
991 // load the next count
992 n = data[0];
993 }
994 runs[0] = 0; // sentinel
995}
996
997SkAAClipBlitter::~SkAAClipBlitter() {
998 sk_free(fRuns);
999}
1000
1001void SkAAClipBlitter::ensureRunsAndAA() {
1002 if (NULL == fRuns) {
1003 // add 1 so we can store the terminating run count of 0
1004 int count = fAAClipBounds.width() + 1;
1005 fRuns = (int16_t*)sk_malloc_throw(count * sizeof(int16_t) +
1006 count * sizeof(SkAlpha));
1007 fAA = (SkAlpha*)(fRuns + count);
1008 }
1009}
1010
1011void SkAAClipBlitter::blitH(int x, int y, int width) {
1012 SkASSERT(width > 0);
1013 SkASSERT(fAAClipBounds.contains(x, y));
1014 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
1015
1016 int lastY;
1017 const uint8_t* row = fAAClip->findRow(y, &lastY);
1018 int initialCount;
1019 row = fAAClip->findX(row, x, &initialCount);
1020
1021 if (initialCount >= width) {
1022 SkAlpha alpha = row[1];
1023 if (0 == alpha) {
1024 return;
1025 }
1026 if (0xFF == alpha) {
1027 fBlitter->blitH(x, y, width);
1028 return;
1029 }
1030 }
1031
1032 this->ensureRunsAndAA();
1033 expandToRuns(row, initialCount, width, fRuns, fAA);
1034
1035 fBlitter->blitAntiH(x, y, fAA, fRuns);
1036}
1037
1038static void merge(const uint8_t* SK_RESTRICT row, int rowN,
1039 const SkAlpha* SK_RESTRICT srcAA,
1040 const int16_t* SK_RESTRICT srcRuns,
1041 SkAlpha* SK_RESTRICT dstAA,
1042 int16_t* SK_RESTRICT dstRuns,
1043 int width) {
1044 SkDEBUGCODE(int accumulated = 0;)
1045 int srcN = srcRuns[0];
1046 for (;;) {
1047 if (0 == srcN) {
1048 break;
1049 }
1050 SkASSERT(rowN > 0);
1051 SkASSERT(srcN > 0);
1052
1053 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1054 int minN = SkMin32(srcN, rowN);
1055 dstRuns[0] = minN;
1056 dstRuns += minN;
1057 dstAA[0] = newAlpha;
1058 dstAA += minN;
1059
1060 if (0 == (srcN -= minN)) {
1061 srcN = srcRuns[0]; // refresh
1062 srcRuns += srcN;
1063 srcAA += srcN;
1064 srcN = srcRuns[0]; // reload
1065 }
1066 if (0 == (rowN -= minN)) {
1067 row += 2;
1068 rowN = row[0]; // reload
1069 }
1070
1071 SkDEBUGCODE(accumulated += minN;)
1072 SkASSERT(accumulated <= width);
1073 }
1074}
1075
1076void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1077 const int16_t runs[]) {
1078 int lastY;
1079 const uint8_t* row = fAAClip->findRow(y, &lastY);
1080 int initialCount;
1081 row = fAAClip->findX(row, x, &initialCount);
1082
1083 this->ensureRunsAndAA();
1084
1085 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1086 fBlitter->blitAntiH(x, y, fAA, fRuns);
1087}
1088
1089void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1090 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1091 fBlitter->blitV(x, y, height, alpha);
1092 return;
1093 }
1094
1095 int stopY = y + height;
1096 do {
1097 int lastY;
1098 const uint8_t* row = fAAClip->findRow(y, &lastY);
1099 int initialCount;
1100 row = fAAClip->findX(row, x, &initialCount);
1101 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1102 if (newAlpha) {
1103 fBlitter->blitV(x, y, lastY - y + 1, newAlpha);
1104 }
1105 y = lastY + 1;
1106 } while (y < stopY);
1107}
1108
1109void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1110 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1111 fBlitter->blitRect(x, y, width, height);
1112 return;
1113 }
1114
1115 while (--height >= 0) {
1116 this->blitH(x, y, width);
1117 y += 1;
1118 }
1119}
1120
1121void SkAAClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
1122 fBlitter->blitMask(mask, clip);
1123}
1124
1125const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1126 return NULL;
1127}
1128
reed@google.com32287892011-10-05 16:27:44 +00001129///////////////////////////////////////////////////////////////////////////////
1130
reed@google.com1c04bf92011-10-10 12:57:12 +00001131bool SkAAClip::offset(int dx, int dy) {
1132 if (this->isEmpty()) {
1133 return false;
1134 }
1135
1136 fBounds.offset(dx, dy);
1137 return true;
1138}
1139
1140bool SkAAClip::offset(int dx, int dy, SkAAClip* dst) const {
1141 if (this == dst) {
1142 return dst->offset(dx, dy);
1143 }
1144
1145 dst->setEmpty();
1146 if (this->isEmpty()) {
1147 return false;
1148 }
1149
1150 sk_atomic_inc(&fRunHead->fRefCnt);
1151 dst->fRunHead = fRunHead;
1152 dst->fBounds = fBounds;
1153 dst->fBounds.offset(dx, dy);
1154 return true;
1155}
1156
reed@google.com32287892011-10-05 16:27:44 +00001157static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1158 const uint8_t* SK_RESTRICT row,
1159 int width) {
1160 while (width > 0) {
1161 int n = row[0];
1162 SkASSERT(width >= n);
1163 memset(mask, row[1], n);
1164 mask += n;
1165 row += 2;
1166 width -= n;
1167 }
1168}
1169
1170void SkAAClip::copyToMask(SkMask* mask) const {
1171 mask->fFormat = SkMask::kA8_Format;
1172 if (this->isEmpty()) {
1173 mask->fBounds.setEmpty();
1174 mask->fImage = NULL;
1175 mask->fRowBytes = 0;
1176 return;
1177 }
1178
1179 mask->fBounds = fBounds;
1180 mask->fRowBytes = fBounds.width();
1181 size_t size = mask->computeImageSize();
1182 mask->fImage = SkMask::AllocImage(size);
1183
1184 Iter iter(*this);
1185 uint8_t* dst = mask->fImage;
1186 const int width = fBounds.width();
1187
1188 int y = fBounds.fTop;
1189 while (!iter.done()) {
1190 do {
1191 expand_row_to_mask(dst, iter.data(), width);
1192 dst += mask->fRowBytes;
1193 } while (++y < iter.bottom());
1194 iter.next();
1195 }
1196}
1197