blob: 19989ff6d2ab468f2dcdcfc94fbc840397053617 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
reed@android.com8a1c16f2008-12-17 15:59:43 +00008
9#include "SkScanPriv.h"
10#include "SkPath.h"
11#include "SkMatrix.h"
12#include "SkBlitter.h"
13#include "SkRegion.h"
14#include "SkAntiRun.h"
15
16#define SHIFT 2
17#define SCALE (1 << SHIFT)
18#define MASK (SCALE - 1)
19
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000020/** @file
reed@google.com2f3567c2011-06-09 15:54:38 +000021 We have two techniques for capturing the output of the supersampler:
22 - SUPERMASK, which records a large mask-bitmap
23 this is often faster for small, complex objects
24 - RLE, which records a rle-encoded scanline
25 this is often faster for large objects with big spans
26
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000027 These blitters use two coordinate systems:
28 - destination coordinates, scale equal to the output - often
29 abbreviated with 'i' or 'I' in variable names
30 - supersampled coordinates, scale equal to the output * SCALE
reed@google.com2f3567c2011-06-09 15:54:38 +000031 */
reed@google.com5b7d6032012-05-09 14:07:34 +000032
reed@google.com9f2f0a82011-04-11 19:43:58 +000033//#define FORCE_SUPERMASK
34//#define FORCE_RLE
35
36///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000037
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000038/// Base class for a single-pass supersampled blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +000039class BaseSuperBlitter : public SkBlitter {
40public:
41 BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
reedbcba2c92014-10-15 08:52:00 -070042 const SkRegion& clip, bool isInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000044 /// Must be explicitly defined on subclasses.
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
mtklein36352bf2015-03-25 18:17:31 -070046 const int16_t runs[]) override {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000047 SkDEBUGFAIL("How did I get here?");
reed@android.com8a1c16f2008-12-17 15:59:43 +000048 }
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000049 /// May not be called on BaseSuperBlitter because it blits out of order.
mtklein36352bf2015-03-25 18:17:31 -070050 void blitV(int x, int y, int height, SkAlpha alpha) override {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000051 SkDEBUGFAIL("How did I get here?");
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000053
54protected:
55 SkBlitter* fRealBlitter;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000056 /// Current y coordinate, in destination coordinates.
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 int fCurrIY;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000058 /// Widest row of region to be blitted, in destination coordinates.
59 int fWidth;
60 /// Leftmost x coordinate in any row, in destination coordinates.
61 int fLeft;
62 /// Leftmost x coordinate in any row, in supersampled coordinates.
63 int fSuperLeft;
reed@android.com8a1c16f2008-12-17 15:59:43 +000064
65 SkDEBUGCODE(int fCurrX;)
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000066 /// Current y coordinate in supersampled coordinates.
reed@google.comfa57ae72011-05-31 19:18:02 +000067 int fCurrY;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +000068 /// Initial y coordinate (top of bounds).
reed@google.com045e62d2011-10-24 12:19:46 +000069 int fTop;
reedbcba2c92014-10-15 08:52:00 -070070
71 SkIRect fSectBounds;
reed@android.com8a1c16f2008-12-17 15:59:43 +000072};
73
reedbcba2c92014-10-15 08:52:00 -070074BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlit, const SkIRect& ir, const SkRegion& clip,
75 bool isInverse) {
76 fRealBlitter = realBlit;
77
78 SkIRect sectBounds;
79 if (isInverse) {
reedc553b7a2014-10-15 09:00:27 -070080 // We use the clip bounds instead of the ir, since we may be asked to
81 //draw outside of the rect when we're a inverse filltype
reedbcba2c92014-10-15 08:52:00 -070082 sectBounds = clip.getBounds();
83 } else {
84 if (!sectBounds.intersect(ir, clip.getBounds())) {
85 sectBounds.setEmpty();
86 }
87 }
reed@google.com55b6b582011-03-02 15:58:18 +000088
reedbcba2c92014-10-15 08:52:00 -070089 const int left = sectBounds.left();
90 const int right = sectBounds.right();
rmistry@google.comfbfcd562012-08-23 18:09:54 +000091
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 fLeft = left;
mtkleincefb4592015-12-09 13:32:58 -080093 fSuperLeft = SkLeftShift(left, SHIFT);
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 fWidth = right - left;
reedbcba2c92014-10-15 08:52:00 -070095 fTop = sectBounds.top();
96 fCurrIY = fTop - 1;
mtkleincefb4592015-12-09 13:32:58 -080097 fCurrY = SkLeftShift(fTop, SHIFT) - 1;
reedbcba2c92014-10-15 08:52:00 -070098
reed@google.com34e52a02011-06-01 17:32:11 +000099 SkDEBUGCODE(fCurrX = -1;)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100}
101
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000102/// Run-length-encoded supersampling antialiased blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103class SuperBlitter : public BaseSuperBlitter {
104public:
reedbcba2c92014-10-15 08:52:00 -0700105 SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106
107 virtual ~SuperBlitter() {
108 this->flush();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 }
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.
mtklein36352bf2015-03-25 18:17:31 -0700117 void blitH(int x, int y, int width) override;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000118 /// Blits a rectangle of pixels, with location and size specified
119 /// in supersampled coordinates.
mtklein36352bf2015-03-25 18:17:31 -0700120 void blitRect(int x, int y, int width, int height) override;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121
122private:
krajcevski2ec93fc2014-07-16 13:31:41 -0700123 // The next three variables are used to track a circular buffer that
124 // contains the values used in SkAlphaRuns. These variables should only
125 // ever be updated in advanceRuns(), and fRuns should always point to
126 // a valid SkAlphaRuns...
127 int fRunsToBuffer;
128 void* fRunsBuffer;
129 int fCurrentRun;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 SkAlphaRuns fRuns;
krajcevski2ec93fc2014-07-16 13:31:41 -0700131
132 // extra one to store the zero at the end
133 int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); }
134
135 // This function updates the fRuns variable to point to the next buffer space
136 // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
137 // and resets fRuns to point to an empty scanline.
138 void advanceRuns() {
139 const size_t kRunsSz = this->getRunsSz();
140 fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
141 fRuns.fRuns = reinterpret_cast<int16_t*>(
142 reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz);
143 fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
144 fRuns.reset(fWidth);
145 }
146
reed@google.comfa57ae72011-05-31 19:18:02 +0000147 int fOffsetX;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148};
149
reedbcba2c92014-10-15 08:52:00 -0700150SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip,
151 bool isInverse)
152 : BaseSuperBlitter(realBlitter, ir, clip, isInverse)
153{
krajcevski2ec93fc2014-07-16 13:31:41 -0700154 fRunsToBuffer = realBlitter->requestRowsPreserved();
krajcevski75f88512014-07-21 09:54:23 -0700155 fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz());
krajcevski2ec93fc2014-07-16 13:31:41 -0700156 fCurrentRun = -1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157
krajcevski2ec93fc2014-07-16 13:31:41 -0700158 this->advanceRuns();
reed@google.comfa57ae72011-05-31 19:18:02 +0000159
160 fOffsetX = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161}
162
reed@google.com9f2f0a82011-04-11 19:43:58 +0000163void SuperBlitter::flush() {
reed@google.com045e62d2011-10-24 12:19:46 +0000164 if (fCurrIY >= fTop) {
krajcevski2ec93fc2014-07-16 13:31:41 -0700165
166 SkASSERT(fCurrentRun < fRunsToBuffer);
reed@google.com9f2f0a82011-04-11 19:43:58 +0000167 if (!fRuns.empty()) {
krajcevski2ec93fc2014-07-16 13:31:41 -0700168 // SkDEBUGCODE(fRuns.dump();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
krajcevski2ec93fc2014-07-16 13:31:41 -0700170 this->advanceRuns();
reed@google.comfa57ae72011-05-31 19:18:02 +0000171 fOffsetX = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000172 }
krajcevski2ec93fc2014-07-16 13:31:41 -0700173
reed@google.com045e62d2011-10-24 12:19:46 +0000174 fCurrIY = fTop - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 SkDEBUGCODE(fCurrX = -1;)
176 }
177}
178
tomhudson@google.comffc92482012-02-23 19:34:34 +0000179/** coverage_to_partial_alpha() is being used by SkAlphaRuns, which
180 *accumulates* SCALE pixels worth of "alpha" in [0,(256/SCALE)]
181 to produce a final value in [0, 255] and handles clamping 256->255
182 itself, with the same (alpha - (alpha >> 8)) correction as
183 coverage_to_exact_alpha().
184*/
185static inline int coverage_to_partial_alpha(int aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 aa <<= 8 - 2*SHIFT;
reed@google.com5b7d6032012-05-09 14:07:34 +0000187 return aa;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188}
189
tomhudson@google.comffc92482012-02-23 19:34:34 +0000190/** coverage_to_exact_alpha() is being used by our blitter, which wants
191 a final value in [0, 255].
192*/
tomhudson@google.com49eac192011-12-27 13:59:20 +0000193static inline int coverage_to_exact_alpha(int aa) {
tomhudson@google.com31bab392012-01-03 20:12:42 +0000194 int alpha = (256 >> SHIFT) * aa;
195 // clamp 256->255
196 return alpha - (alpha >> 8);
tomhudson@google.com49eac192011-12-27 13:59:20 +0000197}
198
reed@google.com9f2f0a82011-04-11 19:43:58 +0000199void SuperBlitter::blitH(int x, int y, int width) {
reed@google.com967a35d2011-10-31 19:37:58 +0000200 SkASSERT(width > 0);
201
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 int iy = y >> SHIFT;
203 SkASSERT(iy >= fCurrIY);
204
205 x -= fSuperLeft;
206 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000207 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 width += x;
209 x = 0;
210 }
211
212#ifdef SK_DEBUG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 SkASSERT(y != fCurrY || x >= fCurrX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214#endif
reed@google.comfa57ae72011-05-31 19:18:02 +0000215 SkASSERT(y >= fCurrY);
216 if (fCurrY != y) {
217 fOffsetX = 0;
218 fCurrY = y;
219 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000220
reed@google.com9f2f0a82011-04-11 19:43:58 +0000221 if (iy != fCurrIY) { // new scanline
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 this->flush();
223 fCurrIY = iy;
224 }
225
reed@google.com5a1e7952011-05-31 14:36:21 +0000226 int start = x;
227 int stop = x + width;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228
reed@google.com5a1e7952011-05-31 14:36:21 +0000229 SkASSERT(start >= 0 && stop > start);
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000230 // integer-pixel-aligned ends of blit, rounded out
231 int fb = start & MASK;
232 int fe = stop & MASK;
reed@google.com5a1e7952011-05-31 14:36:21 +0000233 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234
reed@google.com5a1e7952011-05-31 14:36:21 +0000235 if (n < 0) {
236 fb = fe - fb;
237 n = 0;
238 fe = 0;
239 } else {
240 if (fb == 0) {
241 n += 1;
reed@google.com9f2f0a82011-04-11 19:43:58 +0000242 } else {
tomhudson@google.com49eac192011-12-27 13:59:20 +0000243 fb = SCALE - fb;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 }
reed@google.comfa57ae72011-05-31 19:18:02 +0000246
tomhudson@google.comffc92482012-02-23 19:34:34 +0000247 fOffsetX = fRuns.add(x >> SHIFT, coverage_to_partial_alpha(fb),
248 n, coverage_to_partial_alpha(fe),
reed@google.comfa57ae72011-05-31 19:18:02 +0000249 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
250 fOffsetX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
252#ifdef SK_DEBUG
253 fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
254 fCurrX = x + width;
255#endif
256}
257
caryclark@google.com803eceb2012-06-06 12:09:34 +0000258#if 0 // UNUSED
reed@google.coma89c77b2011-12-01 21:47:26 +0000259static void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
260 int n, U8CPU riteA) {
261 SkASSERT(leftA <= 0xFF);
262 SkASSERT(riteA <= 0xFF);
263
264 int16_t* run = runs.fRuns;
265 uint8_t* aa = runs.fAlpha;
266
267 if (ileft > 0) {
268 run[0] = ileft;
269 aa[0] = 0;
270 run += ileft;
271 aa += ileft;
272 }
273
274 SkASSERT(leftA < 0xFF);
275 if (leftA > 0) {
276 *run++ = 1;
277 *aa++ = leftA;
278 }
279
280 if (n > 0) {
281 run[0] = n;
282 aa[0] = 0xFF;
283 run += n;
284 aa += n;
285 }
286
287 SkASSERT(riteA < 0xFF);
288 if (riteA > 0) {
289 *run++ = 1;
290 *aa++ = riteA;
291 }
292 run[0] = 0;
293}
caryclark@google.com803eceb2012-06-06 12:09:34 +0000294#endif
reed@google.coma89c77b2011-12-01 21:47:26 +0000295
reed@google.com967a35d2011-10-31 19:37:58 +0000296void SuperBlitter::blitRect(int x, int y, int width, int height) {
297 SkASSERT(width > 0);
298 SkASSERT(height > 0);
299
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000300 // blit leading rows
301 while ((y & MASK)) {
reed@google.com967a35d2011-10-31 19:37:58 +0000302 this->blitH(x, y++, width);
303 if (--height <= 0) {
304 return;
305 }
306 }
307 SkASSERT(height > 0);
308
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000309 // Since this is a rect, instead of blitting supersampled rows one at a
310 // time and then resolving to the destination canvas, we can blit
311 // directly to the destintion canvas one row per SCALE supersampled rows.
reed@google.com967a35d2011-10-31 19:37:58 +0000312 int start_y = y >> SHIFT;
313 int stop_y = (y + height) >> SHIFT;
314 int count = stop_y - start_y;
315 if (count > 0) {
316 y += count << SHIFT;
317 height -= count << SHIFT;
318
319 // save original X for our tail blitH() loop at the bottom
320 int origX = x;
321
322 x -= fSuperLeft;
323 // hack, until I figure out why my cubics (I think) go beyond the bounds
324 if (x < 0) {
325 width += x;
326 x = 0;
327 }
328
tomhudson@google.com49eac192011-12-27 13:59:20 +0000329 // There is always a left column, a middle, and a right column.
330 // ileft is the destination x of the first pixel of the entire rect.
331 // xleft is (SCALE - # of covered supersampled pixels) in that
332 // destination pixel.
reed@google.com967a35d2011-10-31 19:37:58 +0000333 int ileft = x >> SHIFT;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000334 int xleft = x & MASK;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000335 // irite is the destination x of the last pixel of the OPAQUE section.
336 // xrite is the number of supersampled pixels extending beyond irite;
337 // xrite/SCALE should give us alpha.
reed@google.com967a35d2011-10-31 19:37:58 +0000338 int irite = (x + width) >> SHIFT;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000339 int xrite = (x + width) & MASK;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000340 if (!xrite) {
341 xrite = SCALE;
342 irite--;
343 }
344
tomhudson@google.com47143592011-12-28 17:58:07 +0000345 // Need to call flush() to clean up pending draws before we
346 // even consider blitV(), since otherwise it can look nonmonotonic.
347 SkASSERT(start_y > fCurrIY);
348 this->flush();
349
reed@google.com967a35d2011-10-31 19:37:58 +0000350 int n = irite - ileft - 1;
351 if (n < 0) {
tomhudson@google.com47143592011-12-28 17:58:07 +0000352 // If n < 0, we'll only have a single partially-transparent column
353 // of pixels to render.
reed@google.com967a35d2011-10-31 19:37:58 +0000354 xleft = xrite - xleft;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000355 SkASSERT(xleft <= SCALE);
356 SkASSERT(xleft > 0);
tomhudson@google.com49eac192011-12-27 13:59:20 +0000357 fRealBlitter->blitV(ileft + fLeft, start_y, count,
358 coverage_to_exact_alpha(xleft));
reed@google.com967a35d2011-10-31 19:37:58 +0000359 } else {
tomhudson@google.com47143592011-12-28 17:58:07 +0000360 // With n = 0, we have two possibly-transparent columns of pixels
361 // to render; with n > 0, we have opaque columns between them.
362
tomhudson@google.com49eac192011-12-27 13:59:20 +0000363 xleft = SCALE - xleft;
tomhudson@google.com47143592011-12-28 17:58:07 +0000364
365 // Using coverage_to_exact_alpha is not consistent with blitH()
366 const int coverageL = coverage_to_exact_alpha(xleft);
367 const int coverageR = coverage_to_exact_alpha(xrite);
368
369 SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
370 SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
371
372 fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
373 coverageL, coverageR);
reed@google.com967a35d2011-10-31 19:37:58 +0000374 }
375
reed@google.com967a35d2011-10-31 19:37:58 +0000376 // preamble for our next call to blitH()
377 fCurrIY = stop_y - 1;
378 fOffsetX = 0;
379 fCurrY = y - 1;
380 fRuns.reset(fWidth);
381 x = origX;
382 }
383
tomhudson@google.com49eac192011-12-27 13:59:20 +0000384 // catch any remaining few rows
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000385 SkASSERT(height <= MASK);
reed@google.com967a35d2011-10-31 19:37:58 +0000386 while (--height >= 0) {
387 this->blitH(x, y++, width);
388 }
389}
390
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391///////////////////////////////////////////////////////////////////////////////
392
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000393/// Masked supersampling antialiased blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394class MaskSuperBlitter : public BaseSuperBlitter {
395public:
reedbcba2c92014-10-15 08:52:00 -0700396 MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion&, bool isInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397 virtual ~MaskSuperBlitter() {
398 fRealBlitter->blitMask(fMask, fClipRect);
399 }
400
mtklein36352bf2015-03-25 18:17:31 -0700401 void blitH(int x, int y, int width) override;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000402
reed@google.com9f2f0a82011-04-11 19:43:58 +0000403 static bool CanHandleRect(const SkIRect& bounds) {
404#ifdef FORCE_RLE
405 return false;
406#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 int width = bounds.width();
reed@google.comf9f258c2012-03-12 16:09:06 +0000408 int64_t rb = SkAlign4(width);
409 // use 64bits to detect overflow
410 int64_t storage = rb * bounds.height();
reed@google.com55b6b582011-03-02 15:58:18 +0000411
reed@android.com8a1c16f2008-12-17 15:59:43 +0000412 return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
reed@google.comf9f258c2012-03-12 16:09:06 +0000413 (storage <= MaskSuperBlitter::kMAX_STORAGE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 }
reed@google.com55b6b582011-03-02 15:58:18 +0000415
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416private:
417 enum {
reed@google.com9f2f0a82011-04-11 19:43:58 +0000418#ifdef FORCE_SUPERMASK
419 kMAX_WIDTH = 2048,
420 kMAX_STORAGE = 1024 * 1024 * 2
421#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
423 kMAX_STORAGE = 1024
reed@google.com9f2f0a82011-04-11 19:43:58 +0000424#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425 };
426
427 SkMask fMask;
428 SkIRect fClipRect;
429 // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
430 // perform a test to see if stopAlpha != 0
431 uint32_t fStorage[(kMAX_STORAGE >> 2) + 1];
432};
433
reedbcba2c92014-10-15 08:52:00 -0700434MaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip,
435 bool isInverse)
436 : BaseSuperBlitter(realBlitter, ir, clip, isInverse)
437{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438 SkASSERT(CanHandleRect(ir));
reedbcba2c92014-10-15 08:52:00 -0700439 SkASSERT(!isInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000440
441 fMask.fImage = (uint8_t*)fStorage;
442 fMask.fBounds = ir;
443 fMask.fRowBytes = ir.width();
444 fMask.fFormat = SkMask::kA8_Format;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000445
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 fClipRect = ir;
robertphillipsf4e59952015-01-07 12:16:10 -0800447 if (!fClipRect.intersect(clip.getBounds())) {
448 SkASSERT(0);
449 fClipRect.setEmpty();
450 }
reed@google.com55b6b582011-03-02 15:58:18 +0000451
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452 // For valgrind, write 1 extra byte at the end so we don't read
453 // uninitialized memory. See comment in add_aa_span and fStorage[].
454 memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
455}
456
reed@google.com9f2f0a82011-04-11 19:43:58 +0000457static void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458 /* I should be able to just add alpha[x] + startAlpha.
459 However, if the trailing edge of the previous span and the leading
460 edge of the current span round to the same super-sampled x value,
461 I might overflow to 256 with this add, hence the funny subtract.
462 */
463 unsigned tmp = *alpha + startAlpha;
464 SkASSERT(tmp <= 256);
465 *alpha = SkToU8(tmp - (tmp >> 8));
466}
467
reed@google.com9f2f0a82011-04-11 19:43:58 +0000468static inline uint32_t quadplicate_byte(U8CPU value) {
469 uint32_t pair = (value << 8) | value;
470 return (pair << 16) | pair;
471}
472
reed@google.com6997e5d2012-05-09 13:48:50 +0000473// Perform this tricky subtract, to avoid overflowing to 256. Our caller should
474// only ever call us with at most enough to hit 256 (never larger), so it is
475// enough to just subtract the high-bit. Actually clamping with a branch would
476// be slower (e.g. if (tmp > 255) tmp = 255;)
477//
478static inline void saturated_add(uint8_t* ptr, U8CPU add) {
479 unsigned tmp = *ptr + add;
480 SkASSERT(tmp <= 256);
481 *ptr = SkToU8(tmp - (tmp >> 8));
482}
483
reed@google.com9f2f0a82011-04-11 19:43:58 +0000484// minimum count before we want to setup an inner loop, adding 4-at-a-time
485#define MIN_COUNT_FOR_QUAD_LOOP 16
486
487static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
488 U8CPU stopAlpha, U8CPU maxValue) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000489 SkASSERT(middleCount >= 0);
490
reed@google.com6997e5d2012-05-09 13:48:50 +0000491 saturated_add(alpha, startAlpha);
492 alpha += 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493
reed@google.com9f2f0a82011-04-11 19:43:58 +0000494 if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
495 // loop until we're quad-byte aligned
496 while (SkTCast<intptr_t>(alpha) & 0x3) {
497 alpha[0] = SkToU8(alpha[0] + maxValue);
498 alpha += 1;
499 middleCount -= 1;
500 }
501
502 int bigCount = middleCount >> 2;
503 uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
504 uint32_t qval = quadplicate_byte(maxValue);
505 do {
506 *qptr++ += qval;
507 } while (--bigCount > 0);
508
509 middleCount &= 3;
510 alpha = reinterpret_cast<uint8_t*> (qptr);
511 // fall through to the following while-loop
512 }
513
514 while (--middleCount >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 alpha[0] = SkToU8(alpha[0] + maxValue);
516 alpha += 1;
517 }
518
519 // potentially this can be off the end of our "legal" alpha values, but that
520 // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
521 // every time (slow), we just do it, and ensure that we've allocated extra space
522 // (see the + 1 comment in fStorage[]
reed@google.com6997e5d2012-05-09 13:48:50 +0000523 saturated_add(alpha, stopAlpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524}
525
reed@google.com9f2f0a82011-04-11 19:43:58 +0000526void MaskSuperBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000527 int iy = (y >> SHIFT);
reed@google.com55b6b582011-03-02 15:58:18 +0000528
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529 SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
530 iy -= fMask.fBounds.fTop; // make it relative to 0
531
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000532 // This should never happen, but it does. Until the true cause is
533 // discovered, let's skip this span instead of crashing.
534 // See http://crbug.com/17569.
535 if (iy < 0) {
536 return;
537 }
538
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539#ifdef SK_DEBUG
540 {
541 int ix = x >> SHIFT;
542 SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
543 }
544#endif
reed@google.com55b6b582011-03-02 15:58:18 +0000545
caryclark3127c992015-12-09 12:02:30 -0800546 x -= SkLeftShift(fMask.fBounds.fLeft, SHIFT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547
548 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000549 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550 width += x;
551 x = 0;
552 }
553
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554 uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
555
556 int start = x;
557 int stop = x + width;
558
559 SkASSERT(start >= 0 && stop > start);
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000560 int fb = start & MASK;
561 int fe = stop & MASK;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
563
564
reed@google.com9f2f0a82011-04-11 19:43:58 +0000565 if (n < 0) {
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000566 SkASSERT(row >= fMask.fImage);
567 SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
tomhudson@google.comffc92482012-02-23 19:34:34 +0000568 add_aa_span(row, coverage_to_partial_alpha(fe - fb));
reed@google.com9f2f0a82011-04-11 19:43:58 +0000569 } else {
tomhudson@google.com49eac192011-12-27 13:59:20 +0000570 fb = SCALE - fb;
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000571 SkASSERT(row >= fMask.fImage);
572 SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
tomhudson@google.comffc92482012-02-23 19:34:34 +0000573 add_aa_span(row, coverage_to_partial_alpha(fb),
574 n, coverage_to_partial_alpha(fe),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
576 }
577
578#ifdef SK_DEBUG
579 fCurrX = x + width;
580#endif
581}
582
583///////////////////////////////////////////////////////////////////////////////
584
reed@google.com07db8612012-02-28 15:32:42 +0000585static bool fitsInsideLimit(const SkRect& r, SkScalar max) {
586 const SkScalar min = -max;
587 return r.fLeft > min && r.fTop > min &&
588 r.fRight < max && r.fBottom < max;
589}
590
tomhudson@google.com17b6ba42012-04-12 14:23:58 +0000591static int overflows_short_shift(int value, int shift) {
592 const int s = 16 + shift;
caryclark3127c992015-12-09 12:02:30 -0800593 return (SkLeftShift(value, s) >> s) - value;
tomhudson@google.com17b6ba42012-04-12 14:23:58 +0000594}
595
596/**
597 Would any of the coordinates of this rectangle not fit in a short,
598 when left-shifted by shift?
599*/
600static int rect_overflows_short_shift(SkIRect rect, int shift) {
601 SkASSERT(!overflows_short_shift(8191, SHIFT));
602 SkASSERT(overflows_short_shift(8192, SHIFT));
603 SkASSERT(!overflows_short_shift(32767, 0));
604 SkASSERT(overflows_short_shift(32768, 0));
605
606 // Since we expect these to succeed, we bit-or together
607 // for a tiny extra bit of speed.
608 return overflows_short_shift(rect.fLeft, SHIFT) |
609 overflows_short_shift(rect.fRight, SHIFT) |
610 overflows_short_shift(rect.fTop, SHIFT) |
611 overflows_short_shift(rect.fBottom, SHIFT);
612}
613
reed@google.com07db8612012-02-28 15:32:42 +0000614static bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) {
615 const SkScalar maxScalar = SkIntToScalar(maxInt);
reed@google.com8f4d2302013-12-17 16:44:46 +0000616
reed@google.com07db8612012-02-28 15:32:42 +0000617 if (fitsInsideLimit(src, maxScalar)) {
618 src.roundOut(dst);
619 return true;
620 }
621 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622}
623
reed@google.com5546ef22012-01-30 17:09:45 +0000624void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip,
reed@google.com2c508f22011-10-03 21:15:46 +0000625 SkBlitter* blitter, bool forceRLE) {
reed@google.com5546ef22012-01-30 17:09:45 +0000626 if (origClip.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627 return;
628 }
629
reedbcba2c92014-10-15 08:52:00 -0700630 const bool isInverse = path.isInverseFillType();
reed@android.comd252db02009-04-01 18:31:44 +0000631 SkIRect ir;
reed@google.com07db8612012-02-28 15:32:42 +0000632
633 if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> SHIFT)) {
634#if 0
635 const SkRect& r = path.getBounds();
636 SkDebugf("--- bounds can't fit in SkIRect\n", r.fLeft, r.fTop, r.fRight, r.fBottom);
637#endif
638 return;
639 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640 if (ir.isEmpty()) {
reedbcba2c92014-10-15 08:52:00 -0700641 if (isInverse) {
reed@google.com5546ef22012-01-30 17:09:45 +0000642 blitter->blitRegion(origClip);
reed@google.comee068aa2011-12-21 19:36:21 +0000643 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000644 return;
645 }
646
tomhudson@google.com17b6ba42012-04-12 14:23:58 +0000647 // If the intersection of the path bounds and the clip bounds
648 // will overflow 32767 when << by SHIFT, we can't supersample,
649 // so draw without antialiasing.
650 SkIRect clippedIR;
reedbcba2c92014-10-15 08:52:00 -0700651 if (isInverse) {
tomhudson@google.com17b6ba42012-04-12 14:23:58 +0000652 // If the path is an inverse fill, it's going to fill the entire
653 // clip, and we care whether the entire clip exceeds our limits.
654 clippedIR = origClip.getBounds();
655 } else {
656 if (!clippedIR.intersect(ir, origClip.getBounds())) {
657 return;
658 }
659 }
660 if (rect_overflows_short_shift(clippedIR, SHIFT)) {
661 SkScan::FillPath(path, origClip, blitter);
662 return;
663 }
664
reed@google.com5546ef22012-01-30 17:09:45 +0000665 // Our antialiasing can't handle a clip larger than 32767, so we restrict
666 // the clip to that limit here. (the runs[] uses int16_t for its index).
667 //
tomhudson@google.com17b6ba42012-04-12 14:23:58 +0000668 // A more general solution (one that could also eliminate the need to
669 // disable aa based on ir bounds (see overflows_short_shift) would be
670 // to tile the clip/target...
reed@google.com5546ef22012-01-30 17:09:45 +0000671 SkRegion tmpClipStorage;
672 const SkRegion* clipRgn = &origClip;
673 {
674 static const int32_t kMaxClipCoord = 32767;
675 const SkIRect& bounds = origClip.getBounds();
676 if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) {
677 SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord };
678 tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op);
679 clipRgn = &tmpClipStorage;
680 }
681 }
682 // for here down, use clipRgn, not origClip
683
684 SkScanClipper clipper(blitter, clipRgn, ir);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 const SkIRect* clipRect = clipper.getClipRect();
686
halcanary96fcdcc2015-08-27 07:41:13 -0700687 if (clipper.getBlitter() == nullptr) { // clipped out
reedbcba2c92014-10-15 08:52:00 -0700688 if (isInverse) {
reed@google.com5546ef22012-01-30 17:09:45 +0000689 blitter->blitRegion(*clipRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690 }
691 return;
692 }
reed@google.com55b6b582011-03-02 15:58:18 +0000693
Yuqian Lie4b8b522016-11-16 10:12:58 -0500694 SkASSERT(clipper.getClipRect() == nullptr ||
695 *clipper.getClipRect() == clipRgn->getBounds());
696
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697 // now use the (possibly wrapped) blitter
698 blitter = clipper.getBlitter();
699
reedbcba2c92014-10-15 08:52:00 -0700700 if (isInverse) {
reed@google.com5546ef22012-01-30 17:09:45 +0000701 sk_blit_above(blitter, ir, *clipRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702 }
703
halcanary96fcdcc2015-08-27 07:41:13 -0700704 SkIRect superRect, *superClipRect = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705
reed@google.com9f2f0a82011-04-11 19:43:58 +0000706 if (clipRect) {
reed513d3072016-02-03 10:16:08 -0800707 superRect.set(SkLeftShift(clipRect->fLeft, SHIFT),
708 SkLeftShift(clipRect->fTop, SHIFT),
709 SkLeftShift(clipRect->fRight, SHIFT),
710 SkLeftShift(clipRect->fBottom, SHIFT));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711 superClipRect = &superRect;
712 }
713
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000714 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
715
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716 // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
717 // if we're an inverse filltype
reedbcba2c92014-10-15 08:52:00 -0700718 if (!isInverse && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
719 MaskSuperBlitter superBlit(blitter, ir, *clipRgn, isInverse);
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000720 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
Yuqian Lie4b8b522016-11-16 10:12:58 -0500721 sk_fill_path(path, clipRgn->getBounds(), &superBlit, ir.fTop, ir.fBottom, SHIFT,
722 superClipRect == nullptr);
reed@google.com9f2f0a82011-04-11 19:43:58 +0000723 } else {
reedbcba2c92014-10-15 08:52:00 -0700724 SuperBlitter superBlit(blitter, ir, *clipRgn, isInverse);
Yuqian Lie4b8b522016-11-16 10:12:58 -0500725 sk_fill_path(path, clipRgn->getBounds(), &superBlit, ir.fTop, ir.fBottom, SHIFT,
726 superClipRect == nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000727 }
reed@google.com55b6b582011-03-02 15:58:18 +0000728
reedbcba2c92014-10-15 08:52:00 -0700729 if (isInverse) {
reed@google.com5546ef22012-01-30 17:09:45 +0000730 sk_blit_below(blitter, ir, *clipRgn);
reed@google.com55b6b582011-03-02 15:58:18 +0000731 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732}
reed@google.com1ba71372011-10-12 20:42:05 +0000733
734///////////////////////////////////////////////////////////////////////////////
735
736#include "SkRasterClip.h"
737
738void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip,
739 SkBlitter* blitter) {
740 if (clip.isEmpty()) {
741 return;
742 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000743
reed@google.com1ba71372011-10-12 20:42:05 +0000744 if (clip.isBW()) {
745 FillPath(path, clip.bwRgn(), blitter);
746 } else {
747 SkRegion tmp;
748 SkAAClipBlitter aaBlitter;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000749
reed@google.com1ba71372011-10-12 20:42:05 +0000750 tmp.setRect(clip.getBounds());
751 aaBlitter.init(blitter, &clip.aaRgn());
752 SkScan::FillPath(path, tmp, &aaBlitter);
753 }
754}
755
Yuqian Li550148b2017-01-13 10:13:13 -0500756static bool suitableForAAA(const SkPath& path) {
Yuqian Li550148b2017-01-13 10:13:13 -0500757 if (gSkForceAnalyticAA.load()) {
758 return true;
759 }
760 const SkRect& bounds = path.getBounds();
761 // When the path have so many points compared to the size of its bounds/resolution,
762 // it indicates that the path is not quite smooth in the current resolution:
763 // the expected number of turning points in every pixel row/column is significantly greater than
Yuqian Li8de05ff2017-03-06 17:04:58 -0500764 // zero. Hence Aanlytic AA is not likely to produce visible quality improvements, and Analytic
765 // AA might be slower than supersampling.
Yuqian Li550148b2017-01-13 10:13:13 -0500766 return path.countPoints() < SkTMax(bounds.width(), bounds.height()) / 2 - 10;
767}
768
reed@google.com1ba71372011-10-12 20:42:05 +0000769void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
770 SkBlitter* blitter) {
Yuqian Li550148b2017-01-13 10:13:13 -0500771 // Do not use AAA if path is too complicated:
772 // there won't be any speedup or significant visual improvement.
773 if (gSkUseAnalyticAA.load() && suitableForAAA(path)) {
liyuqian38911a72016-10-04 11:23:22 -0700774 SkScan::AAAFillPath(path, clip, blitter);
775 return;
776 }
777
reed@google.com1ba71372011-10-12 20:42:05 +0000778 if (clip.isEmpty()) {
779 return;
780 }
781
782 if (clip.isBW()) {
783 AntiFillPath(path, clip.bwRgn(), blitter);
784 } else {
785 SkRegion tmp;
786 SkAAClipBlitter aaBlitter;
787
788 tmp.setRect(clip.getBounds());
789 aaBlitter.init(blitter, &clip.aaRgn());
790 SkScan::AntiFillPath(path, tmp, &aaBlitter, true);
791 }
792}