blob: 346b82a6bed944145485ddb47fa77125a18616f0 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkScanPriv.h"
11#include "SkPath.h"
12#include "SkMatrix.h"
13#include "SkBlitter.h"
14#include "SkRegion.h"
15#include "SkAntiRun.h"
16
17#define SHIFT 2
18#define SCALE (1 << SHIFT)
19#define MASK (SCALE - 1)
20
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000021/** @file
reed@google.com2f3567c2011-06-09 15:54:38 +000022 We have two techniques for capturing the output of the supersampler:
23 - SUPERMASK, which records a large mask-bitmap
24 this is often faster for small, complex objects
25 - RLE, which records a rle-encoded scanline
26 this is often faster for large objects with big spans
27
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000028 These blitters use two coordinate systems:
29 - destination coordinates, scale equal to the output - often
30 abbreviated with 'i' or 'I' in variable names
31 - supersampled coordinates, scale equal to the output * SCALE
32
reed@google.com2f3567c2011-06-09 15:54:38 +000033 NEW_AA is a set of code-changes to try to make both paths produce identical
34 results. Its not quite there yet, though the remaining differences may be
35 in the subsequent blits, and not in the different masks/runs...
36 */
reed@google.com9f2f0a82011-04-11 19:43:58 +000037//#define FORCE_SUPERMASK
38//#define FORCE_RLE
reed@google.com2f3567c2011-06-09 15:54:38 +000039//#define SK_SUPPORT_NEW_AA
reed@google.com9f2f0a82011-04-11 19:43:58 +000040
41///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000042
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000043/// Base class for a single-pass supersampled blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +000044class BaseSuperBlitter : public SkBlitter {
45public:
46 BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
47 const SkRegion& clip);
48
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000049 /// Must be explicitly defined on subclasses.
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
reed@google.com967a35d2011-10-31 19:37:58 +000051 const int16_t runs[]) SK_OVERRIDE {
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 SkASSERT(!"How did I get here?");
53 }
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000054 /// May not be called on BaseSuperBlitter because it blits out of order.
reed@google.com967a35d2011-10-31 19:37:58 +000055 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 SkASSERT(!"How did I get here?");
57 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000058
59protected:
60 SkBlitter* fRealBlitter;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000061 /// Current y coordinate, in destination coordinates.
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 int fCurrIY;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000063 /// Widest row of region to be blitted, in destination coordinates.
64 int fWidth;
65 /// Leftmost x coordinate in any row, in destination coordinates.
66 int fLeft;
67 /// Leftmost x coordinate in any row, in supersampled coordinates.
68 int fSuperLeft;
reed@android.com8a1c16f2008-12-17 15:59:43 +000069
70 SkDEBUGCODE(int fCurrX;)
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000071 /// Current y coordinate in supersampled coordinates.
reed@google.comfa57ae72011-05-31 19:18:02 +000072 int fCurrY;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000073 /// Initial y coordinate (top of bounds).
reed@google.com045e62d2011-10-24 12:19:46 +000074 int fTop;
reed@android.com8a1c16f2008-12-17 15:59:43 +000075};
76
77BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
78 const SkRegion& clip) {
79 fRealBlitter = realBlitter;
reed@google.com55b6b582011-03-02 15:58:18 +000080
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 // take the union of the ir bounds and clip, since we may be called with an
82 // inverse filltype
83 const int left = SkMin32(ir.fLeft, clip.getBounds().fLeft);
84 const int right = SkMax32(ir.fRight, clip.getBounds().fRight);
reed@google.com55b6b582011-03-02 15:58:18 +000085
reed@android.com8a1c16f2008-12-17 15:59:43 +000086 fLeft = left;
87 fSuperLeft = left << SHIFT;
88 fWidth = right - left;
reed@google.com045e62d2011-10-24 12:19:46 +000089#if 0
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 fCurrIY = -1;
reed@google.com34e52a02011-06-01 17:32:11 +000091 fCurrY = -1;
reed@google.com045e62d2011-10-24 12:19:46 +000092#else
93 fTop = ir.fTop;
94 fCurrIY = ir.fTop - 1;
95 fCurrY = (ir.fTop << SHIFT) - 1;
96#endif
reed@google.com34e52a02011-06-01 17:32:11 +000097 SkDEBUGCODE(fCurrX = -1;)
reed@android.com8a1c16f2008-12-17 15:59:43 +000098}
99
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000100/// Run-length-encoded supersampling antialiased blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101class SuperBlitter : public BaseSuperBlitter {
102public:
103 SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
104 const SkRegion& clip);
105
106 virtual ~SuperBlitter() {
107 this->flush();
108 sk_free(fRuns.fRuns);
109 }
110
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000111 /// Once fRuns contains a complete supersampled row, flush() blits
112 /// it out through the wrapped blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 void flush();
114
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000115 /// Blits a row of pixels, with location and width specified
116 /// in supersampled coordinates.
reed@google.com967a35d2011-10-31 19:37:58 +0000117 virtual void blitH(int x, int y, int width) SK_OVERRIDE;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000118 /// Blits a rectangle of pixels, with location and size specified
119 /// in supersampled coordinates.
reed@google.com967a35d2011-10-31 19:37:58 +0000120 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121
122private:
123 SkAlphaRuns fRuns;
reed@google.comfa57ae72011-05-31 19:18:02 +0000124 int fOffsetX;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125};
126
127SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
128 const SkRegion& clip)
129 : BaseSuperBlitter(realBlitter, ir, clip) {
130 const int width = fWidth;
131
132 // extra one to store the zero at the end
133 fRuns.fRuns = (int16_t*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(int16_t));
134 fRuns.fAlpha = (uint8_t*)(fRuns.fRuns + width + 1);
135 fRuns.reset(width);
reed@google.comfa57ae72011-05-31 19:18:02 +0000136
137 fOffsetX = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138}
139
reed@google.com9f2f0a82011-04-11 19:43:58 +0000140void SuperBlitter::flush() {
reed@google.com045e62d2011-10-24 12:19:46 +0000141 if (fCurrIY >= fTop) {
reed@google.com9f2f0a82011-04-11 19:43:58 +0000142 if (!fRuns.empty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 // SkDEBUGCODE(fRuns.dump();)
144 fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
145 fRuns.reset(fWidth);
reed@google.comfa57ae72011-05-31 19:18:02 +0000146 fOffsetX = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 }
reed@google.com045e62d2011-10-24 12:19:46 +0000148 fCurrIY = fTop - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 SkDEBUGCODE(fCurrX = -1;)
150 }
151}
152
reed@google.com9f2f0a82011-04-11 19:43:58 +0000153static inline int coverage_to_alpha(int aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 aa <<= 8 - 2*SHIFT;
155 aa -= aa >> (8 - SHIFT - 1);
156 return aa;
157}
158
tomhudson@google.com49eac192011-12-27 13:59:20 +0000159static inline int coverage_to_exact_alpha(int aa) {
160 static int map [] = { 0, 64, 128, 192, 255 };
161 SkASSERT(SHIFT == 2);
162 return map[aa];
163}
164
reed@google.com9f2f0a82011-04-11 19:43:58 +0000165void SuperBlitter::blitH(int x, int y, int width) {
reed@google.com967a35d2011-10-31 19:37:58 +0000166 SkASSERT(width > 0);
167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 int iy = y >> SHIFT;
169 SkASSERT(iy >= fCurrIY);
170
171 x -= fSuperLeft;
172 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000173 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174 width += x;
175 x = 0;
176 }
177
178#ifdef SK_DEBUG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 SkASSERT(y != fCurrY || x >= fCurrX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180#endif
reed@google.comfa57ae72011-05-31 19:18:02 +0000181 SkASSERT(y >= fCurrY);
182 if (fCurrY != y) {
183 fOffsetX = 0;
184 fCurrY = y;
185 }
186
reed@google.com9f2f0a82011-04-11 19:43:58 +0000187 if (iy != fCurrIY) { // new scanline
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 this->flush();
189 fCurrIY = iy;
190 }
191
reed@google.com5a1e7952011-05-31 14:36:21 +0000192 int start = x;
193 int stop = x + width;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194
reed@google.com5a1e7952011-05-31 14:36:21 +0000195 SkASSERT(start >= 0 && stop > start);
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000196 // integer-pixel-aligned ends of blit, rounded out
197 int fb = start & MASK;
198 int fe = stop & MASK;
reed@google.com5a1e7952011-05-31 14:36:21 +0000199 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200
reed@google.com5a1e7952011-05-31 14:36:21 +0000201 if (n < 0) {
202 fb = fe - fb;
203 n = 0;
204 fe = 0;
205 } else {
206 if (fb == 0) {
207 n += 1;
reed@google.com9f2f0a82011-04-11 19:43:58 +0000208 } else {
tomhudson@google.com49eac192011-12-27 13:59:20 +0000209 fb = SCALE - fb;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211 }
reed@google.comfa57ae72011-05-31 19:18:02 +0000212
tomhudson@google.com49eac192011-12-27 13:59:20 +0000213 // TODO - should this be using coverage_to_exact_alpha?
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000214 fOffsetX = fRuns.add(x >> SHIFT, coverage_to_alpha(fb),
215 n, coverage_to_alpha(fe),
reed@google.comfa57ae72011-05-31 19:18:02 +0000216 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
217 fOffsetX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218
219#ifdef SK_DEBUG
220 fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
221 fCurrX = x + width;
222#endif
223}
224
reed@google.coma89c77b2011-12-01 21:47:26 +0000225static void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
226 int n, U8CPU riteA) {
227 SkASSERT(leftA <= 0xFF);
228 SkASSERT(riteA <= 0xFF);
229
230 int16_t* run = runs.fRuns;
231 uint8_t* aa = runs.fAlpha;
232
233 if (ileft > 0) {
234 run[0] = ileft;
235 aa[0] = 0;
236 run += ileft;
237 aa += ileft;
238 }
239
240 SkASSERT(leftA < 0xFF);
241 if (leftA > 0) {
242 *run++ = 1;
243 *aa++ = leftA;
244 }
245
246 if (n > 0) {
247 run[0] = n;
248 aa[0] = 0xFF;
249 run += n;
250 aa += n;
251 }
252
253 SkASSERT(riteA < 0xFF);
254 if (riteA > 0) {
255 *run++ = 1;
256 *aa++ = riteA;
257 }
258 run[0] = 0;
259}
260
reed@google.com967a35d2011-10-31 19:37:58 +0000261void SuperBlitter::blitRect(int x, int y, int width, int height) {
262 SkASSERT(width > 0);
263 SkASSERT(height > 0);
264
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000265 // blit leading rows
266 while ((y & MASK)) {
reed@google.com967a35d2011-10-31 19:37:58 +0000267 this->blitH(x, y++, width);
268 if (--height <= 0) {
269 return;
270 }
271 }
272 SkASSERT(height > 0);
273
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000274 // Since this is a rect, instead of blitting supersampled rows one at a
275 // time and then resolving to the destination canvas, we can blit
276 // directly to the destintion canvas one row per SCALE supersampled rows.
reed@google.com967a35d2011-10-31 19:37:58 +0000277 int start_y = y >> SHIFT;
278 int stop_y = (y + height) >> SHIFT;
279 int count = stop_y - start_y;
280 if (count > 0) {
281 y += count << SHIFT;
282 height -= count << SHIFT;
283
284 // save original X for our tail blitH() loop at the bottom
285 int origX = x;
286
287 x -= fSuperLeft;
288 // hack, until I figure out why my cubics (I think) go beyond the bounds
289 if (x < 0) {
290 width += x;
291 x = 0;
292 }
293
tomhudson@google.com49eac192011-12-27 13:59:20 +0000294 // There is always a left column, a middle, and a right column.
295 // ileft is the destination x of the first pixel of the entire rect.
296 // xleft is (SCALE - # of covered supersampled pixels) in that
297 // destination pixel.
reed@google.com967a35d2011-10-31 19:37:58 +0000298 int ileft = x >> SHIFT;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000299 int xleft = x & MASK;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000300 // irite is the destination x of the last pixel of the OPAQUE section.
301 // xrite is the number of supersampled pixels extending beyond irite;
302 // xrite/SCALE should give us alpha.
reed@google.com967a35d2011-10-31 19:37:58 +0000303 int irite = (x + width) >> SHIFT;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000304 int xrite = (x + width) & MASK;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000305 if (!xrite) {
306 xrite = SCALE;
307 irite--;
308 }
309
reed@google.com967a35d2011-10-31 19:37:58 +0000310 int n = irite - ileft - 1;
311 if (n < 0) {
reed@google.com967a35d2011-10-31 19:37:58 +0000312 xleft = xrite - xleft;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000313 SkASSERT(xleft <= SCALE);
314 SkASSERT(xleft > 0);
reed@google.com967a35d2011-10-31 19:37:58 +0000315 xrite = 0;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000316 fRealBlitter->blitV(ileft + fLeft, start_y, count,
317 coverage_to_exact_alpha(xleft));
reed@google.com967a35d2011-10-31 19:37:58 +0000318 } else {
tomhudson@google.com49eac192011-12-27 13:59:20 +0000319 xleft = SCALE - xleft;
reed@google.com967a35d2011-10-31 19:37:58 +0000320 }
321
tomhudson@google.com49eac192011-12-27 13:59:20 +0000322
reed@google.com967a35d2011-10-31 19:37:58 +0000323 // here we go
324 SkASSERT(start_y > fCurrIY);
325 this->flush();
326
reed@google.comf2fc5a52011-11-01 11:42:42 +0000327 // to be compatible with the blitH() version, we just shift these
328 // values up. If we didn't care about that, we could be more precise
329 // and compute these exactly (e.g. 2->128 instead of 2->124)
330 //
tomhudson@google.com49eac192011-12-27 13:59:20 +0000331 const int coverageL = coverage_to_exact_alpha(xleft);
332 const int coverageR = coverage_to_exact_alpha(xrite);
reed@google.com967a35d2011-10-31 19:37:58 +0000333 SkASSERT(n + (coverageR != 0) <= fWidth);
334
tomhudson@google.com49eac192011-12-27 13:59:20 +0000335 SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
336 fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
337 coverageL, coverageR);
reed@google.com967a35d2011-10-31 19:37:58 +0000338
339 // preamble for our next call to blitH()
340 fCurrIY = stop_y - 1;
341 fOffsetX = 0;
342 fCurrY = y - 1;
343 fRuns.reset(fWidth);
344 x = origX;
345 }
346
tomhudson@google.com49eac192011-12-27 13:59:20 +0000347 // catch any remaining few rows
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000348 SkASSERT(height <= MASK);
reed@google.com967a35d2011-10-31 19:37:58 +0000349 while (--height >= 0) {
350 this->blitH(x, y++, width);
351 }
352}
353
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354///////////////////////////////////////////////////////////////////////////////
355
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000356/// Masked supersampling antialiased blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357class MaskSuperBlitter : public BaseSuperBlitter {
358public:
359 MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
360 const SkRegion& clip);
361 virtual ~MaskSuperBlitter() {
362 fRealBlitter->blitMask(fMask, fClipRect);
363 }
364
reed@google.com967a35d2011-10-31 19:37:58 +0000365 virtual void blitH(int x, int y, int width) SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000366
reed@google.com9f2f0a82011-04-11 19:43:58 +0000367 static bool CanHandleRect(const SkIRect& bounds) {
368#ifdef FORCE_RLE
369 return false;
370#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371 int width = bounds.width();
372 int rb = SkAlign4(width);
reed@google.com55b6b582011-03-02 15:58:18 +0000373
reed@android.com8a1c16f2008-12-17 15:59:43 +0000374 return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
375 (rb * bounds.height() <= MaskSuperBlitter::kMAX_STORAGE);
376 }
reed@google.com55b6b582011-03-02 15:58:18 +0000377
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378private:
379 enum {
reed@google.com9f2f0a82011-04-11 19:43:58 +0000380#ifdef FORCE_SUPERMASK
381 kMAX_WIDTH = 2048,
382 kMAX_STORAGE = 1024 * 1024 * 2
383#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
385 kMAX_STORAGE = 1024
reed@google.com9f2f0a82011-04-11 19:43:58 +0000386#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387 };
388
389 SkMask fMask;
390 SkIRect fClipRect;
391 // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
392 // perform a test to see if stopAlpha != 0
393 uint32_t fStorage[(kMAX_STORAGE >> 2) + 1];
394};
395
396MaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
397 const SkRegion& clip)
398 : BaseSuperBlitter(realBlitter, ir, clip) {
399 SkASSERT(CanHandleRect(ir));
400
401 fMask.fImage = (uint8_t*)fStorage;
402 fMask.fBounds = ir;
403 fMask.fRowBytes = ir.width();
404 fMask.fFormat = SkMask::kA8_Format;
reed@google.com55b6b582011-03-02 15:58:18 +0000405
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 fClipRect = ir;
407 fClipRect.intersect(clip.getBounds());
reed@google.com55b6b582011-03-02 15:58:18 +0000408
reed@android.com8a1c16f2008-12-17 15:59:43 +0000409 // For valgrind, write 1 extra byte at the end so we don't read
410 // uninitialized memory. See comment in add_aa_span and fStorage[].
411 memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
412}
413
reed@google.com9f2f0a82011-04-11 19:43:58 +0000414static void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415 /* I should be able to just add alpha[x] + startAlpha.
416 However, if the trailing edge of the previous span and the leading
417 edge of the current span round to the same super-sampled x value,
418 I might overflow to 256 with this add, hence the funny subtract.
419 */
420 unsigned tmp = *alpha + startAlpha;
421 SkASSERT(tmp <= 256);
422 *alpha = SkToU8(tmp - (tmp >> 8));
423}
424
reed@google.com9f2f0a82011-04-11 19:43:58 +0000425static inline uint32_t quadplicate_byte(U8CPU value) {
426 uint32_t pair = (value << 8) | value;
427 return (pair << 16) | pair;
428}
429
430// minimum count before we want to setup an inner loop, adding 4-at-a-time
431#define MIN_COUNT_FOR_QUAD_LOOP 16
432
433static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
434 U8CPU stopAlpha, U8CPU maxValue) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 SkASSERT(middleCount >= 0);
436
437 /* I should be able to just add alpha[x] + startAlpha.
438 However, if the trailing edge of the previous span and the leading
439 edge of the current span round to the same super-sampled x value,
440 I might overflow to 256 with this add, hence the funny subtract.
441 */
reed@google.com2f3567c2011-06-09 15:54:38 +0000442#ifdef SK_SUPPORT_NEW_AA
443 if (startAlpha) {
444 unsigned tmp = *alpha + startAlpha;
445 SkASSERT(tmp <= 256);
446 *alpha++ = SkToU8(tmp - (tmp >> 8));
447 }
448#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449 unsigned tmp = *alpha + startAlpha;
450 SkASSERT(tmp <= 256);
451 *alpha++ = SkToU8(tmp - (tmp >> 8));
reed@google.com2f3567c2011-06-09 15:54:38 +0000452#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453
reed@google.com9f2f0a82011-04-11 19:43:58 +0000454 if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
455 // loop until we're quad-byte aligned
456 while (SkTCast<intptr_t>(alpha) & 0x3) {
457 alpha[0] = SkToU8(alpha[0] + maxValue);
458 alpha += 1;
459 middleCount -= 1;
460 }
461
462 int bigCount = middleCount >> 2;
463 uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
464 uint32_t qval = quadplicate_byte(maxValue);
465 do {
466 *qptr++ += qval;
467 } while (--bigCount > 0);
468
469 middleCount &= 3;
470 alpha = reinterpret_cast<uint8_t*> (qptr);
471 // fall through to the following while-loop
472 }
473
474 while (--middleCount >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000475 alpha[0] = SkToU8(alpha[0] + maxValue);
476 alpha += 1;
477 }
478
479 // potentially this can be off the end of our "legal" alpha values, but that
480 // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
481 // every time (slow), we just do it, and ensure that we've allocated extra space
482 // (see the + 1 comment in fStorage[]
483 *alpha = SkToU8(*alpha + stopAlpha);
484}
485
reed@google.com9f2f0a82011-04-11 19:43:58 +0000486void MaskSuperBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000487 int iy = (y >> SHIFT);
reed@google.com55b6b582011-03-02 15:58:18 +0000488
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489 SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
490 iy -= fMask.fBounds.fTop; // make it relative to 0
491
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000492 // This should never happen, but it does. Until the true cause is
493 // discovered, let's skip this span instead of crashing.
494 // See http://crbug.com/17569.
495 if (iy < 0) {
496 return;
497 }
498
reed@android.com8a1c16f2008-12-17 15:59:43 +0000499#ifdef SK_DEBUG
500 {
501 int ix = x >> SHIFT;
502 SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
503 }
504#endif
reed@google.com55b6b582011-03-02 15:58:18 +0000505
reed@android.com8a1c16f2008-12-17 15:59:43 +0000506 x -= (fMask.fBounds.fLeft << SHIFT);
507
508 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000509 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000510 width += x;
511 x = 0;
512 }
513
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514 uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
515
516 int start = x;
517 int stop = x + width;
518
519 SkASSERT(start >= 0 && stop > start);
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000520 int fb = start & MASK;
521 int fe = stop & MASK;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000522 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
523
524
reed@google.com9f2f0a82011-04-11 19:43:58 +0000525 if (n < 0) {
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000526 SkASSERT(row >= fMask.fImage);
527 SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528 add_aa_span(row, coverage_to_alpha(fe - fb));
reed@google.com9f2f0a82011-04-11 19:43:58 +0000529 } else {
reed@google.com2f3567c2011-06-09 15:54:38 +0000530#ifdef SK_SUPPORT_NEW_AA
531 if (0 == fb) {
532 n += 1;
533 } else {
tomhudson@google.com49eac192011-12-27 13:59:20 +0000534 fb = SCALE - fb;
reed@google.com2f3567c2011-06-09 15:54:38 +0000535 }
536#else
tomhudson@google.com49eac192011-12-27 13:59:20 +0000537 fb = SCALE - fb;
reed@google.com2f3567c2011-06-09 15:54:38 +0000538#endif
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000539 SkASSERT(row >= fMask.fImage);
540 SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541 add_aa_span(row, coverage_to_alpha(fb), n, coverage_to_alpha(fe),
542 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
543 }
544
545#ifdef SK_DEBUG
546 fCurrX = x + width;
547#endif
548}
549
550///////////////////////////////////////////////////////////////////////////////
551
reed@android.com35555912009-03-16 18:46:55 +0000552/* Returns non-zero if (value << shift) overflows a short, which would mean
553 we could not shift it up and then convert to SkFixed.
554 i.e. is x expressible as signed (16-shift) bits?
555 */
556static int overflows_short_shift(int value, int shift) {
557 const int s = 16 + shift;
558 return (value << s >> s) - value;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559}
560
561void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
reed@google.com2c508f22011-10-03 21:15:46 +0000562 SkBlitter* blitter, bool forceRLE) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563 if (clip.isEmpty()) {
564 return;
565 }
566
reed@android.comd252db02009-04-01 18:31:44 +0000567 SkIRect ir;
568 path.getBounds().roundOut(&ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569 if (ir.isEmpty()) {
reed@google.comee068aa2011-12-21 19:36:21 +0000570 if (path.isInverseFillType()) {
571 blitter->blitRegion(clip);
572 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573 return;
574 }
575
reed@android.com35555912009-03-16 18:46:55 +0000576 // use bit-or since we expect all to pass, so no need to go slower with
577 // a short-circuiting logical-or
578 if (overflows_short_shift(ir.fLeft, SHIFT) |
579 overflows_short_shift(ir.fRight, SHIFT) |
580 overflows_short_shift(ir.fTop, SHIFT) |
581 overflows_short_shift(ir.fBottom, SHIFT)) {
582 // can't supersample, so draw w/o antialiasing
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583 SkScan::FillPath(path, clip, blitter);
584 return;
585 }
586
587 SkScanClipper clipper(blitter, &clip, ir);
588 const SkIRect* clipRect = clipper.getClipRect();
589
590 if (clipper.getBlitter() == NULL) { // clipped out
591 if (path.isInverseFillType()) {
592 blitter->blitRegion(clip);
593 }
594 return;
595 }
reed@google.com55b6b582011-03-02 15:58:18 +0000596
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597 // now use the (possibly wrapped) blitter
598 blitter = clipper.getBlitter();
599
600 if (path.isInverseFillType()) {
reed@google.com55b6b582011-03-02 15:58:18 +0000601 sk_blit_above(blitter, ir, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000602 }
603
604 SkIRect superRect, *superClipRect = NULL;
605
reed@google.com9f2f0a82011-04-11 19:43:58 +0000606 if (clipRect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607 superRect.set( clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
608 clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
609 superClipRect = &superRect;
610 }
611
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000612 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
613
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
615 // if we're an inverse filltype
reed@google.com2c508f22011-10-03 21:15:46 +0000616 if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000617 MaskSuperBlitter superBlit(blitter, ir, clip);
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000618 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
reed@android.comdca6a562010-02-22 16:05:48 +0000619 sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
reed@google.com9f2f0a82011-04-11 19:43:58 +0000620 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000621 SuperBlitter superBlit(blitter, ir, clip);
reed@android.comdca6a562010-02-22 16:05:48 +0000622 sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, clip);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623 }
reed@google.com55b6b582011-03-02 15:58:18 +0000624
625 if (path.isInverseFillType()) {
626 sk_blit_below(blitter, ir, clip);
627 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628}
reed@google.com1ba71372011-10-12 20:42:05 +0000629
630///////////////////////////////////////////////////////////////////////////////
631
632#include "SkRasterClip.h"
633
634void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip,
635 SkBlitter* blitter) {
636 if (clip.isEmpty()) {
637 return;
638 }
639
640 if (clip.isBW()) {
641 FillPath(path, clip.bwRgn(), blitter);
642 } else {
643 SkRegion tmp;
644 SkAAClipBlitter aaBlitter;
645
646 tmp.setRect(clip.getBounds());
647 aaBlitter.init(blitter, &clip.aaRgn());
648 SkScan::FillPath(path, tmp, &aaBlitter);
649 }
650}
651
652void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
653 SkBlitter* blitter) {
654 if (clip.isEmpty()) {
655 return;
656 }
657
658 if (clip.isBW()) {
659 AntiFillPath(path, clip.bwRgn(), blitter);
660 } else {
661 SkRegion tmp;
662 SkAAClipBlitter aaBlitter;
663
664 tmp.setRect(clip.getBounds());
665 aaBlitter.init(blitter, &clip.aaRgn());
666 SkScan::AntiFillPath(path, tmp, &aaBlitter, true);
667 }
668}
669