blob: b7ce190e9a59982929e1a406fcd7fae1ae7f26f2 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/sgl/SkScan_AntiPath.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
reed@google.com55b6b582011-03-02 15:58:18 +00005** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
reed@android.com8a1c16f2008-12-17 15:59:43 +00008**
reed@google.com55b6b582011-03-02 15:58:18 +00009** http://www.apache.org/licenses/LICENSE-2.0
reed@android.com8a1c16f2008-12-17 15:59:43 +000010**
reed@google.com55b6b582011-03-02 15:58:18 +000011** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
reed@android.com8a1c16f2008-12-17 15:59:43 +000015** limitations under the License.
16*/
17
18#include "SkScanPriv.h"
19#include "SkPath.h"
20#include "SkMatrix.h"
21#include "SkBlitter.h"
22#include "SkRegion.h"
23#include "SkAntiRun.h"
24
25#define SHIFT 2
26#define SCALE (1 << SHIFT)
27#define MASK (SCALE - 1)
28
reed@google.com9f2f0a82011-04-11 19:43:58 +000029//#define FORCE_SUPERMASK
30//#define FORCE_RLE
31
32///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000033
34class BaseSuperBlitter : public SkBlitter {
35public:
36 BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
37 const SkRegion& clip);
38
39 virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
40 const int16_t runs[]) {
41 SkASSERT(!"How did I get here?");
42 }
43 virtual void blitV(int x, int y, int height, SkAlpha alpha) {
44 SkASSERT(!"How did I get here?");
45 }
46 virtual void blitRect(int x, int y, int width, int height) {
47 SkASSERT(!"How did I get here?");
48 }
49
50protected:
51 SkBlitter* fRealBlitter;
52 int fCurrIY;
53 int fWidth, fLeft, fSuperLeft;
54
55 SkDEBUGCODE(int fCurrX;)
56 SkDEBUGCODE(int fCurrY;)
57};
58
59BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
60 const SkRegion& clip) {
61 fRealBlitter = realBlitter;
reed@google.com55b6b582011-03-02 15:58:18 +000062
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 // take the union of the ir bounds and clip, since we may be called with an
64 // inverse filltype
65 const int left = SkMin32(ir.fLeft, clip.getBounds().fLeft);
66 const int right = SkMax32(ir.fRight, clip.getBounds().fRight);
reed@google.com55b6b582011-03-02 15:58:18 +000067
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 fLeft = left;
69 fSuperLeft = left << SHIFT;
70 fWidth = right - left;
71 fCurrIY = -1;
72 SkDEBUGCODE(fCurrX = -1; fCurrY = -1;)
73}
74
75class SuperBlitter : public BaseSuperBlitter {
76public:
77 SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
78 const SkRegion& clip);
79
80 virtual ~SuperBlitter() {
81 this->flush();
82 sk_free(fRuns.fRuns);
83 }
84
85 void flush();
86
87 virtual void blitH(int x, int y, int width);
agl@chromium.org8cfdf012010-12-06 18:52:40 +000088 virtual void blitRect(int x, int y, int width, int height);
reed@android.com8a1c16f2008-12-17 15:59:43 +000089
90private:
91 SkAlphaRuns fRuns;
92};
93
94SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
95 const SkRegion& clip)
96 : BaseSuperBlitter(realBlitter, ir, clip) {
97 const int width = fWidth;
98
99 // extra one to store the zero at the end
100 fRuns.fRuns = (int16_t*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(int16_t));
101 fRuns.fAlpha = (uint8_t*)(fRuns.fRuns + width + 1);
102 fRuns.reset(width);
103}
104
reed@google.com9f2f0a82011-04-11 19:43:58 +0000105void SuperBlitter::flush() {
106 if (fCurrIY >= 0) {
107 if (!fRuns.empty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 // SkDEBUGCODE(fRuns.dump();)
109 fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
110 fRuns.reset(fWidth);
111 }
112 fCurrIY = -1;
113 SkDEBUGCODE(fCurrX = -1;)
114 }
115}
116
reed@google.com9f2f0a82011-04-11 19:43:58 +0000117static inline int coverage_to_alpha(int aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 aa <<= 8 - 2*SHIFT;
119 aa -= aa >> (8 - SHIFT - 1);
120 return aa;
121}
122
123#define SUPER_Mask ((1 << SHIFT) - 1)
124
reed@google.com9f2f0a82011-04-11 19:43:58 +0000125void SuperBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 int iy = y >> SHIFT;
127 SkASSERT(iy >= fCurrIY);
128
129 x -= fSuperLeft;
130 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000131 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 width += x;
133 x = 0;
134 }
135
136#ifdef SK_DEBUG
137 SkASSERT(y >= fCurrY);
138 SkASSERT(y != fCurrY || x >= fCurrX);
139 fCurrY = y;
140#endif
141
reed@google.com9f2f0a82011-04-11 19:43:58 +0000142 if (iy != fCurrIY) { // new scanline
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 this->flush();
144 fCurrIY = iy;
145 }
146
147 // we sub 1 from maxValue 1 time for each block, so that we don't
148 // hit 256 as a summed max, but 255.
149// int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
150
reed@google.com5a1e7952011-05-31 14:36:21 +0000151 int start = x;
152 int stop = x + width;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153
reed@google.com5a1e7952011-05-31 14:36:21 +0000154 SkASSERT(start >= 0 && stop > start);
155 int fb = start & SUPER_Mask;
156 int fe = stop & SUPER_Mask;
157 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158
reed@google.com5a1e7952011-05-31 14:36:21 +0000159 if (n < 0) {
160 fb = fe - fb;
161 n = 0;
162 fe = 0;
163 } else {
164 if (fb == 0) {
165 n += 1;
reed@google.com9f2f0a82011-04-11 19:43:58 +0000166 } else {
reed@google.com5a1e7952011-05-31 14:36:21 +0000167 fb = (1 << SHIFT) - fb;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 }
reed@google.com5a1e7952011-05-31 14:36:21 +0000170 fRuns.add(x >> SHIFT, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
171 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172
173#ifdef SK_DEBUG
174 fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
175 fCurrX = x + width;
176#endif
177}
178
reed@google.com9f2f0a82011-04-11 19:43:58 +0000179void SuperBlitter::blitRect(int x, int y, int width, int height) {
agl@chromium.org8cfdf012010-12-06 18:52:40 +0000180 for (int i = 0; i < height; ++i) {
181 blitH(x, y + i, width);
182 }
183
184 flush();
185}
186
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187///////////////////////////////////////////////////////////////////////////////
188
189class MaskSuperBlitter : public BaseSuperBlitter {
190public:
191 MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
192 const SkRegion& clip);
193 virtual ~MaskSuperBlitter() {
194 fRealBlitter->blitMask(fMask, fClipRect);
195 }
196
197 virtual void blitH(int x, int y, int width);
198
reed@google.com9f2f0a82011-04-11 19:43:58 +0000199 static bool CanHandleRect(const SkIRect& bounds) {
200#ifdef FORCE_RLE
201 return false;
202#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 int width = bounds.width();
204 int rb = SkAlign4(width);
reed@google.com55b6b582011-03-02 15:58:18 +0000205
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206 return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
207 (rb * bounds.height() <= MaskSuperBlitter::kMAX_STORAGE);
208 }
reed@google.com55b6b582011-03-02 15:58:18 +0000209
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210private:
211 enum {
reed@google.com9f2f0a82011-04-11 19:43:58 +0000212#ifdef FORCE_SUPERMASK
213 kMAX_WIDTH = 2048,
214 kMAX_STORAGE = 1024 * 1024 * 2
215#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
217 kMAX_STORAGE = 1024
reed@google.com9f2f0a82011-04-11 19:43:58 +0000218#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 };
220
221 SkMask fMask;
222 SkIRect fClipRect;
223 // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
224 // perform a test to see if stopAlpha != 0
225 uint32_t fStorage[(kMAX_STORAGE >> 2) + 1];
226};
227
228MaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
229 const SkRegion& clip)
230 : BaseSuperBlitter(realBlitter, ir, clip) {
231 SkASSERT(CanHandleRect(ir));
232
233 fMask.fImage = (uint8_t*)fStorage;
234 fMask.fBounds = ir;
235 fMask.fRowBytes = ir.width();
236 fMask.fFormat = SkMask::kA8_Format;
reed@google.com55b6b582011-03-02 15:58:18 +0000237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 fClipRect = ir;
239 fClipRect.intersect(clip.getBounds());
reed@google.com55b6b582011-03-02 15:58:18 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241 // For valgrind, write 1 extra byte at the end so we don't read
242 // uninitialized memory. See comment in add_aa_span and fStorage[].
243 memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
244}
245
reed@google.com9f2f0a82011-04-11 19:43:58 +0000246static void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 /* I should be able to just add alpha[x] + startAlpha.
248 However, if the trailing edge of the previous span and the leading
249 edge of the current span round to the same super-sampled x value,
250 I might overflow to 256 with this add, hence the funny subtract.
251 */
252 unsigned tmp = *alpha + startAlpha;
253 SkASSERT(tmp <= 256);
254 *alpha = SkToU8(tmp - (tmp >> 8));
255}
256
reed@google.com9f2f0a82011-04-11 19:43:58 +0000257static inline uint32_t quadplicate_byte(U8CPU value) {
258 uint32_t pair = (value << 8) | value;
259 return (pair << 16) | pair;
260}
261
262// minimum count before we want to setup an inner loop, adding 4-at-a-time
263#define MIN_COUNT_FOR_QUAD_LOOP 16
264
265static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
266 U8CPU stopAlpha, U8CPU maxValue) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 SkASSERT(middleCount >= 0);
268
269 /* I should be able to just add alpha[x] + startAlpha.
270 However, if the trailing edge of the previous span and the leading
271 edge of the current span round to the same super-sampled x value,
272 I might overflow to 256 with this add, hence the funny subtract.
273 */
274 unsigned tmp = *alpha + startAlpha;
275 SkASSERT(tmp <= 256);
276 *alpha++ = SkToU8(tmp - (tmp >> 8));
277
reed@google.com9f2f0a82011-04-11 19:43:58 +0000278 if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
279 // loop until we're quad-byte aligned
280 while (SkTCast<intptr_t>(alpha) & 0x3) {
281 alpha[0] = SkToU8(alpha[0] + maxValue);
282 alpha += 1;
283 middleCount -= 1;
284 }
285
286 int bigCount = middleCount >> 2;
287 uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
288 uint32_t qval = quadplicate_byte(maxValue);
289 do {
290 *qptr++ += qval;
291 } while (--bigCount > 0);
292
293 middleCount &= 3;
294 alpha = reinterpret_cast<uint8_t*> (qptr);
295 // fall through to the following while-loop
296 }
297
298 while (--middleCount >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299 alpha[0] = SkToU8(alpha[0] + maxValue);
300 alpha += 1;
301 }
302
303 // potentially this can be off the end of our "legal" alpha values, but that
304 // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
305 // every time (slow), we just do it, and ensure that we've allocated extra space
306 // (see the + 1 comment in fStorage[]
307 *alpha = SkToU8(*alpha + stopAlpha);
308}
309
reed@google.com9f2f0a82011-04-11 19:43:58 +0000310void MaskSuperBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311 int iy = (y >> SHIFT);
reed@google.com55b6b582011-03-02 15:58:18 +0000312
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
314 iy -= fMask.fBounds.fTop; // make it relative to 0
315
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000316 // This should never happen, but it does. Until the true cause is
317 // discovered, let's skip this span instead of crashing.
318 // See http://crbug.com/17569.
319 if (iy < 0) {
320 return;
321 }
322
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323#ifdef SK_DEBUG
324 {
325 int ix = x >> SHIFT;
326 SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
327 }
328#endif
reed@google.com55b6b582011-03-02 15:58:18 +0000329
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 x -= (fMask.fBounds.fLeft << SHIFT);
331
332 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000333 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334 width += x;
335 x = 0;
336 }
337
338 // we sub 1 from maxValue 1 time for each block, so that we don't
339 // hit 256 as a summed max, but 255.
340// int maxValue = (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT);
341
342 uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
343
344 int start = x;
345 int stop = x + width;
346
347 SkASSERT(start >= 0 && stop > start);
348 int fb = start & SUPER_Mask;
349 int fe = stop & SUPER_Mask;
350 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
351
352
reed@google.com9f2f0a82011-04-11 19:43:58 +0000353 if (n < 0) {
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000354 SkASSERT(row >= fMask.fImage);
355 SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 add_aa_span(row, coverage_to_alpha(fe - fb));
reed@google.com9f2f0a82011-04-11 19:43:58 +0000357 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358 fb = (1 << SHIFT) - fb;
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000359 SkASSERT(row >= fMask.fImage);
360 SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 add_aa_span(row, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
362 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
363 }
364
365#ifdef SK_DEBUG
366 fCurrX = x + width;
367#endif
368}
369
370///////////////////////////////////////////////////////////////////////////////
371
reed@android.com35555912009-03-16 18:46:55 +0000372/* Returns non-zero if (value << shift) overflows a short, which would mean
373 we could not shift it up and then convert to SkFixed.
374 i.e. is x expressible as signed (16-shift) bits?
375 */
376static int overflows_short_shift(int value, int shift) {
377 const int s = 16 + shift;
378 return (value << s >> s) - value;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379}
380
381void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
382 SkBlitter* blitter) {
383 if (clip.isEmpty()) {
384 return;
385 }
386
reed@android.comd252db02009-04-01 18:31:44 +0000387 SkIRect ir;
388 path.getBounds().roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389 if (ir.isEmpty()) {
390 return;
391 }
392
reed@android.com35555912009-03-16 18:46:55 +0000393 // use bit-or since we expect all to pass, so no need to go slower with
394 // a short-circuiting logical-or
395 if (overflows_short_shift(ir.fLeft, SHIFT) |
396 overflows_short_shift(ir.fRight, SHIFT) |
397 overflows_short_shift(ir.fTop, SHIFT) |
398 overflows_short_shift(ir.fBottom, SHIFT)) {
399 // can't supersample, so draw w/o antialiasing
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 SkScan::FillPath(path, clip, blitter);
401 return;
402 }
403
404 SkScanClipper clipper(blitter, &clip, ir);
405 const SkIRect* clipRect = clipper.getClipRect();
406
407 if (clipper.getBlitter() == NULL) { // clipped out
408 if (path.isInverseFillType()) {
409 blitter->blitRegion(clip);
410 }
411 return;
412 }
reed@google.com55b6b582011-03-02 15:58:18 +0000413
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 // now use the (possibly wrapped) blitter
415 blitter = clipper.getBlitter();
416
417 if (path.isInverseFillType()) {
reed@google.com55b6b582011-03-02 15:58:18 +0000418 sk_blit_above(blitter, ir, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000419 }
420
421 SkIRect superRect, *superClipRect = NULL;
422
reed@google.com9f2f0a82011-04-11 19:43:58 +0000423 if (clipRect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424 superRect.set( clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
425 clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
426 superClipRect = &superRect;
427 }
428
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000429 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
430
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431 // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
432 // if we're an inverse filltype
reed@google.com9f2f0a82011-04-11 19:43:58 +0000433 if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000434 MaskSuperBlitter superBlit(blitter, ir, clip);
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000435 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
reed@android.comdca6a562010-02-22 16:05:48 +0000436 sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
reed@google.com9f2f0a82011-04-11 19:43:58 +0000437 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 SuperBlitter superBlit(blitter, ir, clip);
reed@android.comdca6a562010-02-22 16:05:48 +0000439 sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440 }
reed@google.com55b6b582011-03-02 15:58:18 +0000441
442 if (path.isInverseFillType()) {
443 sk_blit_below(blitter, ir, clip);
444 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000445}