blob: db1527f6506c49e23621aeb36e2c5f6d14ecee2c [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
Mike Reed23e0cf22018-01-16 13:58:01 -050016#define SHIFT SK_SUPERSAMPLE_SHIFT
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#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,
Yuqian Li3a5e1fe2017-09-28 10:58:38 -040042 const SkIRect& clipBounds, 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
Yuqian Li3a5e1fe2017-09-28 10:58:38 -040074BaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlit, const SkIRect& ir,
75 const SkIRect& clipBounds, bool isInverse) {
reedbcba2c92014-10-15 08:52:00 -070076 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
Yuqian Li3a5e1fe2017-09-28 10:58:38 -040082 sectBounds = clipBounds;
reedbcba2c92014-10-15 08:52:00 -070083 } else {
Yuqian Li3a5e1fe2017-09-28 10:58:38 -040084 if (!sectBounds.intersect(ir, clipBounds)) {
reedbcba2c92014-10-15 08:52:00 -070085 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:
Yuqian Li3a5e1fe2017-09-28 10:58:38 -0400105 SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkIRect& clipBounds,
106 bool isInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107
Brian Salomond3b65972017-03-22 12:05:03 -0400108 ~SuperBlitter() override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 this->flush();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110 }
111
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000112 /// Once fRuns contains a complete supersampled row, flush() blits
113 /// it out through the wrapped blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 void flush();
115
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000116 /// Blits a row of pixels, with location and width specified
117 /// in supersampled coordinates.
mtklein36352bf2015-03-25 18:17:31 -0700118 void blitH(int x, int y, int width) override;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000119 /// Blits a rectangle of pixels, with location and size specified
120 /// in supersampled coordinates.
mtklein36352bf2015-03-25 18:17:31 -0700121 void blitRect(int x, int y, int width, int height) override;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122
123private:
krajcevski2ec93fc2014-07-16 13:31:41 -0700124 // The next three variables are used to track a circular buffer that
125 // contains the values used in SkAlphaRuns. These variables should only
126 // ever be updated in advanceRuns(), and fRuns should always point to
127 // a valid SkAlphaRuns...
128 int fRunsToBuffer;
129 void* fRunsBuffer;
130 int fCurrentRun;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 SkAlphaRuns fRuns;
krajcevski2ec93fc2014-07-16 13:31:41 -0700132
133 // extra one to store the zero at the end
134 int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); }
135
136 // This function updates the fRuns variable to point to the next buffer space
137 // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
138 // and resets fRuns to point to an empty scanline.
139 void advanceRuns() {
140 const size_t kRunsSz = this->getRunsSz();
141 fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
142 fRuns.fRuns = reinterpret_cast<int16_t*>(
143 reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz);
144 fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
145 fRuns.reset(fWidth);
146 }
147
reed@google.comfa57ae72011-05-31 19:18:02 +0000148 int fOffsetX;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149};
150
Yuqian Li3a5e1fe2017-09-28 10:58:38 -0400151SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkIRect& clipBounds,
reedbcba2c92014-10-15 08:52:00 -0700152 bool isInverse)
Yuqian Li3a5e1fe2017-09-28 10:58:38 -0400153 : BaseSuperBlitter(realBlitter, ir, clipBounds, isInverse)
reedbcba2c92014-10-15 08:52:00 -0700154{
krajcevski2ec93fc2014-07-16 13:31:41 -0700155 fRunsToBuffer = realBlitter->requestRowsPreserved();
krajcevski75f88512014-07-21 09:54:23 -0700156 fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz());
krajcevski2ec93fc2014-07-16 13:31:41 -0700157 fCurrentRun = -1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158
krajcevski2ec93fc2014-07-16 13:31:41 -0700159 this->advanceRuns();
reed@google.comfa57ae72011-05-31 19:18:02 +0000160
161 fOffsetX = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162}
163
reed@google.com9f2f0a82011-04-11 19:43:58 +0000164void SuperBlitter::flush() {
reed@google.com045e62d2011-10-24 12:19:46 +0000165 if (fCurrIY >= fTop) {
krajcevski2ec93fc2014-07-16 13:31:41 -0700166
167 SkASSERT(fCurrentRun < fRunsToBuffer);
reed@google.com9f2f0a82011-04-11 19:43:58 +0000168 if (!fRuns.empty()) {
krajcevski2ec93fc2014-07-16 13:31:41 -0700169 // SkDEBUGCODE(fRuns.dump();)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
krajcevski2ec93fc2014-07-16 13:31:41 -0700171 this->advanceRuns();
reed@google.comfa57ae72011-05-31 19:18:02 +0000172 fOffsetX = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 }
krajcevski2ec93fc2014-07-16 13:31:41 -0700174
reed@google.com045e62d2011-10-24 12:19:46 +0000175 fCurrIY = fTop - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 SkDEBUGCODE(fCurrX = -1;)
177 }
178}
179
tomhudson@google.comffc92482012-02-23 19:34:34 +0000180/** coverage_to_partial_alpha() is being used by SkAlphaRuns, which
181 *accumulates* SCALE pixels worth of "alpha" in [0,(256/SCALE)]
182 to produce a final value in [0, 255] and handles clamping 256->255
183 itself, with the same (alpha - (alpha >> 8)) correction as
184 coverage_to_exact_alpha().
185*/
186static inline int coverage_to_partial_alpha(int aa) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 aa <<= 8 - 2*SHIFT;
reed@google.com5b7d6032012-05-09 14:07:34 +0000188 return aa;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189}
190
tomhudson@google.comffc92482012-02-23 19:34:34 +0000191/** coverage_to_exact_alpha() is being used by our blitter, which wants
192 a final value in [0, 255].
193*/
tomhudson@google.com49eac192011-12-27 13:59:20 +0000194static inline int coverage_to_exact_alpha(int aa) {
tomhudson@google.com31bab392012-01-03 20:12:42 +0000195 int alpha = (256 >> SHIFT) * aa;
196 // clamp 256->255
197 return alpha - (alpha >> 8);
tomhudson@google.com49eac192011-12-27 13:59:20 +0000198}
199
reed@google.com9f2f0a82011-04-11 19:43:58 +0000200void SuperBlitter::blitH(int x, int y, int width) {
reed@google.com967a35d2011-10-31 19:37:58 +0000201 SkASSERT(width > 0);
202
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 int iy = y >> SHIFT;
204 SkASSERT(iy >= fCurrIY);
205
206 x -= fSuperLeft;
207 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000208 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 width += x;
210 x = 0;
211 }
212
213#ifdef SK_DEBUG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214 SkASSERT(y != fCurrY || x >= fCurrX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215#endif
reed@google.comfa57ae72011-05-31 19:18:02 +0000216 SkASSERT(y >= fCurrY);
217 if (fCurrY != y) {
218 fOffsetX = 0;
219 fCurrY = y;
220 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000221
reed@google.com9f2f0a82011-04-11 19:43:58 +0000222 if (iy != fCurrIY) { // new scanline
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 this->flush();
224 fCurrIY = iy;
225 }
226
reed@google.com5a1e7952011-05-31 14:36:21 +0000227 int start = x;
228 int stop = x + width;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229
reed@google.com5a1e7952011-05-31 14:36:21 +0000230 SkASSERT(start >= 0 && stop > start);
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000231 // integer-pixel-aligned ends of blit, rounded out
232 int fb = start & MASK;
233 int fe = stop & MASK;
reed@google.com5a1e7952011-05-31 14:36:21 +0000234 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235
reed@google.com5a1e7952011-05-31 14:36:21 +0000236 if (n < 0) {
237 fb = fe - fb;
238 n = 0;
239 fe = 0;
240 } else {
241 if (fb == 0) {
242 n += 1;
reed@google.com9f2f0a82011-04-11 19:43:58 +0000243 } else {
tomhudson@google.com49eac192011-12-27 13:59:20 +0000244 fb = SCALE - fb;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 }
reed@google.comfa57ae72011-05-31 19:18:02 +0000247
tomhudson@google.comffc92482012-02-23 19:34:34 +0000248 fOffsetX = fRuns.add(x >> SHIFT, coverage_to_partial_alpha(fb),
249 n, coverage_to_partial_alpha(fe),
reed@google.comfa57ae72011-05-31 19:18:02 +0000250 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
251 fOffsetX);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252
253#ifdef SK_DEBUG
254 fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
255 fCurrX = x + width;
256#endif
257}
258
caryclark@google.com803eceb2012-06-06 12:09:34 +0000259#if 0 // UNUSED
reed@google.coma89c77b2011-12-01 21:47:26 +0000260static void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
261 int n, U8CPU riteA) {
262 SkASSERT(leftA <= 0xFF);
263 SkASSERT(riteA <= 0xFF);
264
265 int16_t* run = runs.fRuns;
266 uint8_t* aa = runs.fAlpha;
267
268 if (ileft > 0) {
269 run[0] = ileft;
270 aa[0] = 0;
271 run += ileft;
272 aa += ileft;
273 }
274
275 SkASSERT(leftA < 0xFF);
276 if (leftA > 0) {
277 *run++ = 1;
278 *aa++ = leftA;
279 }
280
281 if (n > 0) {
282 run[0] = n;
283 aa[0] = 0xFF;
284 run += n;
285 aa += n;
286 }
287
288 SkASSERT(riteA < 0xFF);
289 if (riteA > 0) {
290 *run++ = 1;
291 *aa++ = riteA;
292 }
293 run[0] = 0;
294}
caryclark@google.com803eceb2012-06-06 12:09:34 +0000295#endif
reed@google.coma89c77b2011-12-01 21:47:26 +0000296
reed@google.com967a35d2011-10-31 19:37:58 +0000297void SuperBlitter::blitRect(int x, int y, int width, int height) {
298 SkASSERT(width > 0);
299 SkASSERT(height > 0);
300
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000301 // blit leading rows
302 while ((y & MASK)) {
reed@google.com967a35d2011-10-31 19:37:58 +0000303 this->blitH(x, y++, width);
304 if (--height <= 0) {
305 return;
306 }
307 }
308 SkASSERT(height > 0);
309
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000310 // Since this is a rect, instead of blitting supersampled rows one at a
311 // time and then resolving to the destination canvas, we can blit
312 // directly to the destintion canvas one row per SCALE supersampled rows.
reed@google.com967a35d2011-10-31 19:37:58 +0000313 int start_y = y >> SHIFT;
314 int stop_y = (y + height) >> SHIFT;
315 int count = stop_y - start_y;
316 if (count > 0) {
317 y += count << SHIFT;
318 height -= count << SHIFT;
319
320 // save original X for our tail blitH() loop at the bottom
321 int origX = x;
322
323 x -= fSuperLeft;
324 // hack, until I figure out why my cubics (I think) go beyond the bounds
325 if (x < 0) {
326 width += x;
327 x = 0;
328 }
329
tomhudson@google.com49eac192011-12-27 13:59:20 +0000330 // There is always a left column, a middle, and a right column.
331 // ileft is the destination x of the first pixel of the entire rect.
332 // xleft is (SCALE - # of covered supersampled pixels) in that
333 // destination pixel.
reed@google.com967a35d2011-10-31 19:37:58 +0000334 int ileft = x >> SHIFT;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000335 int xleft = x & MASK;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000336 // irite is the destination x of the last pixel of the OPAQUE section.
337 // xrite is the number of supersampled pixels extending beyond irite;
338 // xrite/SCALE should give us alpha.
reed@google.com967a35d2011-10-31 19:37:58 +0000339 int irite = (x + width) >> SHIFT;
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000340 int xrite = (x + width) & MASK;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000341 if (!xrite) {
342 xrite = SCALE;
343 irite--;
344 }
345
tomhudson@google.com47143592011-12-28 17:58:07 +0000346 // Need to call flush() to clean up pending draws before we
347 // even consider blitV(), since otherwise it can look nonmonotonic.
348 SkASSERT(start_y > fCurrIY);
349 this->flush();
350
reed@google.com967a35d2011-10-31 19:37:58 +0000351 int n = irite - ileft - 1;
352 if (n < 0) {
tomhudson@google.com47143592011-12-28 17:58:07 +0000353 // If n < 0, we'll only have a single partially-transparent column
354 // of pixels to render.
reed@google.com967a35d2011-10-31 19:37:58 +0000355 xleft = xrite - xleft;
tomhudson@google.com49eac192011-12-27 13:59:20 +0000356 SkASSERT(xleft <= SCALE);
357 SkASSERT(xleft > 0);
tomhudson@google.com49eac192011-12-27 13:59:20 +0000358 fRealBlitter->blitV(ileft + fLeft, start_y, count,
359 coverage_to_exact_alpha(xleft));
reed@google.com967a35d2011-10-31 19:37:58 +0000360 } else {
tomhudson@google.com47143592011-12-28 17:58:07 +0000361 // With n = 0, we have two possibly-transparent columns of pixels
362 // to render; with n > 0, we have opaque columns between them.
363
tomhudson@google.com49eac192011-12-27 13:59:20 +0000364 xleft = SCALE - xleft;
tomhudson@google.com47143592011-12-28 17:58:07 +0000365
366 // Using coverage_to_exact_alpha is not consistent with blitH()
367 const int coverageL = coverage_to_exact_alpha(xleft);
368 const int coverageR = coverage_to_exact_alpha(xrite);
369
370 SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
371 SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
372
373 fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
374 coverageL, coverageR);
reed@google.com967a35d2011-10-31 19:37:58 +0000375 }
376
reed@google.com967a35d2011-10-31 19:37:58 +0000377 // preamble for our next call to blitH()
378 fCurrIY = stop_y - 1;
379 fOffsetX = 0;
380 fCurrY = y - 1;
381 fRuns.reset(fWidth);
382 x = origX;
383 }
384
tomhudson@google.com49eac192011-12-27 13:59:20 +0000385 // catch any remaining few rows
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000386 SkASSERT(height <= MASK);
reed@google.com967a35d2011-10-31 19:37:58 +0000387 while (--height >= 0) {
388 this->blitH(x, y++, width);
389 }
390}
391
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392///////////////////////////////////////////////////////////////////////////////
393
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000394/// Masked supersampling antialiased blitter.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395class MaskSuperBlitter : public BaseSuperBlitter {
396public:
Yuqian Li3a5e1fe2017-09-28 10:58:38 -0400397 MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkIRect&, bool isInverse);
Brian Salomond3b65972017-03-22 12:05:03 -0400398 ~MaskSuperBlitter() override {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000399 fRealBlitter->blitMask(fMask, fClipRect);
400 }
401
mtklein36352bf2015-03-25 18:17:31 -0700402 void blitH(int x, int y, int width) override;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403
reed@google.com9f2f0a82011-04-11 19:43:58 +0000404 static bool CanHandleRect(const SkIRect& bounds) {
405#ifdef FORCE_RLE
406 return false;
407#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408 int width = bounds.width();
reed@google.comf9f258c2012-03-12 16:09:06 +0000409 int64_t rb = SkAlign4(width);
410 // use 64bits to detect overflow
411 int64_t storage = rb * bounds.height();
reed@google.com55b6b582011-03-02 15:58:18 +0000412
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413 return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
reed@google.comf9f258c2012-03-12 16:09:06 +0000414 (storage <= MaskSuperBlitter::kMAX_STORAGE);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415 }
reed@google.com55b6b582011-03-02 15:58:18 +0000416
reed@android.com8a1c16f2008-12-17 15:59:43 +0000417private:
418 enum {
reed@google.com9f2f0a82011-04-11 19:43:58 +0000419#ifdef FORCE_SUPERMASK
420 kMAX_WIDTH = 2048,
421 kMAX_STORAGE = 1024 * 1024 * 2
422#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423 kMAX_WIDTH = 32, // so we don't try to do very wide things, where the RLE blitter would be faster
424 kMAX_STORAGE = 1024
reed@google.com9f2f0a82011-04-11 19:43:58 +0000425#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 };
427
428 SkMask fMask;
429 SkIRect fClipRect;
430 // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
431 // perform a test to see if stopAlpha != 0
432 uint32_t fStorage[(kMAX_STORAGE >> 2) + 1];
433};
434
Yuqian Li3a5e1fe2017-09-28 10:58:38 -0400435MaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
436 const SkIRect& clipBounds, bool isInverse)
437 : BaseSuperBlitter(realBlitter, ir, clipBounds, isInverse)
reedbcba2c92014-10-15 08:52:00 -0700438{
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439 SkASSERT(CanHandleRect(ir));
reedbcba2c92014-10-15 08:52:00 -0700440 SkASSERT(!isInverse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441
442 fMask.fImage = (uint8_t*)fStorage;
443 fMask.fBounds = ir;
444 fMask.fRowBytes = ir.width();
445 fMask.fFormat = SkMask::kA8_Format;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000446
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447 fClipRect = ir;
Yuqian Li3a5e1fe2017-09-28 10:58:38 -0400448 if (!fClipRect.intersect(clipBounds)) {
robertphillipsf4e59952015-01-07 12:16:10 -0800449 SkASSERT(0);
450 fClipRect.setEmpty();
451 }
reed@google.com55b6b582011-03-02 15:58:18 +0000452
reed@android.com8a1c16f2008-12-17 15:59:43 +0000453 // For valgrind, write 1 extra byte at the end so we don't read
454 // uninitialized memory. See comment in add_aa_span and fStorage[].
455 memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
456}
457
reed@google.com9f2f0a82011-04-11 19:43:58 +0000458static void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000459 /* I should be able to just add alpha[x] + startAlpha.
460 However, if the trailing edge of the previous span and the leading
461 edge of the current span round to the same super-sampled x value,
462 I might overflow to 256 with this add, hence the funny subtract.
463 */
464 unsigned tmp = *alpha + startAlpha;
465 SkASSERT(tmp <= 256);
466 *alpha = SkToU8(tmp - (tmp >> 8));
467}
468
reed@google.com9f2f0a82011-04-11 19:43:58 +0000469static inline uint32_t quadplicate_byte(U8CPU value) {
470 uint32_t pair = (value << 8) | value;
471 return (pair << 16) | pair;
472}
473
reed@google.com6997e5d2012-05-09 13:48:50 +0000474// Perform this tricky subtract, to avoid overflowing to 256. Our caller should
475// only ever call us with at most enough to hit 256 (never larger), so it is
476// enough to just subtract the high-bit. Actually clamping with a branch would
477// be slower (e.g. if (tmp > 255) tmp = 255;)
478//
479static inline void saturated_add(uint8_t* ptr, U8CPU add) {
480 unsigned tmp = *ptr + add;
481 SkASSERT(tmp <= 256);
482 *ptr = SkToU8(tmp - (tmp >> 8));
483}
484
reed@google.com9f2f0a82011-04-11 19:43:58 +0000485// minimum count before we want to setup an inner loop, adding 4-at-a-time
486#define MIN_COUNT_FOR_QUAD_LOOP 16
487
488static void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
489 U8CPU stopAlpha, U8CPU maxValue) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490 SkASSERT(middleCount >= 0);
491
reed@google.com6997e5d2012-05-09 13:48:50 +0000492 saturated_add(alpha, startAlpha);
493 alpha += 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000494
reed@google.com9f2f0a82011-04-11 19:43:58 +0000495 if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
496 // loop until we're quad-byte aligned
497 while (SkTCast<intptr_t>(alpha) & 0x3) {
498 alpha[0] = SkToU8(alpha[0] + maxValue);
499 alpha += 1;
500 middleCount -= 1;
501 }
502
503 int bigCount = middleCount >> 2;
504 uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
505 uint32_t qval = quadplicate_byte(maxValue);
506 do {
507 *qptr++ += qval;
508 } while (--bigCount > 0);
509
510 middleCount &= 3;
511 alpha = reinterpret_cast<uint8_t*> (qptr);
512 // fall through to the following while-loop
513 }
514
515 while (--middleCount >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516 alpha[0] = SkToU8(alpha[0] + maxValue);
517 alpha += 1;
518 }
519
520 // potentially this can be off the end of our "legal" alpha values, but that
521 // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
522 // every time (slow), we just do it, and ensure that we've allocated extra space
523 // (see the + 1 comment in fStorage[]
reed@google.com6997e5d2012-05-09 13:48:50 +0000524 saturated_add(alpha, stopAlpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525}
526
reed@google.com9f2f0a82011-04-11 19:43:58 +0000527void MaskSuperBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000528 int iy = (y >> SHIFT);
reed@google.com55b6b582011-03-02 15:58:18 +0000529
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
531 iy -= fMask.fBounds.fTop; // make it relative to 0
532
senorblanco@chromium.orgc41513c2009-08-21 22:00:12 +0000533 // This should never happen, but it does. Until the true cause is
534 // discovered, let's skip this span instead of crashing.
535 // See http://crbug.com/17569.
536 if (iy < 0) {
537 return;
538 }
539
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540#ifdef SK_DEBUG
541 {
542 int ix = x >> SHIFT;
543 SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
544 }
545#endif
reed@google.com55b6b582011-03-02 15:58:18 +0000546
caryclark3127c992015-12-09 12:02:30 -0800547 x -= SkLeftShift(fMask.fBounds.fLeft, SHIFT);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548
549 // hack, until I figure out why my cubics (I think) go beyond the bounds
reed@google.com9f2f0a82011-04-11 19:43:58 +0000550 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551 width += x;
552 x = 0;
553 }
554
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555 uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
556
557 int start = x;
558 int stop = x + width;
559
560 SkASSERT(start >= 0 && stop > start);
tomhudson@google.com05fffdc2011-12-01 20:41:24 +0000561 int fb = start & MASK;
562 int fe = stop & MASK;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563 int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
564
565
reed@google.com9f2f0a82011-04-11 19:43:58 +0000566 if (n < 0) {
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000567 SkASSERT(row >= fMask.fImage);
568 SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
tomhudson@google.comffc92482012-02-23 19:34:34 +0000569 add_aa_span(row, coverage_to_partial_alpha(fe - fb));
reed@google.com9f2f0a82011-04-11 19:43:58 +0000570 } else {
tomhudson@google.com49eac192011-12-27 13:59:20 +0000571 fb = SCALE - fb;
senorblanco@chromium.orgfeef49c2009-08-12 20:21:49 +0000572 SkASSERT(row >= fMask.fImage);
573 SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
tomhudson@google.comffc92482012-02-23 19:34:34 +0000574 add_aa_span(row, coverage_to_partial_alpha(fb),
575 n, coverage_to_partial_alpha(fe),
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576 (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
577 }
578
579#ifdef SK_DEBUG
580 fCurrX = x + width;
581#endif
582}
583
584///////////////////////////////////////////////////////////////////////////////
585
Yuqian Li7d99dad2017-07-26 13:47:26 -0400586static bool ShouldUseDAA(const SkPath& path) {
587 if (gSkForceDeltaAA) {
588 return true;
589 }
590 if (!gSkUseDeltaAA) {
591 return false;
592 }
593 const SkRect& bounds = path.getBounds();
594 return !path.isConvex() && path.countPoints() >= SkTMax(bounds.width(), bounds.height()) / 8;
595}
596
597static bool ShouldUseAAA(const SkPath& path) {
598 if (gSkForceAnalyticAA) {
599 return true;
600 }
601 if (!gSkUseAnalyticAA) {
602 return false;
603 }
604 if (path.isRect(nullptr)) {
605 return true;
606 }
607 const SkRect& bounds = path.getBounds();
608 // When the path have so many points compared to the size of its bounds/resolution,
609 // it indicates that the path is not quite smooth in the current resolution:
610 // the expected number of turning points in every pixel row/column is significantly greater than
611 // zero. Hence Aanlytic AA is not likely to produce visible quality improvements, and Analytic
612 // AA might be slower than supersampling.
613 return path.countPoints() < SkTMax(bounds.width(), bounds.height()) / 2 - 10;
614}
615
Yuqian Lib49d7b02017-11-06 16:21:06 -0500616void SkScan::SAAFillPath(const SkPath& path, SkBlitter* blitter, const SkIRect& ir,
Yuqian Lif4848822018-01-08 13:40:45 -0500617 const SkIRect& clipBounds, bool forceRLE) {
618 bool containedInClip = clipBounds.contains(ir);
Yuqian Lib49d7b02017-11-06 16:21:06 -0500619 bool isInverse = path.isInverseFillType();
620
621 // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
622 // if we're an inverse filltype
623 if (!isInverse && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
624 MaskSuperBlitter superBlit(blitter, ir, clipBounds, isInverse);
625 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
626 sk_fill_path(path, clipBounds, &superBlit, ir.fTop, ir.fBottom, SHIFT, containedInClip);
627 } else {
628 SuperBlitter superBlit(blitter, ir, clipBounds, isInverse);
629 sk_fill_path(path, clipBounds, &superBlit, ir.fTop, ir.fBottom, SHIFT, containedInClip);
630 }
631}
632
Yuqian Lib49d7b02017-11-06 16:21:06 -0500633static int overflows_short_shift(int value, int shift) {
634 const int s = 16 + shift;
635 return (SkLeftShift(value, s) >> s) - value;
636}
637
638/**
639 Would any of the coordinates of this rectangle not fit in a short,
640 when left-shifted by shift?
641*/
642static int rect_overflows_short_shift(SkIRect rect, int shift) {
643 SkASSERT(!overflows_short_shift(8191, shift));
644 SkASSERT(overflows_short_shift(8192, shift));
645 SkASSERT(!overflows_short_shift(32767, 0));
646 SkASSERT(overflows_short_shift(32768, 0));
647
648 // Since we expect these to succeed, we bit-or together
649 // for a tiny extra bit of speed.
650 return overflows_short_shift(rect.fLeft, shift) |
651 overflows_short_shift(rect.fRight, shift) |
652 overflows_short_shift(rect.fTop, shift) |
653 overflows_short_shift(rect.fBottom, shift);
654}
655
Mike Reed23e0cf22018-01-16 13:58:01 -0500656static SkIRect safeRoundOut(const SkRect& src) {
657 // roundOut will pin huge floats to max/min int
658 SkIRect dst = src.roundOut();
Yuqian Lib49d7b02017-11-06 16:21:06 -0500659
Mike Reed23e0cf22018-01-16 13:58:01 -0500660 // intersect with a smaller huge rect, so the rect will not be considered empty for being
661 // too large. e.g. { -SK_MaxS32 ... SK_MaxS32 } is considered empty because its width
662 // exceeds signed 32bit.
663 const int32_t limit = SK_MaxS32 >> SK_SUPERSAMPLE_SHIFT;
664 (void)dst.intersect({ -limit, -limit, limit, limit});
665
666 return dst;
Yuqian Lib49d7b02017-11-06 16:21:06 -0500667}
668
reed@google.com5546ef22012-01-30 17:09:45 +0000669void SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip,
Yuqian Li57899c72017-11-27 12:01:49 -0500670 SkBlitter* blitter, bool forceRLE, bool forceDAA) {
Yuqian Lib49d7b02017-11-06 16:21:06 -0500671 if (origClip.isEmpty()) {
Yuqian Lic8f2d192017-11-06 19:55:25 +0000672 return;
Yuqian Li12f322b2017-11-06 10:56:30 -0500673 }
674
Yuqian Lib49d7b02017-11-06 16:21:06 -0500675 const bool isInverse = path.isInverseFillType();
Mike Reed23e0cf22018-01-16 13:58:01 -0500676 SkIRect ir = safeRoundOut(path.getBounds());
Yuqian Lib49d7b02017-11-06 16:21:06 -0500677 if (ir.isEmpty()) {
678 if (isInverse) {
679 blitter->blitRegion(origClip);
680 }
681 return;
682 }
683
684 // If the intersection of the path bounds and the clip bounds
685 // will overflow 32767 when << by SHIFT, we can't supersample,
686 // so draw without antialiasing.
687 SkIRect clippedIR;
688 if (isInverse) {
689 // If the path is an inverse fill, it's going to fill the entire
690 // clip, and we care whether the entire clip exceeds our limits.
691 clippedIR = origClip.getBounds();
692 } else {
693 if (!clippedIR.intersect(ir, origClip.getBounds())) {
694 return;
695 }
696 }
697 if (rect_overflows_short_shift(clippedIR, SHIFT)) {
698 SkScan::FillPath(path, origClip, blitter);
699 return;
700 }
701
702 // Our antialiasing can't handle a clip larger than 32767, so we restrict
703 // the clip to that limit here. (the runs[] uses int16_t for its index).
704 //
705 // A more general solution (one that could also eliminate the need to
706 // disable aa based on ir bounds (see overflows_short_shift) would be
707 // to tile the clip/target...
708 SkRegion tmpClipStorage;
709 const SkRegion* clipRgn = &origClip;
710 {
711 static const int32_t kMaxClipCoord = 32767;
712 const SkIRect& bounds = origClip.getBounds();
713 if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) {
714 SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord };
715 tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op);
716 clipRgn = &tmpClipStorage;
717 }
718 }
719 // for here down, use clipRgn, not origClip
720
721 SkScanClipper clipper(blitter, clipRgn, ir);
722
723 if (clipper.getBlitter() == nullptr) { // clipped out
724 if (isInverse) {
725 blitter->blitRegion(*clipRgn);
726 }
727 return;
728 }
729
730 SkASSERT(clipper.getClipRect() == nullptr ||
731 *clipper.getClipRect() == clipRgn->getBounds());
732
733 // now use the (possibly wrapped) blitter
734 blitter = clipper.getBlitter();
735
736 if (isInverse) {
737 sk_blit_above(blitter, ir, *clipRgn);
738 }
739
Yuqian Li57899c72017-11-27 12:01:49 -0500740 if (forceDAA || ShouldUseDAA(path)) {
Yuqian Lif4848822018-01-08 13:40:45 -0500741 SkScan::DAAFillPath(path, blitter, ir, clipRgn->getBounds(), forceRLE);
Yuqian Lib49d7b02017-11-06 16:21:06 -0500742 } else if (ShouldUseAAA(path)) {
743 // Do not use AAA if path is too complicated:
744 // there won't be any speedup or significant visual improvement.
Yuqian Lif4848822018-01-08 13:40:45 -0500745 SkScan::AAAFillPath(path, blitter, ir, clipRgn->getBounds(), forceRLE);
Yuqian Lib49d7b02017-11-06 16:21:06 -0500746 } else {
Yuqian Lif4848822018-01-08 13:40:45 -0500747 SkScan::SAAFillPath(path, blitter, ir, clipRgn->getBounds(), forceRLE);
Yuqian Lib49d7b02017-11-06 16:21:06 -0500748 }
749
750 if (isInverse) {
751 sk_blit_below(blitter, ir, *clipRgn);
752 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753}
reed@google.com1ba71372011-10-12 20:42:05 +0000754
755///////////////////////////////////////////////////////////////////////////////
756
757#include "SkRasterClip.h"
758
Mike Reed1fe0bcc2018-01-22 16:49:49 -0500759void SkScan::FillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter* blitter) {
760 if (clip.isEmpty() || !path.isFinite()) {
reed@google.com1ba71372011-10-12 20:42:05 +0000761 return;
762 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000763
reed@google.com1ba71372011-10-12 20:42:05 +0000764 if (clip.isBW()) {
765 FillPath(path, clip.bwRgn(), blitter);
766 } else {
767 SkRegion tmp;
768 SkAAClipBlitter aaBlitter;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000769
reed@google.com1ba71372011-10-12 20:42:05 +0000770 tmp.setRect(clip.getBounds());
771 aaBlitter.init(blitter, &clip.aaRgn());
772 SkScan::FillPath(path, tmp, &aaBlitter);
773 }
774}
775
776void SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
Yuqian Li57899c72017-11-27 12:01:49 -0500777 SkBlitter* blitter, bool forceDAA) {
Mike Reed1fe0bcc2018-01-22 16:49:49 -0500778 if (clip.isEmpty() || !path.isFinite()) {
reed@google.com1ba71372011-10-12 20:42:05 +0000779 return;
780 }
781
782 if (clip.isBW()) {
Yuqian Li57899c72017-11-27 12:01:49 -0500783 AntiFillPath(path, clip.bwRgn(), blitter, false, forceDAA);
reed@google.com1ba71372011-10-12 20:42:05 +0000784 } else {
785 SkRegion tmp;
786 SkAAClipBlitter aaBlitter;
787
788 tmp.setRect(clip.getBounds());
789 aaBlitter.init(blitter, &clip.aaRgn());
Yuqian Li57899c72017-11-27 12:01:49 -0500790 AntiFillPath(path, tmp, &aaBlitter, true, forceDAA); // SkAAClipBlitter can blitMask, why forceRLE?
reed@google.com1ba71372011-10-12 20:42:05 +0000791 }
792}