blob: c7cfca5c34d4627560ea725d3f77efd22c683546 [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
15static inline bool x_in_rect(int x, const SkIRect& rect) {
16 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
17}
18
19static inline bool y_in_rect(int y, const SkIRect& rect) {
20 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
21}
22
23/*
24 * Data runs are packed [count, alpha]
25 */
26
27struct SkAAClip::YOffset {
28 int32_t fY;
29 uint32_t fOffset;
30};
31
32struct SkAAClip::RunHead {
33 int32_t fRefCnt;
34 int32_t fRowCount;
35 int32_t fDataSize;
36
37 YOffset* yoffsets() {
38 return (YOffset*)((char*)this + sizeof(RunHead));
39 }
40 const YOffset* yoffsets() const {
41 return (const YOffset*)((const char*)this + sizeof(RunHead));
42 }
43 uint8_t* data() {
44 return (uint8_t*)(this->yoffsets() + fRowCount);
45 }
46 const uint8_t* data() const {
47 return (const uint8_t*)(this->yoffsets() + fRowCount);
48 }
49
50 static RunHead* Alloc(int rowCount, size_t dataSize) {
51 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize;
52 RunHead* head = (RunHead*)sk_malloc_throw(size);
53 head->fRefCnt = 1;
54 head->fRowCount = rowCount;
55 head->fDataSize = dataSize;
56 return head;
57 }
58};
59
60///////////////////////////////////////////////////////////////////////////////
61
62void SkAAClip::freeRuns() {
63 if (this->isComplex()) {
64 SkASSERT(fRunHead->fRefCnt >= 1);
65 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) {
66 sk_free(fRunHead);
67 }
68 }
69}
70
71SkAAClip::SkAAClip() {
72 fBounds.setEmpty();
73 fRunHead = SkAAClip_gEmptyPtr;
74}
75
76SkAAClip::SkAAClip(const SkAAClip& src) {
77 fRunHead = SkAAClip_gEmptyPtr;
78 *this = src;
79}
80
81SkAAClip::~SkAAClip() {
82 this->freeRuns();
83}
84
85SkAAClip& SkAAClip::operator=(const SkAAClip& src) {
86 if (this != &src) {
87 this->freeRuns();
88 fBounds = src.fBounds;
89 fRunHead = src.fRunHead;
90 if (this->isComplex()) {
91 sk_atomic_inc(&fRunHead->fRefCnt);
92 }
93 }
94 return *this;
95}
96
97bool operator==(const SkAAClip& a, const SkAAClip& b) {
98 if (&a == &b) {
99 return true;
100 }
101 if (a.fBounds != b.fBounds) {
102 return false;
103 }
104
105 const SkAAClip::RunHead* ah = a.fRunHead;
106 const SkAAClip::RunHead* bh = b.fRunHead;
107
108 // this catches empties and rects being equal
109 if (ah == bh) {
110 return true;
111 }
112
113 // now we insist that both are complex (but different ptrs)
114 if (!a.isComplex() || !b.isComplex()) {
115 return false;
116 }
117
118 return ah->fRowCount == bh->fRowCount &&
119 ah->fDataSize == bh->fDataSize &&
120 !memcmp(ah->data(), bh->data(), ah->fDataSize);
121}
122
123void SkAAClip::swap(SkAAClip& other) {
124 SkTSwap(fBounds, other.fBounds);
125 SkTSwap(fRunHead, other.fRunHead);
126}
127
128bool SkAAClip::setEmpty() {
129 this->freeRuns();
130 fBounds.setEmpty();
131 fRunHead = SkAAClip_gEmptyPtr;
132 return false;
133}
134
135bool SkAAClip::setRect(const SkIRect& bounds) {
136 if (bounds.isEmpty()) {
137 return this->setEmpty();
138 }
139 this->freeRuns();
140 fBounds = bounds;
141 fRunHead = SkAAClip_gRectPtr;
142 return true;
143}
144
145bool SkAAClip::setRect(const SkRect& r) {
146 if (r.isEmpty()) {
147 return this->setEmpty();
148 }
149
150 SkIRect ibounds;
151 r.roundOut(&ibounds);
152
153 SkRegion clip;
154 clip.setRect(ibounds);
155
156 SkPath path;
157 path.addRect(r);
158 return this->setPath(path, clip);
159}
160
161///////////////////////////////////////////////////////////////////////////////
162
163const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const {
164 SkASSERT(this->isComplex());
165
166 if (!y_in_rect(y, fBounds)) {
167 return NULL;
168 }
169 y -= fBounds.y(); // our yoffs values are relative to the top
170
171 const YOffset* yoff = fRunHead->yoffsets();
172 while (yoff->fY < y) {
173 yoff += 1;
174 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount);
175 }
176
177 if (lastYForRow) {
178 *lastYForRow = yoff->fY;
179 }
180 return fRunHead->data() + yoff->fOffset;
181}
182
183const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const {
184 SkASSERT(x_in_rect(x, fBounds));
185 x -= fBounds.x();
186
187 // first skip up to X
188 for (;;) {
189 int n = data[0];
190 if (x < n) {
191 *initialCount = n - x;
192 break;
193 }
194 data += 2;
195 x -= n;
196 }
197 return data;
198}
199
200bool SkAAClip::quickContains(int left, int top, int right, int bottom) const {
201 if (this->isEmpty()) {
202 return false;
203 }
204 if (!fBounds.contains(left, top, right, bottom)) {
205 return false;
206 }
207 if (this->isRect()) {
208 return true;
209 }
210
211 int lastY;
212 const uint8_t* row = this->findRow(top, &lastY);
213 if (lastY < bottom) {
214 return false;
215 }
216 // now just need to check in X
217 int initialCount;
218 row = this->findX(row, left, &initialCount);
219 return initialCount >= (right - left) && 0xFF == row[1];
220}
221
222///////////////////////////////////////////////////////////////////////////////
223
224class SkAAClip::Builder {
225 SkIRect fBounds;
226 struct Row {
227 int fY;
228 int fWidth;
229 SkTDArray<uint8_t>* fData;
230 };
231 SkTDArray<Row> fRows;
232 Row* fCurrRow;
233 int fPrevY;
234 int fWidth;
235
236public:
237 Builder(const SkIRect& bounds) : fBounds(bounds) {
238 fPrevY = -1;
239 fWidth = bounds.width();
240 fCurrRow = NULL;
241 }
242
243 ~Builder() {
244 Row* row = fRows.begin();
245 Row* stop = fRows.end();
246 while (row < stop) {
247 delete row->fData;
248 row += 1;
249 }
250 }
251
252 void addRun(int x, int y, U8CPU alpha, int count) {
253 SkASSERT(count > 0);
254 SkASSERT(fBounds.contains(x, y));
255 SkASSERT(fBounds.contains(x + count - 1, y));
256
257 x -= fBounds.left();
258 y -= fBounds.top();
259
260 Row* row = fCurrRow;
261 if (y != fPrevY) {
262 SkASSERT(y > fPrevY);
263 fPrevY = y;
264 row = this->flushRow(true);
265 row->fY = y;
266 row->fWidth = 0;
267 SkASSERT(row->fData);
268 SkASSERT(0 == row->fData->count());
269 fCurrRow = row;
270 }
271
272 SkASSERT(row->fWidth <= x);
273 SkASSERT(row->fWidth < fBounds.width());
274
275 SkTDArray<uint8_t>& data = *row->fData;
276
277 int gap = x - row->fWidth;
278 if (gap) {
279 AppendRun(data, 0, gap);
280 row->fWidth += gap;
281 SkASSERT(row->fWidth < fBounds.width());
282 }
283
284 AppendRun(data, alpha, count);
285 row->fWidth += count;
286 SkASSERT(row->fWidth <= fBounds.width());
287 }
288
289 RunHead* finish() {
290 this->flushRow(false);
291
292 const Row* row = fRows.begin();
293 const Row* stop = fRows.end();
294
295 size_t dataSize = 0;
296 while (row < stop) {
297 dataSize += row->fData->count();
298 row += 1;
299 }
300
301 RunHead* head = RunHead::Alloc(fRows.count(), dataSize);
302 YOffset* yoffset = head->yoffsets();
303 uint8_t* data = head->data();
304 uint8_t* baseData = data;
305
306 row = fRows.begin();
307 while (row < stop) {
308 yoffset->fY = row->fY;
309 yoffset->fOffset = data - baseData;
310 yoffset += 1;
311
312 size_t n = row->fData->count();
313 memcpy(data, row->fData->begin(), n);
314 data += n;
315
316 row += 1;
317 }
318
319 return head;
320 }
321
322 void dump() {
323 this->validate();
324 int y;
325 for (y = 0; y < fRows.count(); ++y) {
326 const Row& row = fRows[y];
327 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth);
328 const SkTDArray<uint8_t>& data = *row.fData;
329 int count = data.count();
330 SkASSERT(!(count & 1));
331 const uint8_t* ptr = data.begin();
332 for (int x = 0; x < count; x += 2) {
333 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]);
334 ptr += 2;
335 }
336 SkDebugf("\n");
337 }
338
339#if 0
340 int prevY = -1;
341 for (y = 0; y < fRows.count(); ++y) {
342 const Row& row = fRows[y];
343 const SkTDArray<uint8_t>& data = *row.fData;
344 int count = data.count();
345 for (int n = prevY; n < row.fY; ++n) {
346 const uint8_t* ptr = data.begin();
347 for (int x = 0; x < count; x += 2) {
348 for (int i = 0; i < ptr[0]; ++i) {
349 SkDebugf("%02X", ptr[1]);
350 }
351 ptr += 2;
352 }
353 SkDebugf("\n");
354 }
355 prevY = row.fY;
356 }
357#endif
358 }
359
360 void validate() {
361#ifdef SK_DEBUG
362 int prevY = -1;
363 for (int i = 0; i < fRows.count(); ++i) {
364 const Row& row = fRows[i];
365 SkASSERT(prevY < row.fY);
366 SkASSERT(fWidth == row.fWidth);
367 int count = row.fData->count();
368 const uint8_t* ptr = row.fData->begin();
369 SkASSERT(!(count & 1));
370 int w = 0;
371 for (int x = 0; x < count; x += 2) {
372 w += ptr[0];
373 SkASSERT(w <= fWidth);
374 ptr += 2;
375 }
376 SkASSERT(w == fWidth);
377 prevY = row.fY;
378 }
379#endif
380 }
381
382private:
383 Row* flushRow(bool readyForAnother) {
384 Row* next = NULL;
385 int count = fRows.count();
386 if (count > 0) {
387 // flush current row if needed
388 Row* curr = &fRows[count - 1];
389 if (curr->fWidth < fWidth) {
390 AppendRun(*curr->fData, 0, fWidth - curr->fWidth);
391 }
392 }
393 if (count > 1) {
394 // are our last two runs the same?
395 Row* prev = &fRows[count - 2];
396 Row* curr = &fRows[count - 1];
397 SkASSERT(prev->fWidth == fWidth);
398 SkASSERT(curr->fWidth == fWidth);
399 if (*prev->fData == *curr->fData) {
400 prev->fY = curr->fY;
401 if (readyForAnother) {
402 curr->fData->rewind();
403 next = curr;
404 } else {
405 delete curr->fData;
406 fRows.removeShuffle(count - 1);
407 }
408 } else {
409 if (readyForAnother) {
410 next = fRows.append();
411 next->fData = new SkTDArray<uint8_t>;
412 }
413 }
414 } else {
415 if (readyForAnother) {
416 next = fRows.append();
417 next->fData = new SkTDArray<uint8_t>;
418 }
419 }
420 return next;
421 }
422
423 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) {
424 do {
425 int n = count;
426 if (n > 255) {
427 n = 255;
428 }
429 uint8_t* ptr = data.append(2);
430 ptr[0] = n;
431 ptr[1] = alpha;
432 count -= n;
433 } while (count > 0);
434 }
435};
436
437class SkAAClip::BuilderBlitter : public SkBlitter {
438public:
439 BuilderBlitter(Builder* builder) {
440 fBuilder = builder;
441 }
442
443 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE
444 { unexpected(); }
445 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE
446 { unexpected(); }
447 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE
448 { unexpected(); }
449
450 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE {
451 return false;
452 }
453
454 virtual void blitH(int x, int y, int width) SK_OVERRIDE {
455 fBuilder->addRun(x, y, 0xFF, width);
456 }
457
458 virtual void blitAntiH(int x, int y, const SkAlpha alpha[],
459 const int16_t runs[]) SK_OVERRIDE {
460 for (;;) {
461 int count = *runs;
462 if (count <= 0) {
463 return;
464 }
465 fBuilder->addRun(x, y, *alpha, count);
466 runs += count;
467 alpha += count;
468 x += count;
469 }
470 }
471
472private:
473 Builder* fBuilder;
474
475 void unexpected() {
476 SkDebugf("---- did not expect to get called here");
477 sk_throw();
478 }
479};
480
481bool SkAAClip::setPath(const SkPath& path, const SkRegion& clip) {
482 if (clip.isEmpty()) {
483 return this->setEmpty();
484 }
485
486 SkIRect ibounds;
487
488 if (!path.isInverseFillType()) {
489 path.getBounds().roundOut(&ibounds);
490 if (ibounds.isEmpty() || !ibounds.intersect(clip.getBounds())) {
491 return this->setEmpty();
492 }
493 } else {
494 ibounds = clip.getBounds();
495 }
496
497 Builder builder(ibounds);
498 BuilderBlitter blitter(&builder);
499
500 SkScan::AntiFillPath(path, clip, &blitter, true);
501
502 this->freeRuns();
503 fBounds = ibounds;
504 fRunHead = builder.finish();
505
506 builder.dump();
507}
508
509///////////////////////////////////////////////////////////////////////////////
510
511bool SkAAClip::op(const SkAAClip&, const SkAAClip&, SkRegion::Op op) {
512 return true;
513}
514
515///////////////////////////////////////////////////////////////////////////////
516///////////////////////////////////////////////////////////////////////////////
517
518static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width,
519 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) {
520 // we don't read our initial n from data, since the caller may have had to
521 // clip it, hence the initialCount parameter.
522 int n = initialCount;
523 for (;;) {
524 if (n > width) {
525 n = width;
526 }
527 SkASSERT(n > 0);
528 runs[0] = n;
529 runs += n;
530
531 aa[0] = data[1];
532 aa += n;
533
534 data += 2;
535 width -= n;
536 if (0 == width) {
537 break;
538 }
539 // load the next count
540 n = data[0];
541 }
542 runs[0] = 0; // sentinel
543}
544
545SkAAClipBlitter::~SkAAClipBlitter() {
546 sk_free(fRuns);
547}
548
549void SkAAClipBlitter::ensureRunsAndAA() {
550 if (NULL == fRuns) {
551 // add 1 so we can store the terminating run count of 0
552 int count = fAAClipBounds.width() + 1;
553 fRuns = (int16_t*)sk_malloc_throw(count * sizeof(int16_t) +
554 count * sizeof(SkAlpha));
555 fAA = (SkAlpha*)(fRuns + count);
556 }
557}
558
559void SkAAClipBlitter::blitH(int x, int y, int width) {
560 SkASSERT(width > 0);
561 SkASSERT(fAAClipBounds.contains(x, y));
562 SkASSERT(fAAClipBounds.contains(x + width - 1, y));
563
564 int lastY;
565 const uint8_t* row = fAAClip->findRow(y, &lastY);
566 int initialCount;
567 row = fAAClip->findX(row, x, &initialCount);
568
569 if (initialCount >= width) {
570 SkAlpha alpha = row[1];
571 if (0 == alpha) {
572 return;
573 }
574 if (0xFF == alpha) {
575 fBlitter->blitH(x, y, width);
576 return;
577 }
578 }
579
580 this->ensureRunsAndAA();
581 expandToRuns(row, initialCount, width, fRuns, fAA);
582
583 fBlitter->blitAntiH(x, y, fAA, fRuns);
584}
585
586static void merge(const uint8_t* SK_RESTRICT row, int rowN,
587 const SkAlpha* SK_RESTRICT srcAA,
588 const int16_t* SK_RESTRICT srcRuns,
589 SkAlpha* SK_RESTRICT dstAA,
590 int16_t* SK_RESTRICT dstRuns,
591 int width) {
592 SkDEBUGCODE(int accumulated = 0;)
593 int srcN = srcRuns[0];
594 for (;;) {
595 if (0 == srcN) {
596 break;
597 }
598 SkASSERT(rowN > 0);
599 SkASSERT(srcN > 0);
600
601 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]);
602 int minN = SkMin32(srcN, rowN);
603 dstRuns[0] = minN;
604 dstRuns += minN;
605 dstAA[0] = newAlpha;
606 dstAA += minN;
607
608 if (0 == (srcN -= minN)) {
609 srcN = srcRuns[0]; // refresh
610 srcRuns += srcN;
611 srcAA += srcN;
612 srcN = srcRuns[0]; // reload
613 }
614 if (0 == (rowN -= minN)) {
615 row += 2;
616 rowN = row[0]; // reload
617 }
618
619 SkDEBUGCODE(accumulated += minN;)
620 SkASSERT(accumulated <= width);
621 }
622}
623
624void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
625 const int16_t runs[]) {
626 int lastY;
627 const uint8_t* row = fAAClip->findRow(y, &lastY);
628 int initialCount;
629 row = fAAClip->findX(row, x, &initialCount);
630
631 this->ensureRunsAndAA();
632
633 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width());
634 fBlitter->blitAntiH(x, y, fAA, fRuns);
635}
636
637void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
638 if (fAAClip->quickContains(x, y, x + 1, y + height)) {
639 fBlitter->blitV(x, y, height, alpha);
640 return;
641 }
642
643 int stopY = y + height;
644 do {
645 int lastY;
646 const uint8_t* row = fAAClip->findRow(y, &lastY);
647 int initialCount;
648 row = fAAClip->findX(row, x, &initialCount);
649 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]);
650 if (newAlpha) {
651 fBlitter->blitV(x, y, lastY - y + 1, newAlpha);
652 }
653 y = lastY + 1;
654 } while (y < stopY);
655}
656
657void SkAAClipBlitter::blitRect(int x, int y, int width, int height) {
658 if (fAAClip->quickContains(x, y, x + width, y + height)) {
659 fBlitter->blitRect(x, y, width, height);
660 return;
661 }
662
663 while (--height >= 0) {
664 this->blitH(x, y, width);
665 y += 1;
666 }
667}
668
669void SkAAClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
670 fBlitter->blitMask(mask, clip);
671}
672
673const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) {
674 return NULL;
675}
676