blob: 3e740313abe2339238b35b489e92187b5263a764 [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
213bool SkAAClip::setRect(const SkRect& r) {
214 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.com32287892011-10-05 16:27:44 +0000220 return this->setPath(path);
reed@google.come36707a2011-10-04 21:38:55 +0000221}
222
223///////////////////////////////////////////////////////////////////////////////
224
225const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
reed@google.com47ac84e2011-10-06 13:11:25 +0000226 SkASSERT(fRunHead);
reed@google.come36707a2011-10-04 21:38:55 +0000227
228 if (!y_in_rect(y, fBounds)) {
229 return NULL;
230 }
231 y -= fBounds.y(); // our yoffs values are relative to the top
232
233 const YOffset* yoff = fRunHead->yoffsets();
234 while (yoff->fY < y) {
235 yoff += 1;
236 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
237 }
238
239 if (lastYForRow) {
240 *lastYForRow = yoff->fY;
241 }
242 return fRunHead->data() + yoff->fOffset;
243}
244
245const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
246 SkASSERT(x_in_rect(x, fBounds));
247 x -= fBounds.x();
248
249 // first skip up to X
250 for (;;) {
251 int n = data[0];
252 if (x < n) {
253 *initialCount = n - x;
254 break;
255 }
256 data += 2;
257 x -= n;
258 }
259 return data;
260}
261
262bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
263 if (this->isEmpty()) {
264 return false;
265 }
266 if (!fBounds.contains(left, top, right, bottom)) {
267 return false;
268 }
reed@google.com32287892011-10-05 16:27:44 +0000269#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000270 if (this->isRect()) {
271 return true;
272 }
reed@google.com32287892011-10-05 16:27:44 +0000273#endif
reed@google.come36707a2011-10-04 21:38:55 +0000274
275 int lastY;
276 const uint8_t* row = this->findRow(top, &lastY);
277 if (lastY < bottom) {
278 return false;
279 }
280 // now just need to check in X
281 int initialCount;
282 row = this->findX(row, left, &initialCount);
283 return initialCount >= (right - left) && 0xFF == row[1];
284}
285
286///////////////////////////////////////////////////////////////////////////////
287
288class SkAAClip::Builder {
289 SkIRect fBounds;
290 struct Row {
291 int fY;
292 int fWidth;
293 SkTDArray<uint8_t>* fData;
294 };
295 SkTDArray<Row> fRows;
296 Row* fCurrRow;
297 int fPrevY;
298 int fWidth;
299
300public:
301 Builder(const SkIRect& bounds) : fBounds(bounds) {
302 fPrevY = -1;
303 fWidth = bounds.width();
304 fCurrRow = NULL;
305 }
306
307 ~Builder() {
308 Row* row = fRows.begin();
309 Row* stop = fRows.end();
310 while (row < stop) {
311 delete row->fData;
312 row += 1;
313 }
314 }
315
reed@google.com32287892011-10-05 16:27:44 +0000316 const SkIRect& getBounds() const { return fBounds; }
317
reed@google.come36707a2011-10-04 21:38:55 +0000318 void addRun(int x, int y, U8CPU alpha, int count) {
319 SkASSERT(count > 0);
320 SkASSERT(fBounds.contains(x, y));
321 SkASSERT(fBounds.contains(x + count - 1, y));
322
323 x -= fBounds.left();
324 y -= fBounds.top();
325
326 Row* row = fCurrRow;
327 if (y != fPrevY) {
328 SkASSERT(y > fPrevY);
329 fPrevY = y;
330 row = this->flushRow(true);
331 row->fY = y;
332 row->fWidth = 0;
333 SkASSERT(row->fData);
334 SkASSERT(0 == row->fData->count());
335 fCurrRow = row;
336 }
337
338 SkASSERT(row->fWidth <= x);
339 SkASSERT(row->fWidth < fBounds.width());
340
341 SkTDArray<uint8_t>& data = *row->fData;
342
343 int gap = x - row->fWidth;
344 if (gap) {
345 AppendRun(data, 0, gap);
346 row->fWidth += gap;
347 SkASSERT(row->fWidth < fBounds.width());
348 }
349
350 AppendRun(data, alpha, count);
351 row->fWidth += count;
352 SkASSERT(row->fWidth <= fBounds.width());
353 }
354
355 RunHead* finish() {
356 this->flushRow(false);
357
358 const Row* row = fRows.begin();
359 const Row* stop = fRows.end();
360
361 size_t dataSize = 0;
362 while (row < stop) {
363 dataSize += row->fData->count();
364 row += 1;
365 }
366
367 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
368 YOffset* yoffset = head->yoffsets();
369 uint8_t* data = head->data();
370 uint8_t* baseData = data;
371
372 row = fRows.begin();
373 while (row < stop) {
374 yoffset->fY = row->fY;
375 yoffset->fOffset = data - baseData;
376 yoffset += 1;
377
378 size_t n = row->fData->count();
379 memcpy(data, row->fData->begin(), n);
380 data += n;
381
382 row += 1;
383 }
384
385 return head;
386 }
387
388 void dump() {
389 this->validate();
390 int y;
391 for (y = 0; y < fRows.count(); ++y) {
392 const Row& row = fRows[y];
393 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
394 const SkTDArray<uint8_t>& data = *row.fData;
395 int count = data.count();
396 SkASSERT(!(count & 1));
397 const uint8_t* ptr = data.begin();
398 for (int x = 0; x < count; x += 2) {
399 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
400 ptr += 2;
401 }
402 SkDebugf("\n");
403 }
404
reed@google.com1c04bf92011-10-10 12:57:12 +0000405#if 0
reed@google.come36707a2011-10-04 21:38:55 +0000406 int prevY = -1;
407 for (y = 0; y < fRows.count(); ++y) {
408 const Row& row = fRows[y];
409 const SkTDArray<uint8_t>& data = *row.fData;
410 int count = data.count();
411 for (int n = prevY; n < row.fY; ++n) {
412 const uint8_t* ptr = data.begin();
413 for (int x = 0; x < count; x += 2) {
414 for (int i = 0; i < ptr[0]; ++i) {
415 SkDebugf("%02X", ptr[1]);
416 }
417 ptr += 2;
418 }
419 SkDebugf("\n");
420 }
421 prevY = row.fY;
422 }
423#endif
424 }
425
426 void validate() {
427#ifdef SK_DEBUG
428 int prevY = -1;
429 for (int i = 0; i < fRows.count(); ++i) {
430 const Row& row = fRows[i];
431 SkASSERT(prevY < row.fY);
432 SkASSERT(fWidth == row.fWidth);
433 int count = row.fData->count();
434 const uint8_t* ptr = row.fData->begin();
435 SkASSERT(!(count & 1));
436 int w = 0;
437 for (int x = 0; x < count; x += 2) {
438 w += ptr[0];
439 SkASSERT(w <= fWidth);
440 ptr += 2;
441 }
442 SkASSERT(w == fWidth);
443 prevY = row.fY;
444 }
445#endif
446 }
447
448private:
449 Row* flushRow(bool readyForAnother) {
450 Row* next = NULL;
451 int count = fRows.count();
452 if (count > 0) {
453 // flush current row if needed
454 Row* curr = &fRows[count - 1];
455 if (curr->fWidth < fWidth) {
456 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
457 }
458 }
459 if (count > 1) {
460 // are our last two runs the same?
461 Row* prev = &fRows[count - 2];
462 Row* curr = &fRows[count - 1];
463 SkASSERT(prev->fWidth == fWidth);
464 SkASSERT(curr->fWidth == fWidth);
465 if (*prev->fData == *curr->fData) {
466 prev->fY = curr->fY;
467 if (readyForAnother) {
468 curr->fData->rewind();
469 next = curr;
470 } else {
471 delete curr->fData;
472 fRows.removeShuffle(count - 1);
473 }
474 } else {
475 if (readyForAnother) {
476 next = fRows.append();
477 next->fData = new SkTDArray<uint8_t>;
478 }
479 }
480 } else {
481 if (readyForAnother) {
482 next = fRows.append();
483 next->fData = new SkTDArray<uint8_t>;
484 }
485 }
486 return next;
487 }
488
489 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
490 do {
491 int n = count;
492 if (n > 255) {
493 n = 255;
494 }
495 uint8_t* ptr = data.append(2);
496 ptr[0] = n;
497 ptr[1] = alpha;
498 count -= n;
499 } while (count > 0);
500 }
501};
502
503class SkAAClip::BuilderBlitter : public SkBlitter {
504public:
505 BuilderBlitter(Builder* builder) {
506 fBuilder = builder;
507 }
508
509 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
510 { unexpected(); }
511 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
512 { unexpected(); }
513 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
514 { unexpected(); }
515
516 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
517 return false;
518 }
519
520 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
521 fBuilder->addRun(x, y, 0xFF, width);
522 }
523
524 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
525 const int16_t runs[]) SK_OVERRIDE {
526 for (;;) {
527 int count = *runs;
528 if (count <= 0) {
529 return;
530 }
531 fBuilder->addRun(x, y, *alpha, count);
532 runs += count;
533 alpha += count;
534 x += count;
535 }
536 }
537
538private:
539 Builder* fBuilder;
540
541 void unexpected() {
542 SkDebugf("---- did not expect to get called here");
543 sk_throw();
544 }
545};
546
reed@google.com32287892011-10-05 16:27:44 +0000547bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip) {
548 if (clip && clip->isEmpty()) {
reed@google.come36707a2011-10-04 21:38:55 +0000549 return this->setEmpty();
550 }
551
552 SkIRect ibounds;
reed@google.com32287892011-10-05 16:27:44 +0000553 path.getBounds().roundOut(&ibounds);
reed@google.come36707a2011-10-04 21:38:55 +0000554
reed@google.com32287892011-10-05 16:27:44 +0000555 SkRegion tmpClip;
556 if (NULL == clip) {
557 tmpClip.setRect(ibounds);
558 clip = &tmpClip;
559 }
560
reed@google.come36707a2011-10-04 21:38:55 +0000561 if (!path.isInverseFillType()) {
reed@google.com32287892011-10-05 16:27:44 +0000562 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) {
reed@google.come36707a2011-10-04 21:38:55 +0000563 return this->setEmpty();
564 }
reed@google.come36707a2011-10-04 21:38:55 +0000565 }
566
567 Builder builder(ibounds);
568 BuilderBlitter blitter(&builder);
569
reed@google.com32287892011-10-05 16:27:44 +0000570 SkScan::AntiFillPath(path, *clip, &blitter, true);
reed@google.come36707a2011-10-04 21:38:55 +0000571
572 this->freeRuns();
573 fBounds = ibounds;
574 fRunHead = builder.finish();
575
576 builder.dump();
577}
578
579///////////////////////////////////////////////////////////////////////////////
580
reed@google.com32287892011-10-05 16:27:44 +0000581typedef void (*RowProc)(SkAAClip::Builder&, int bottom,
582 const uint8_t* rowA, const SkIRect& rectA,
583 const uint8_t* rowB, const SkIRect& rectB);
584
585static void sectRowProc(SkAAClip::Builder& builder, int bottom,
586 const uint8_t* rowA, const SkIRect& rectA,
587 const uint8_t* rowB, const SkIRect& rectB) {
588
589}
590
591typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB);
592
593static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) {
594 // Multiply
595 return SkMulDiv255Round(alphaA, alphaB);
596}
597
598static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) {
599 // SrcOver
600 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB);
601}
602
603static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) {
604 // SrcOut
605 return SkMulDiv255Round(alphaA, 0xFF - alphaB);
606}
607
608static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) {
609 // XOR
610 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB);
611}
612
613static AlphaProc find_alpha_proc(SkRegion::Op op) {
614 switch (op) {
615 case SkRegion::kIntersect_Op:
616 return sectAlphaProc;
617 case SkRegion::kDifference_Op:
618 return diffAlphaProc;
619 case SkRegion::kUnion_Op:
620 return unionAlphaProc;
621 case SkRegion::kXOR_Op:
622 return xorAlphaProc;
623 default:
624 SkASSERT(!"unexpected region op");
625 return sectAlphaProc;
626 }
627}
628
629static const uint8_t gEmptyRow[] = {
630 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
631 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
632 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
633 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
634 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
635 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
636 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
637 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0,
638};
639
640class RowIter {
641public:
642 RowIter(const uint8_t* row, const SkIRect& bounds) {
643 fRow = row;
644 fLeft = bounds.fLeft;
reed@google.com32287892011-10-05 16:27:44 +0000645 fBoundsRight = bounds.fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000646 if (row) {
647 fRight = bounds.fLeft + row[0];
648 SkASSERT(fRight <= fBoundsRight);
649 fAlpha = row[1];
650 fDone = false;
651 } else {
652 fDone = true;
653 fRight = kMaxInt32;
654 fAlpha = 0;
655 }
reed@google.com32287892011-10-05 16:27:44 +0000656 }
657
658 bool done() const { return fDone; }
reed@google.com1c04bf92011-10-10 12:57:12 +0000659 int left() const { return fLeft; }
660 int right() const { return fRight; }
661 U8CPU alpha() const { return fAlpha; }
reed@google.com32287892011-10-05 16:27:44 +0000662 void next() {
reed@google.com1c04bf92011-10-10 12:57:12 +0000663 if (!fDone) {
reed@google.com32287892011-10-05 16:27:44 +0000664 fLeft = fRight;
reed@google.com1c04bf92011-10-10 12:57:12 +0000665 if (fRight == fBoundsRight) {
666 fDone = true;
667 fRight = kMaxInt32;
668 fAlpha = 0;
669 } else {
670 fRow += 2;
671 fRight += fRow[0];
672 fAlpha = fRow[1];
673 SkASSERT(fRight <= fBoundsRight);
674 }
reed@google.com32287892011-10-05 16:27:44 +0000675 }
676 }
677
678private:
679 const uint8_t* fRow;
680 int fLeft;
681 int fRight;
682 int fBoundsRight;
683 bool fDone;
reed@google.com1c04bf92011-10-10 12:57:12 +0000684 uint8_t fAlpha;
reed@google.com32287892011-10-05 16:27:44 +0000685};
686
reed@google.com1c04bf92011-10-10 12:57:12 +0000687static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) {
688 if (rite == riteA) {
689 iter.next();
690 leftA = iter.left();
691 riteA = iter.right();
reed@google.com32287892011-10-05 16:27:44 +0000692 }
693}
694
reed@google.com1c04bf92011-10-10 12:57:12 +0000695static bool intersect(int& min, int& max, int boundsMin, int boundsMax) {
696 SkASSERT(min < max);
697 SkASSERT(boundsMin < boundsMax);
698 if (min >= boundsMax || max <= boundsMin) {
699 return false;
700 }
701 if (min < boundsMin) {
702 min = boundsMin;
703 }
704 if (max > boundsMax) {
705 max = boundsMax;
706 }
707 return true;
708}
709
reed@google.com32287892011-10-05 16:27:44 +0000710static void operatorX(SkAAClip::Builder& builder, int lastY,
711 RowIter& iterA, RowIter& iterB,
712 AlphaProc proc, const SkIRect& bounds) {
reed@google.com32287892011-10-05 16:27:44 +0000713 int leftA = iterA.left();
714 int riteA = iterA.right();
reed@google.com32287892011-10-05 16:27:44 +0000715 int leftB = iterB.left();
716 int riteB = iterB.right();
717
reed@google.com1c04bf92011-10-10 12:57:12 +0000718 int prevRite = bounds.fLeft;
719
720 do {
reed@google.com32287892011-10-05 16:27:44 +0000721 U8CPU alphaA = 0;
722 U8CPU alphaB = 0;
reed@google.com32287892011-10-05 16:27:44 +0000723 int left, rite;
reed@google.com1c04bf92011-10-10 12:57:12 +0000724
725 if (leftA < leftB) {
reed@google.com32287892011-10-05 16:27:44 +0000726 left = leftA;
reed@google.com32287892011-10-05 16:27:44 +0000727 alphaA = iterA.alpha();
reed@google.com1c04bf92011-10-10 12:57:12 +0000728 if (riteA <= leftB) {
729 rite = riteA;
730 } else {
731 rite = leftA = leftB;
reed@google.com32287892011-10-05 16:27:44 +0000732 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000733 } else if (leftB < leftA) {
734 left = leftB;
735 alphaB = iterB.alpha();
736 if (riteB <= leftA) {
737 rite = riteB;
738 } else {
739 rite = leftB = leftA;
740 }
741 } else {
742 left = leftA; // or leftB, since leftA == leftB
743 rite = leftA = leftB = SkMin32(riteA, riteB);
744 alphaA = iterA.alpha();
745 alphaB = iterB.alpha();
reed@google.com32287892011-10-05 16:27:44 +0000746 }
747
748 if (left >= bounds.fRight) {
749 break;
750 }
reed@google.com32287892011-10-05 16:27:44 +0000751 if (left >= bounds.fLeft) {
reed@google.com1c04bf92011-10-10 12:57:12 +0000752 SkASSERT(rite > left);
reed@google.com32287892011-10-05 16:27:44 +0000753 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left);
reed@google.com1c04bf92011-10-10 12:57:12 +0000754 prevRite = rite;
reed@google.com32287892011-10-05 16:27:44 +0000755 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000756
757 adjust_row(iterA, leftA, riteA, rite);
758 adjust_row(iterB, leftB, riteB, rite);
759 } while (!iterA.done() || !iterB.done());
760
761 if (prevRite < bounds.fRight) {
762 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite);
reed@google.com32287892011-10-05 16:27:44 +0000763 }
764}
765
reed@google.com1c04bf92011-10-10 12:57:12 +0000766static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) {
767 if (bot == botA) {
768 iter.next();
769 topA = botA;
770 SkASSERT(botA == iter.top());
771 botA = iter.bottom();
reed@google.com32287892011-10-05 16:27:44 +0000772 }
773}
774
775static void operateY(SkAAClip::Builder& builder, const SkAAClip& A,
776 const SkAAClip& B, SkRegion::Op op) {
777 AlphaProc proc = find_alpha_proc(op);
778 const SkIRect& bounds = builder.getBounds();
779
780 SkAAClip::Iter iterA(A);
781 SkAAClip::Iter iterB(B);
782
783 SkASSERT(!iterA.done());
784 int topA = iterA.top();
785 int botA = iterA.bottom();
786 SkASSERT(!iterB.done());
787 int topB = iterB.top();
788 int botB = iterB.bottom();
789
reed@google.com1c04bf92011-10-10 12:57:12 +0000790 do {
791 const uint8_t* rowA = NULL;
792 const uint8_t* rowB = NULL;
reed@google.com32287892011-10-05 16:27:44 +0000793 int top, bot;
reed@google.com1c04bf92011-10-10 12:57:12 +0000794
795 if (topA < topB) {
reed@google.com32287892011-10-05 16:27:44 +0000796 top = topA;
reed@google.com32287892011-10-05 16:27:44 +0000797 rowA = iterA.data();
reed@google.com1c04bf92011-10-10 12:57:12 +0000798 if (botA <= topB) {
799 bot = botA;
800 } else {
801 bot = topA = topB;
reed@google.com32287892011-10-05 16:27:44 +0000802 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000803
804 } else if (topB < topA) {
805 top = topB;
806 rowB = iterB.data();
807 if (botB <= topA) {
808 bot = botB;
809 } else {
810 bot = topB = topA;
811 }
812 } else {
813 top = topA; // or topB, since topA == topB
814 bot = topA = topB = SkMin32(botA, botB);
815 rowA = iterA.data();
816 rowB = iterB.data();
reed@google.com32287892011-10-05 16:27:44 +0000817 }
818
819 if (top >= bounds.fBottom) {
820 break;
821 }
reed@google.com1c04bf92011-10-10 12:57:12 +0000822 if (!rowA && !rowB) {
823 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width());
824 } else if (top >= bounds.fTop) {
825 SkASSERT(bot <= bounds.fBottom);
826 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds);
827 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds);
reed@google.com32287892011-10-05 16:27:44 +0000828 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds);
reed@google.com32287892011-10-05 16:27:44 +0000829 }
830
reed@google.com1c04bf92011-10-10 12:57:12 +0000831 adjust_iter(iterA, topA, botA, bot);
832 adjust_iter(iterB, topB, botB, bot);
833 } while (!iterA.done() || !iterB.done());
reed@google.com32287892011-10-05 16:27:44 +0000834}
835
836bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig,
837 SkRegion::Op op) {
838 if (SkRegion::kReplace_Op == op) {
839 return this->set(clipBOrig);
840 }
841
842 const SkAAClip* clipA = &clipAOrig;
843 const SkAAClip* clipB = &clipBOrig;
844
845 if (SkRegion::kReverseDifference_Op == op) {
846 SkTSwap(clipA, clipB);
847 op = SkRegion::kDifference_Op;
848 }
849
850 bool a_empty = clipA->isEmpty();
851 bool b_empty = clipB->isEmpty();
852
853 SkIRect bounds;
854 switch (op) {
855 case SkRegion::kDifference_Op:
856 if (a_empty) {
857 return this->setEmpty();
858 }
859 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) {
860 return this->set(*clipA);
861 }
862 bounds = clipA->fBounds;
863 break;
864
865 case SkRegion::kIntersect_Op:
866 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds,
867 clipB->fBounds)) {
868 return this->setEmpty();
869 }
870 break;
871
872 case SkRegion::kUnion_Op:
873 case SkRegion::kXOR_Op:
874 if (a_empty) {
875 return this->set(*clipB);
876 }
877 if (b_empty) {
878 return this->set(*clipA);
879 }
880 bounds = clipA->fBounds;
881 bounds.join(clipB->fBounds);
882 break;
883
884 default:
885 SkASSERT(!"unknown region op");
886 return !this->isEmpty();
887 }
888
reed@google.com32287892011-10-05 16:27:44 +0000889 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
890 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds));
891
892 Builder builder(bounds);
893 operateY(builder, *clipA, *clipB, op);
894 // don't free us until now, since we might be clipA or clipB
895 this->freeRuns();
896 fBounds = bounds;
897 fRunHead = builder.finish();
898
899 return !this->isEmpty();
reed@google.come36707a2011-10-04 21:38:55 +0000900}
901
reed@google.com47ac84e2011-10-06 13:11:25 +0000902bool SkAAClip::op(const SkIRect& r, SkRegion::Op op) {
903 SkAAClip clip;
904 clip.setRect(r);
905 return this->op(*this, clip, op);
906}
907
908bool SkAAClip::op(const SkRect& r, SkRegion::Op op) {
909 SkAAClip clip;
910 clip.setRect(r);
911 return this->op(*this, clip, op);
912}
913
914bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) {
915 return this->op(*this, clip, op);
916}
917
reed@google.come36707a2011-10-04 21:38:55 +0000918///////////////////////////////////////////////////////////////////////////////
919///////////////////////////////////////////////////////////////////////////////
920
921static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
922 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
923 // we don't read our initial n from data, since the caller may have had to
924 // clip it, hence the initialCount parameter.
925 int n = initialCount;
926 for (;;) {
927 if (n > width) {
928 n = width;
929 }
930 SkASSERT(n > 0);
931 runs[0] = n;
932 runs += n;
933
934 aa[0] = data[1];
935 aa += n;
936
937 data += 2;
938 width -= n;
939 if (0 == width) {
940 break;
941 }
942 // load the next count
943 n = data[0];
944 }
945 runs[0] = 0; // sentinel
946}
947
948SkAAClipBlitter::~SkAAClipBlitter() {
949 sk_free(fRuns);
950}
951
952void SkAAClipBlitter::ensureRunsAndAA() {
953 if (NULL == fRuns) {
954 // add 1 so we can store the terminating run count of 0
955 int count = fAAClipBounds.width() + 1;
956 fRuns = (int16_t*)sk_malloc_throw(count * sizeof(int16_t) +
957 count * sizeof(SkAlpha));
958 fAA = (SkAlpha*)(fRuns + count);
959 }
960}
961
962void SkAAClipBlitter::blitH(int x, int y, int width) {
963 SkASSERT(width > 0);
964 SkASSERT(fAAClipBounds.contains(x, y));
965 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
966
967 int lastY;
968 const uint8_t* row = fAAClip->findRow(y, &lastY);
969 int initialCount;
970 row = fAAClip->findX(row, x, &initialCount);
971
972 if (initialCount >= width) {
973 SkAlpha alpha = row[1];
974 if (0 == alpha) {
975 return;
976 }
977 if (0xFF == alpha) {
978 fBlitter->blitH(x, y, width);
979 return;
980 }
981 }
982
983 this->ensureRunsAndAA();
984 expandToRuns(row, initialCount, width, fRuns, fAA);
985
986 fBlitter->blitAntiH(x, y, fAA, fRuns);
987}
988
989static void merge(const uint8_t* SK_RESTRICT row, int rowN,
990 const SkAlpha* SK_RESTRICT srcAA,
991 const int16_t* SK_RESTRICT srcRuns,
992 SkAlpha* SK_RESTRICT dstAA,
993 int16_t* SK_RESTRICT dstRuns,
994 int width) {
995 SkDEBUGCODE(int accumulated = 0;)
996 int srcN = srcRuns[0];
997 for (;;) {
998 if (0 == srcN) {
999 break;
1000 }
1001 SkASSERT(rowN > 0);
1002 SkASSERT(srcN > 0);
1003
1004 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
1005 int minN = SkMin32(srcN, rowN);
1006 dstRuns[0] = minN;
1007 dstRuns += minN;
1008 dstAA[0] = newAlpha;
1009 dstAA += minN;
1010
1011 if (0 == (srcN -= minN)) {
1012 srcN = srcRuns[0]; // refresh
1013 srcRuns += srcN;
1014 srcAA += srcN;
1015 srcN = srcRuns[0]; // reload
1016 }
1017 if (0 == (rowN -= minN)) {
1018 row += 2;
1019 rowN = row[0]; // reload
1020 }
1021
1022 SkDEBUGCODE(accumulated += minN;)
1023 SkASSERT(accumulated <= width);
1024 }
1025}
1026
1027void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
1028 const int16_t runs[]) {
1029 int lastY;
1030 const uint8_t* row = fAAClip->findRow(y, &lastY);
1031 int initialCount;
1032 row = fAAClip->findX(row, x, &initialCount);
1033
1034 this->ensureRunsAndAA();
1035
1036 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
1037 fBlitter->blitAntiH(x, y, fAA, fRuns);
1038}
1039
1040void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
1041 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
1042 fBlitter->blitV(x, y, height, alpha);
1043 return;
1044 }
1045
1046 int stopY = y + height;
1047 do {
1048 int lastY;
1049 const uint8_t* row = fAAClip->findRow(y, &lastY);
1050 int initialCount;
1051 row = fAAClip->findX(row, x, &initialCount);
1052 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
1053 if (newAlpha) {
1054 fBlitter->blitV(x, y, lastY - y + 1, newAlpha);
1055 }
1056 y = lastY + 1;
1057 } while (y < stopY);
1058}
1059
1060void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
1061 if (fAAClip->quickContains(x, y, x + width, y + height)) {
1062 fBlitter->blitRect(x, y, width, height);
1063 return;
1064 }
1065
1066 while (--height >= 0) {
1067 this->blitH(x, y, width);
1068 y += 1;
1069 }
1070}
1071
1072void SkAAClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
1073 fBlitter->blitMask(mask, clip);
1074}
1075
1076const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
1077 return NULL;
1078}
1079
reed@google.com32287892011-10-05 16:27:44 +00001080///////////////////////////////////////////////////////////////////////////////
1081
reed@google.com1c04bf92011-10-10 12:57:12 +00001082bool SkAAClip::offset(int dx, int dy) {
1083 if (this->isEmpty()) {
1084 return false;
1085 }
1086
1087 fBounds.offset(dx, dy);
1088 return true;
1089}
1090
1091bool SkAAClip::offset(int dx, int dy, SkAAClip* dst) const {
1092 if (this == dst) {
1093 return dst->offset(dx, dy);
1094 }
1095
1096 dst->setEmpty();
1097 if (this->isEmpty()) {
1098 return false;
1099 }
1100
1101 sk_atomic_inc(&fRunHead->fRefCnt);
1102 dst->fRunHead = fRunHead;
1103 dst->fBounds = fBounds;
1104 dst->fBounds.offset(dx, dy);
1105 return true;
1106}
1107
reed@google.com32287892011-10-05 16:27:44 +00001108static void expand_row_to_mask(uint8_t* SK_RESTRICT mask,
1109 const uint8_t* SK_RESTRICT row,
1110 int width) {
1111 while (width > 0) {
1112 int n = row[0];
1113 SkASSERT(width >= n);
1114 memset(mask, row[1], n);
1115 mask += n;
1116 row += 2;
1117 width -= n;
1118 }
1119}
1120
1121void SkAAClip::copyToMask(SkMask* mask) const {
1122 mask->fFormat = SkMask::kA8_Format;
1123 if (this->isEmpty()) {
1124 mask->fBounds.setEmpty();
1125 mask->fImage = NULL;
1126 mask->fRowBytes = 0;
1127 return;
1128 }
1129
1130 mask->fBounds = fBounds;
1131 mask->fRowBytes = fBounds.width();
1132 size_t size = mask->computeImageSize();
1133 mask->fImage = SkMask::AllocImage(size);
1134
1135 Iter iter(*this);
1136 uint8_t* dst = mask->fImage;
1137 const int width = fBounds.width();
1138
1139 int y = fBounds.fTop;
1140 while (!iter.done()) {
1141 do {
1142 expand_row_to_mask(dst, iter.data(), width);
1143 dst += mask->fRowBytes;
1144 } while (++y < iter.bottom());
1145 iter.next();
1146 }
1147}
1148