OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2016 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 |
| 8 #include "SkAntiRun.h" |
| 9 #include "SkBlitter.h" |
| 10 #include "SkEdge.h" |
| 11 #include "SkEdgeBuilder.h" |
| 12 #include "SkGeometry.h" |
| 13 #include "SkPath.h" |
| 14 #include "SkQuadClipper.h" |
| 15 #include "SkRasterClip.h" |
| 16 #include "SkRegion.h" |
| 17 #include "SkScan.h" |
| 18 #include "SkScanPriv.h" |
| 19 #include "SkTemplates.h" |
| 20 #include "SkTSort.h" |
| 21 #include "SkUtils.h" |
| 22 |
| 23 /////////////////////////////////////////////////////////////////////////////// |
| 24 |
| 25 /* |
| 26 |
| 27 The following is a high-level overview of our analytic anti-aliasing |
| 28 algorithm. We consider a path as a collection of line segments, as |
| 29 quadratic/cubic curves are converted to small line segments. Without loss of |
| 30 generality, let's assume that the draw region is [0, W] x [0, H]. |
| 31 |
| 32 Our algorithm is based on horizontal scan lines (y = c_i) as the previous |
| 33 sampling-based algorithm did. However, our algorithm uses non-equal-spaced |
| 34 scan lines, while the previous method always uses equal-spaced scan lines, |
| 35 such as (y = 1/2 + 0, 1/2 + 1, 1/2 + 2, ...) in the previous non-AA algorithm, |
| 36 and (y = 1/8 + 1/4, 1/8 + 2/4, 1/8 + 3/4, ...) in the previous |
| 37 16-supersampling AA algorithm. |
| 38 |
| 39 Our algorithm contains scan lines y = c_i for c_i that is either: |
| 40 |
| 41 1. an integer between [0, H] |
| 42 |
| 43 2. the y value of a line segment endpoint |
| 44 |
| 45 3. the y value of an intersection of two line segments |
| 46 |
| 47 For two consecutive scan lines y = c_i, y = c_{i+1}, we analytically computes |
| 48 the coverage of this horizontal strip of our path on each pixel. This can be |
| 49 done very efficiently because the strip of our path now only consists of |
| 50 trapezoids whose top and bottom edges are y = c_i, y = c_{i+1} (this includes |
| 51 rectangles and triangles as special cases). |
| 52 |
| 53 We now describe how the coverage of single pixel is computed against such a |
| 54 trapezoid. That coverage is essentially the intersection area of a rectangle |
| 55 (e.g., [0, 1] x [c_i, c_{i+1}]) and our trapezoid. However, that intersection |
| 56 could be complicated, as shown in the example region A below: |
| 57 |
| 58 +-----------\----+ |
| 59 | \ C| |
| 60 | \ | |
| 61 \ \ | |
| 62 |\ A \| |
| 63 | \ \ |
| 64 | \ | |
| 65 | B \ | |
| 66 +----\-----------+ |
| 67 |
| 68 However, we don't have to compute the area of A directly. Instead, we can |
| 69 compute the excluded area, which are B and C, quite easily, because they're |
| 70 just triangles. In fact, we can prove that an excluded region (take B as an |
| 71 example) is either itself a simple trapezoid (including rectangles, triangles, |
| 72 and empty regions), or its opposite (the opposite of B is A + C) is a simple |
| 73 trapezoid. In any case, we can compute its area efficiently. |
| 74 |
| 75 In summary, our algorithm has a higher quality because it generates ground- |
| 76 truth coverages analytically. It is also faster because it has much fewer |
| 77 unnessasary horizontal scan lines. For example, given a triangle path, the |
| 78 number of scan lines in our algorithm is only about 3 + H while the |
| 79 16-supersampling algorithm has about 4H scan lines. |
| 80 |
| 81 */ |
| 82 |
| 83 /////////////////////////////////////////////////////////////////////////////// |
| 84 |
| 85 class AdditiveBlitter : public SkBlitter { |
| 86 public: |
| 87 AdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& c
lip, |
| 88 bool isInverse); |
| 89 ~AdditiveBlitter(); |
| 90 |
| 91 SkBlitter* getRealBlitter(); |
| 92 |
| 93 void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]
) override; |
| 94 void blitAntiH(int x, int y, const SkAlpha alpha); |
| 95 void blitAntiH(int x, int y, int width, const SkAlpha alpha); |
| 96 |
| 97 void blitV(int x, int y, int height, SkAlpha alpha) override { |
| 98 SkDEBUGFAIL("Please call real blitter's blitV instead."); |
| 99 } |
| 100 |
| 101 void blitH(int x, int y, int width) override { |
| 102 SkDEBUGFAIL("Please call real blitter's blitH instead."); |
| 103 } |
| 104 |
| 105 void blitRect(int x, int y, int width, int height) override { |
| 106 SkDEBUGFAIL("Please call real blitter's blitRect instead."); |
| 107 } |
| 108 |
| 109 void blitAntiRect(int x, int y, int width, int height, |
| 110 SkAlpha leftAlpha, SkAlpha rightAlpha) override { |
| 111 SkDEBUGFAIL("Please call real blitter's blitAntiRect instead."); |
| 112 } |
| 113 |
| 114 int getWidth(); |
| 115 |
| 116 private: |
| 117 SkBlitter* fRealBlitter; |
| 118 |
| 119 /// Current y coordinate |
| 120 int fCurrY; |
| 121 /// Widest row of region to be blitted |
| 122 int fWidth; |
| 123 /// Leftmost x coordinate in any row |
| 124 int fLeft; |
| 125 /// Initial y coordinate (top of bounds). |
| 126 int fTop; |
| 127 |
| 128 // The next three variables are used to track a circular buffer that |
| 129 // contains the values used in SkAlphaRuns. These variables should only |
| 130 // ever be updated in advanceRuns(), and fRuns should always point to |
| 131 // a valid SkAlphaRuns... |
| 132 int fRunsToBuffer; |
| 133 void* fRunsBuffer; |
| 134 int fCurrentRun; |
| 135 SkAlphaRuns fRuns; |
| 136 |
| 137 int fOffsetX; |
| 138 |
| 139 inline bool check(int x, int width) { |
| 140 #ifdef SK_DEBUG |
| 141 if (x < 0 || x + width > fWidth) { |
| 142 SkDebugf("Ignore x = %d, width = %d\n", x, width); |
| 143 } |
| 144 #endif |
| 145 return (x >= 0 && x + width <= fWidth); |
| 146 } |
| 147 |
| 148 // extra one to store the zero at the end |
| 149 inline int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof
(int16_t); } |
| 150 |
| 151 // This function updates the fRuns variable to point to the next buffer spac
e |
| 152 // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrent
Run |
| 153 // and resets fRuns to point to an empty scanline. |
| 154 inline void advanceRuns() { |
| 155 const size_t kRunsSz = this->getRunsSz(); |
| 156 fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer; |
| 157 fRuns.fRuns = reinterpret_cast<int16_t*>( |
| 158 reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz); |
| 159 fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1); |
| 160 fRuns.reset(fWidth); |
| 161 } |
| 162 |
| 163 inline SkAlpha snapAlpha(SkAlpha alpha) { |
| 164 return alpha > 247 ? 0xFF : alpha < 8 ? 0 : alpha; |
| 165 } |
| 166 |
| 167 inline void flush() { |
| 168 if (fCurrY >= fTop) { |
| 169 SkASSERT(fCurrentRun < fRunsToBuffer); |
| 170 for (int x = 0; fRuns.fRuns[x]; x += fRuns.fRuns[x]) { |
| 171 // It seems that blitting 255 or 0 is much faster than blitting
254 or 1 |
| 172 fRuns.fAlpha[x] = snapAlpha(fRuns.fAlpha[x]); |
| 173 } |
| 174 if (!fRuns.empty()) { |
| 175 // SkDEBUGCODE(fRuns.dump();) |
| 176 fRealBlitter->blitAntiH(fLeft, fCurrY, fRuns.fAlpha, fRuns.fRuns
); |
| 177 this->advanceRuns(); |
| 178 fOffsetX = 0; |
| 179 } |
| 180 fCurrY = fTop - 1; |
| 181 } |
| 182 } |
| 183 |
| 184 inline void checkY(int y) { |
| 185 if (y != fCurrY) { |
| 186 this->flush(); |
| 187 fCurrY = y; |
| 188 } |
| 189 } |
| 190 }; |
| 191 |
| 192 AdditiveBlitter::AdditiveBlitter(SkBlitter* realBlitter, const SkIRect& ir, cons
t SkRegion& clip, |
| 193 bool isInverse) { |
| 194 fRealBlitter = realBlitter; |
| 195 |
| 196 SkIRect sectBounds; |
| 197 if (isInverse) { |
| 198 // We use the clip bounds instead of the ir, since we may be asked to |
| 199 //draw outside of the rect when we're a inverse filltype |
| 200 sectBounds = clip.getBounds(); |
| 201 } else { |
| 202 if (!sectBounds.intersect(ir, clip.getBounds())) { |
| 203 sectBounds.setEmpty(); |
| 204 } |
| 205 } |
| 206 |
| 207 const int left = sectBounds.left(); |
| 208 const int right = sectBounds.right(); |
| 209 |
| 210 fLeft = left; |
| 211 fWidth = right - left; |
| 212 fTop = sectBounds.top(); |
| 213 fCurrY = fTop - 1; |
| 214 |
| 215 fRunsToBuffer = realBlitter->requestRowsPreserved(); |
| 216 fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz()
); |
| 217 fCurrentRun = -1; |
| 218 |
| 219 this->advanceRuns(); |
| 220 |
| 221 fOffsetX = 0; |
| 222 } |
| 223 |
| 224 AdditiveBlitter::~AdditiveBlitter() { |
| 225 this->flush(); |
| 226 } |
| 227 |
| 228 SkBlitter* AdditiveBlitter::getRealBlitter() { |
| 229 return fRealBlitter; |
| 230 } |
| 231 |
| 232 void AdditiveBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const i
nt16_t runs[]) { |
| 233 checkY(y); |
| 234 x -= fLeft; |
| 235 |
| 236 if (x < fOffsetX) { |
| 237 fOffsetX = 0; |
| 238 } |
| 239 |
| 240 for (int i=0; runs[i]; i += runs[i]) { |
| 241 if (check(x, runs[i])) { |
| 242 fOffsetX = fRuns.add(x, 0, runs[i], 0, antialias[i], fOffsetX); |
| 243 } |
| 244 x += runs[i]; |
| 245 } |
| 246 } |
| 247 |
| 248 void AdditiveBlitter::blitAntiH(int x, int y, const SkAlpha alpha) { |
| 249 checkY(y); |
| 250 x -= fLeft; |
| 251 |
| 252 if (x < fOffsetX) { |
| 253 fOffsetX = 0; |
| 254 } |
| 255 |
| 256 if (check(x, 1)) { |
| 257 fOffsetX = fRuns.add(x, 0, 1, 0, alpha, fOffsetX); |
| 258 } |
| 259 } |
| 260 |
| 261 void AdditiveBlitter::blitAntiH(int x, int y, int width, const SkAlpha alpha) { |
| 262 checkY(y); |
| 263 x -= fLeft; |
| 264 |
| 265 if (x < fOffsetX) { |
| 266 fOffsetX = 0; |
| 267 } |
| 268 |
| 269 if (check(x, width)) { |
| 270 fOffsetX = fRuns.add(x, 0, width, 0, alpha, fOffsetX); |
| 271 } |
| 272 } |
| 273 |
| 274 int AdditiveBlitter::getWidth() { return fWidth; } |
| 275 |
| 276 /////////////////////////////////////////////////////////////////////////////// |
| 277 |
| 278 // Return the alpha of a trapezoid whose height is 1 |
| 279 inline SkAlpha trapezoidToAlpha(SkFixed l1, SkFixed l2) { |
| 280 SkASSERT(l1 >= 0 && l2 >= 0); |
| 281 return ((l1 + l2) >> 9); |
| 282 } |
| 283 |
| 284 // Return the alpha of a right-angle triangle whose two right-angle edges are l1
, l2 |
| 285 inline SkAlpha triangleToAlpha(SkFixed l1, SkFixed l2) { |
| 286 SkASSERT(l1 >= 0 && l2 >= 0); |
| 287 // Since l1, l2 <= SK_Fixed1, we should be able to become more accurate in m
ultiplication |
| 288 return SkFixedMul_lowprec(l1, l2) >> 9; |
| 289 } |
| 290 |
| 291 inline SkAlpha getPartialAlpha(SkAlpha alpha, SkFixed partialHeight) { |
| 292 return (alpha * partialHeight) >> 16; |
| 293 } |
| 294 |
| 295 // Suppose that line (l1, y)-(r1, y+1) intersects with (l2, y)-(r2, y+1), |
| 296 // approximate (very coarsely) the x coordinate of the intersection. |
| 297 inline SkFixed approximateIntersection(SkFixed l1, SkFixed r1, SkFixed l2, SkFix
ed r2) { |
| 298 if (l1 > r1) { SkTSwap(l1, r1); } |
| 299 if (l2 > r2) { SkTSwap(l2, r2); } |
| 300 return (SkTMax(l1, l2) + SkTMin(r1, r2)) >> 1; |
| 301 } |
| 302 |
| 303 inline void computeAlphaAboveLine(SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed
dY, SkFixed rowHeight) { |
| 304 SkASSERT(l <= r); |
| 305 SkASSERT(l >> 16 == 0); |
| 306 int R = SkFixedCeilToInt(r); |
| 307 if (R == 0) { |
| 308 return; |
| 309 } else if (R == 1) { |
| 310 alphas[0] = getPartialAlpha(((R << 17) - l - r) >> 9, rowHeight); |
| 311 } else { |
| 312 SkFixed first = SK_Fixed1 - l; |
| 313 SkFixed last = r - ((R - 1) << 16); |
| 314 SkFixed alpha16 = SkFixedMul_lowprec(first, SkFixedMul_lowprec(first, dY
)) >> 1; |
| 315 for (int i = 0; i < R - 1; i++) { |
| 316 alphas[i] = alpha16 >> 8; |
| 317 alpha16 += dY; |
| 318 } |
| 319 alphas[R - 1] = getPartialAlpha(0xFF, rowHeight) - triangleToAlpha(last,
SkFixedMul_lowprec(last, dY)); |
| 320 } |
| 321 } |
| 322 |
| 323 inline void computeAlphaBelowLine(SkAlpha* alphas, SkFixed l, SkFixed r, SkFixed
dY, SkFixed rowHeight) { |
| 324 SkASSERT(l <= r); |
| 325 SkASSERT(l >> 16 == 0); |
| 326 int R = SkFixedCeilToInt(r); |
| 327 if (R == 0) { |
| 328 return; |
| 329 } else if (R == 1) { |
| 330 alphas[0] = getPartialAlpha(trapezoidToAlpha(l, r), rowHeight); |
| 331 } else { |
| 332 SkFixed first = SK_Fixed1 - l; |
| 333 SkFixed last = r - ((R - 1) << 16); |
| 334 SkFixed alpha16 = SkFixedMul_lowprec(last, SkFixedMul_lowprec(last, dY))
>> 1; |
| 335 for (int i = R - 1; i > 0; i--) { |
| 336 alphas[i] = alpha16 >> 8; |
| 337 alpha16 += dY; |
| 338 } |
| 339 alphas[0] = getPartialAlpha(0xFF, rowHeight) - triangleToAlpha(first, Sk
FixedMul_lowprec(first, dY)); |
| 340 } |
| 341 } |
| 342 |
| 343 // Blit antialiasing trapzoid (ul, y), (ur, y), (ll, y + rowHeight), (lr, y + ro
wHeight) |
| 344 // ul = upper left, ur = upper rite, ll = lower left, lr = lower rite |
| 345 // When rowHeight < SK_Fixed1, blit the partial row with that partial height. |
| 346 // lDY is the dY for the left edge (ul, y) - (ll, y + rowHeight), |
| 347 // and rDY is the dY for the right edge. |
| 348 // |
| 349 // NOTE! To increase performance, we use real blitter (without additive alphas) |
| 350 // if rowHeight = SK_Fixed1. Therefore, we'll lose information if there are |
| 351 // many thin vertical strips within the same pixel. |
| 352 void blit_aaa_trapzoid_row(AdditiveBlitter* blitter, int y, |
| 353 SkFixed ul, SkFixed ur, SkFixed ll, SkFixed lr, |
| 354 SkFixed lDY, SkFixed rDY, |
| 355 SkFixed rowHeight) { |
| 356 SkASSERT(lDY >= 0 && rDY >= 0); // We should only send in the absolte value |
| 357 |
| 358 if (ul > ur) { |
| 359 #ifdef SK_DEBUG |
| 360 SkDebugf("ul = %f > ur = %f!\n", SkFixedToFloat(ul), SkFixedToFloat(ur))
; |
| 361 #endif |
| 362 return; |
| 363 } |
| 364 |
| 365 // Edge crosses. Approximate it. This should only happend due to precision l
imit, |
| 366 // so the approximation could be very coarse. |
| 367 if (ll > lr) { |
| 368 #ifdef SK_DEBUG |
| 369 SkDebugf("approximate intersection: %d %f %f\n", y, |
| 370 SkFixedToFloat(ll), SkFixedToFloat(lr)); |
| 371 #endif |
| 372 ll = lr = approximateIntersection(ul, ll, ur, lr); |
| 373 } |
| 374 |
| 375 if (ul == ur && ll == lr) { |
| 376 return; // empty trapzoid |
| 377 } |
| 378 |
| 379 bool isFullRow = rowHeight == SK_Fixed1; |
| 380 SkAlpha fullAlpha = getPartialAlpha(0xFF, rowHeight); |
| 381 |
| 382 SkFixed joinLeft = SkFixedCeilToFixed(SkTMax(ul, ll)); |
| 383 SkFixed joinRite = SkFixedFloorToFixed(SkTMin(ur, lr)); |
| 384 if (joinLeft < joinRite) { |
| 385 // There's a strip from joinLeft to joinRite that we can blit at once |
| 386 blit_aaa_trapzoid_row(blitter, y, ul, joinLeft, ll, joinLeft, lDY, SK_Ma
xS32, rowHeight); |
| 387 if (isFullRow) { |
| 388 blitter->getRealBlitter()->blitH(joinLeft >> 16, y, (joinRite - join
Left) >> 16); |
| 389 } else { |
| 390 blitter->blitAntiH(joinLeft >> 16, y, (joinRite - joinLeft) >> 16, f
ullAlpha); |
| 391 } |
| 392 blit_aaa_trapzoid_row(blitter, y, joinRite, ur, joinRite, lr, SK_MaxS32,
rDY, rowHeight); |
| 393 return; |
| 394 } |
| 395 |
| 396 SkFixed left = SkTMin(ul, ll), rite = SkTMax(ur, lr); |
| 397 int L = SkFixedFloorToInt(left), R = SkFixedCeilToInt(rite); |
| 398 int len = R - L; |
| 399 |
| 400 #ifdef SK_DEBUG |
| 401 // SkDebugf("y = %d, len = %d\n", y, len); |
| 402 #endif |
| 403 |
| 404 if (len == 1) { // Most of the time, len is 1 so we accelerate it |
| 405 SkAlpha alpha = trapezoidToAlpha(ur - ul, lr - ll); |
| 406 if (isFullRow) { |
| 407 blitter->getRealBlitter()->blitV(L, y, 1, alpha); |
| 408 } else { |
| 409 blitter->blitAntiH(L, y, getPartialAlpha(alpha, rowHeight)); |
| 410 } |
| 411 return; |
| 412 } |
| 413 |
| 414 SkAutoSMalloc<1024> storage((len + 1) * (sizeof(SkAlpha) * 2 + sizeof(int16_
t))); |
| 415 SkAlpha* alphas = (SkAlpha*)storage.get(); |
| 416 SkAlpha* tempAlphas = alphas + len + 1; |
| 417 int16_t* runs = (int16_t*)(alphas + (len + 1) * 2); |
| 418 |
| 419 // We're going to use the left line ul-ll and the rite line ur-lr |
| 420 // to exclude the area that's not covered by the path. |
| 421 // Swapping (ul, ll) or (ur, lr) won't affect that exclusion |
| 422 // so we'll do that for simplicity. |
| 423 if (ul > ll) { SkTSwap(ul, ll); } |
| 424 if (ur > lr) { SkTSwap(ur, lr); } |
| 425 |
| 426 for (int i = 0; i < len; i++) { |
| 427 runs[i] = 1; |
| 428 alphas[i] = fullAlpha; |
| 429 } |
| 430 runs[len] = 0; |
| 431 |
| 432 if (ul == ll && ll == L << 16) { // the left edge is vertical integer |
| 433 computeAlphaBelowLine(alphas, ur - (L << 16), lr - (L << 16), rDY, rowHe
ight); |
| 434 } else if (ur == lr && lr == R << 16) { // the right edge is vertical intege
r |
| 435 computeAlphaAboveLine(alphas, ul - (L << 16), ll - (L << 16), lDY, rowHe
ight); |
| 436 } else { |
| 437 int uL = SkFixedFloorToInt(ul); |
| 438 int lL = SkFixedCeilToInt(ll); |
| 439 computeAlphaBelowLine(tempAlphas + uL - L, ul - (uL << 16), ll - (uL <<
16), |
| 440 lDY, rowHeight); |
| 441 for (int i = uL; i < lL; i++) { |
| 442 if (alphas[i - L] > tempAlphas[i - L]) { |
| 443 alphas[i - L] -= tempAlphas[i - L]; |
| 444 } else { |
| 445 alphas[i - L] = 0; |
| 446 } |
| 447 } |
| 448 |
| 449 int uR = SkFixedFloorToInt(ur); |
| 450 int lR = SkFixedCeilToInt(lr); |
| 451 computeAlphaAboveLine(tempAlphas + uR - L, ur - (uR << 16), lr - (uR <<
16), |
| 452 rDY, rowHeight); |
| 453 for (int i = uR; i < lR; i++) { |
| 454 if (alphas[i - L] > tempAlphas[i - L]) { |
| 455 alphas[i - L] -= tempAlphas[i - L]; |
| 456 } else { |
| 457 alphas[i - L] = 0; |
| 458 } |
| 459 } |
| 460 } |
| 461 |
| 462 if (isFullRow) { |
| 463 blitter->getRealBlitter()->blitAntiH(L, y, alphas, runs); |
| 464 } else { |
| 465 blitter->blitAntiH(L, y, alphas, runs); |
| 466 } |
| 467 } |
| 468 |
| 469 /////////////////////////////////////////////////////////////////////////////// |
| 470 |
| 471 static bool operator<(const SkAnalyticEdge& a, const SkAnalyticEdge& b) { |
| 472 int valuea = a.fUpperY; |
| 473 int valueb = b.fUpperY; |
| 474 |
| 475 if (valuea == valueb) { |
| 476 valuea = a.fX; |
| 477 valueb = b.fX; |
| 478 } |
| 479 |
| 480 if (valuea == valueb) { |
| 481 valuea = a.fDX; |
| 482 valueb = b.fDX; |
| 483 } |
| 484 |
| 485 return valuea < valueb; |
| 486 } |
| 487 |
| 488 static SkAnalyticEdge* sort_edges(SkAnalyticEdge* list[], int count, SkAnalyticE
dge** last) { |
| 489 SkTQSort(list, list + count - 1); |
| 490 |
| 491 // now make the edges linked in sorted order |
| 492 for (int i = 1; i < count; i++) { |
| 493 list[i - 1]->fNext = list[i]; |
| 494 list[i]->fPrev = list[i - 1]; |
| 495 } |
| 496 |
| 497 *last = list[count - 1]; |
| 498 return list[0]; |
| 499 } |
| 500 |
| 501 #ifdef SK_DEBUG |
| 502 static void validate_sort(const SkAnalyticEdge* edge) { |
| 503 SkFixed y = SkIntToFixed(-32768); |
| 504 |
| 505 while (edge->fUpperY != SK_MaxS32) { |
| 506 edge->validate(); |
| 507 SkASSERT(y <= edge->fUpperY); |
| 508 |
| 509 y = edge->fUpperY; |
| 510 edge = (SkAnalyticEdge*)edge->fNext; |
| 511 } |
| 512 } |
| 513 #else |
| 514 #define validate_sort(edge) |
| 515 #endif |
| 516 |
| 517 // return true if we're done with this edge |
| 518 static bool update_edge(SkAnalyticEdge* edge, SkFixed last_y) { |
| 519 if (last_y >= edge->fLowerY) { |
| 520 if (edge->fCurveCount < 0) { |
| 521 if (static_cast<SkAnalyticCubicEdge*>(edge)->updateCubic()) { |
| 522 return false; |
| 523 } |
| 524 } else if (edge->fCurveCount > 0) { |
| 525 if (static_cast<SkAnalyticQuadraticEdge*>(edge)->updateQuadratic())
{ |
| 526 return false; |
| 527 } |
| 528 } |
| 529 return true; |
| 530 } |
| 531 SkASSERT(false); |
| 532 return false; |
| 533 } |
| 534 |
| 535 void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitter* blitter, |
| 536 int start_y, int stop_y) { |
| 537 validate_sort((SkAnalyticEdge*)prevHead->fNext); |
| 538 |
| 539 SkAnalyticEdge* leftE = (SkAnalyticEdge*) prevHead->fNext; |
| 540 SkAnalyticEdge* riteE = (SkAnalyticEdge*) leftE->fNext; |
| 541 SkAnalyticEdge* currE = (SkAnalyticEdge*) riteE->fNext; |
| 542 |
| 543 SkFixed y = SkTMax(leftE->fUpperY, riteE->fUpperY); |
| 544 int local_top = SkFixedFloorToInt(y); |
| 545 SkASSERT(local_top >= start_y); |
| 546 |
| 547 #ifdef SK_DEBUG |
| 548 int frac_y_cnt = 0; |
| 549 int total_y_cnt = 0; |
| 550 #endif |
| 551 |
| 552 for (;;) { |
| 553 SkASSERT(SkFixedFloorToInt(leftE->fUpperY) <= stop_y); |
| 554 SkASSERT(SkFixedFloorToInt(riteE->fUpperY) <= stop_y); |
| 555 |
| 556 if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && |
| 557 leftE->fDX > riteE->fDX)) { |
| 558 SkTSwap(leftE, riteE); |
| 559 } |
| 560 |
| 561 SkFixed local_bot_fixed = SkMin32(leftE->fLowerY, riteE->fLowerY); |
| 562 local_bot_fixed = SkMin32(local_bot_fixed, SkIntToFixed(stop_y + 1)); |
| 563 |
| 564 SkFixed left = leftE->fX; |
| 565 SkFixed dLeft = leftE->fDX; |
| 566 SkFixed rite = riteE->fX; |
| 567 SkFixed dRite = riteE->fDX; |
| 568 // x may be out of range without snapping due to precision limit |
| 569 SkFixed snappedLeft = SkAnalyticEdge::snapX(left); |
| 570 SkFixed snappedRite = SkAnalyticEdge::snapX(rite); |
| 571 if (0 == (dLeft | dRite)) { |
| 572 int fullLeft = SkFixedCeilToInt(snappedLeft); |
| 573 int fullRite = SkFixedFloorToInt(snappedRite); |
| 574 SkFixed partialLeft = SkIntToFixed(fullLeft) - snappedLeft; |
| 575 SkFixed partialRite = snappedRite - SkIntToFixed(fullRite); |
| 576 int fullTop = SkFixedCeilToInt(y); |
| 577 int fullBot = SkFixedFloorToInt(local_bot_fixed); |
| 578 SkFixed partialTop = SkIntToFixed(fullTop) - y; |
| 579 SkFixed partialBot = local_bot_fixed - SkIntToFixed(fullBot); |
| 580 |
| 581 if (fullRite >= fullLeft) { |
| 582 // Blit all full-height rows from fullTop to fullBot |
| 583 blitter->getRealBlitter()->blitAntiRect(fullLeft - 1, fullTop, f
ullRite - fullLeft, |
| 584 fullBot - fullTop, |
| 585 partialLeft >> 8, partia
lRite >> 8); |
| 586 |
| 587 if (partialTop > 0) { // blit first partial row |
| 588 if (partialLeft > 0) { |
| 589 blitter->blitAntiH(fullLeft - 1, fullTop - 1, |
| 590 SkFixedMul_lowprec(partialTop, partia
lLeft) >> 8); |
| 591 } |
| 592 if (partialRite > 0) { |
| 593 blitter->blitAntiH(fullRite, fullTop - 1, |
| 594 SkFixedMul_lowprec(partialTop, partia
lRite) >> 8); |
| 595 } |
| 596 blitter->blitAntiH(fullLeft, fullTop - 1, fullRite - fullLef
t, partialTop >> 8); |
| 597 } |
| 598 |
| 599 if (partialBot > 0) { // blit last partial row |
| 600 if (partialLeft > 0) { |
| 601 blitter->blitAntiH(fullLeft - 1, fullBot, |
| 602 SkFixedMul_lowprec(partialBot, partia
lLeft) >> 8); |
| 603 } |
| 604 if (partialRite > 0) { |
| 605 blitter->blitAntiH(fullRite, fullBot, |
| 606 SkFixedMul_lowprec(partialBot, partia
lRite) >> 8); |
| 607 } |
| 608 blitter->blitAntiH(fullLeft, fullBot, fullRite - fullLeft, p
artialBot >> 8); |
| 609 } |
| 610 } else { |
| 611 if (partialTop > 0) { |
| 612 blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop - 1,
1, |
| 613 SkFixedMul_lowprec(partialTop, rite - left) >> 8); |
| 614 } |
| 615 if (partialBot > 0) { |
| 616 blitter->getRealBlitter()->blitV(fullLeft - 1, fullBot, 1, |
| 617 SkFixedMul_lowprec(partialBot, snappedRite - snapped
Left) >> 8); |
| 618 } |
| 619 if (fullBot >= fullTop) { |
| 620 blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop, full
Bot - fullTop, |
| 621 (snappedRite - snappedLeft) >> 8); |
| 622 } |
| 623 } |
| 624 |
| 625 y = local_bot_fixed; |
| 626 } else { |
| 627 do { |
| 628 #ifdef SK_DEBUG |
| 629 if ((y >> 16 << 16) != y) { |
| 630 frac_y_cnt++; |
| 631 SkDebugf("frac_y = %f\n", SkFixedToFloat(y)); |
| 632 } |
| 633 total_y_cnt++; |
| 634 #endif |
| 635 |
| 636 local_top = SkFixedFloorToInt(y); |
| 637 SkFixed nextY = SkIntToFixed(local_top + 1); |
| 638 nextY = SkTMin(nextY, local_bot_fixed); |
| 639 SkFixed dY = nextY - y; |
| 640 |
| 641 SkFixed nextLeft = left + dLeft; |
| 642 SkFixed nextRite = rite + dRite; |
| 643 |
| 644 if (dY != SK_Fixed1) { |
| 645 nextLeft = left + SkFixedMul_lowprec(dLeft, dY); |
| 646 nextRite = rite + SkFixedMul_lowprec(dRite, dY); |
| 647 } |
| 648 |
| 649 SkFixed snappedNextLeft = SkAnalyticEdge::snapX(nextLeft); |
| 650 SkFixed snappedNextRite = SkAnalyticEdge::snapX(nextRite); |
| 651 |
| 652 blit_aaa_trapzoid_row(blitter, local_top, snappedLeft, snappedRi
te, |
| 653 snappedNextLeft, snappedNextRite, |
| 654 leftE->fDY, riteE->fDY, nextY - y); |
| 655 |
| 656 left = nextLeft; |
| 657 rite = nextRite; |
| 658 snappedLeft = snappedNextLeft; |
| 659 snappedRite = snappedNextRite; |
| 660 y = nextY; |
| 661 } while (y < local_bot_fixed); |
| 662 } |
| 663 |
| 664 leftE->fX = left; |
| 665 riteE->fX = rite; |
| 666 |
| 667 while (leftE->fLowerY <= y) { |
| 668 if (update_edge(leftE, y)) { |
| 669 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { |
| 670 goto END_WALK; |
| 671 } |
| 672 leftE = currE; |
| 673 leftE->goY(y); |
| 674 currE = (SkAnalyticEdge*)currE->fNext; |
| 675 } |
| 676 } |
| 677 while (riteE->fLowerY <= y) { |
| 678 if (update_edge(riteE, y)) { |
| 679 if (SkFixedFloorToInt(currE->fUpperY) >= stop_y) { |
| 680 goto END_WALK; |
| 681 } |
| 682 riteE = currE; |
| 683 riteE->goY(y); |
| 684 currE = (SkAnalyticEdge*)currE->fNext; |
| 685 } |
| 686 } |
| 687 |
| 688 SkASSERT(leftE); |
| 689 SkASSERT(riteE); |
| 690 |
| 691 // check our bottom clip |
| 692 SkASSERT(y == local_bot_fixed); |
| 693 if (SkFixedFloorToInt(y) >= stop_y) { |
| 694 break; |
| 695 } |
| 696 } |
| 697 |
| 698 END_WALK: |
| 699 ; |
| 700 #ifdef SK_DEBUG |
| 701 SkDebugf("frac_y_cnt = %d, total_y_cnt = %d\n", frac_y_cnt, total_y_cnt); |
| 702 #endif |
| 703 } |
| 704 |
| 705 void SkScan::aaa_fill_path(const SkPath& path, const SkIRect* clipRect, Additive
Blitter* blitter, |
| 706 int start_y, int stop_y, const SkRegion& clipRgn) { |
| 707 SkASSERT(blitter); |
| 708 |
| 709 if (path.isInverseFillType() || !path.isConvex()) { |
| 710 // fall back to supersampling AA |
| 711 GlobalAAConfig::getInstance().fUseAnalyticAA = false; |
| 712 SkScan::AntiFillPath(path, clipRgn, blitter->getRealBlitter(), false); |
| 713 GlobalAAConfig::getInstance().fUseAnalyticAA = true; // turne analytic A
A back on |
| 714 return; |
| 715 } |
| 716 |
| 717 SkEdgeBuilder builder; |
| 718 |
| 719 // If we're convex, then we need both edges, even the right edge is past the
clip |
| 720 const bool canCullToTheRight = !path.isConvex(); |
| 721 |
| 722 SkASSERT(GlobalAAConfig::getInstance().fUseAnalyticAA); |
| 723 int count = builder.build(path, clipRect, 0, canCullToTheRight, true); |
| 724 SkASSERT(count >= 0); |
| 725 |
| 726 SkAnalyticEdge** list = (SkAnalyticEdge**)builder.analyticEdgeList(); |
| 727 |
| 728 if (0 == count) { |
| 729 if (path.isInverseFillType()) { |
| 730 /* |
| 731 * Since we are in inverse-fill, our caller has already drawn above |
| 732 * our top (start_y) and will draw below our bottom (stop_y). Thus |
| 733 * we need to restrict our drawing to the intersection of the clip |
| 734 * and those two limits. |
| 735 */ |
| 736 SkIRect rect = clipRgn.getBounds(); |
| 737 if (rect.fTop < start_y) { |
| 738 rect.fTop = start_y; |
| 739 } |
| 740 if (rect.fBottom > stop_y) { |
| 741 rect.fBottom = stop_y; |
| 742 } |
| 743 if (!rect.isEmpty()) { |
| 744 blitter->blitRect(rect.fLeft, rect.fTop, rect.width(), rect.heig
ht()); |
| 745 } |
| 746 } |
| 747 return; |
| 748 } |
| 749 |
| 750 SkAnalyticEdge headEdge, tailEdge, *last; |
| 751 // this returns the first and last edge after they're sorted into a dlink li
st |
| 752 SkAnalyticEdge* edge = sort_edges(list, count, &last); |
| 753 |
| 754 headEdge.fPrev = nullptr; |
| 755 headEdge.fNext = edge; |
| 756 headEdge.fUpperY = headEdge.fLowerY = SK_MinS32; |
| 757 headEdge.fX = SK_MinS32; |
| 758 headEdge.fDX = 0; |
| 759 headEdge.fDY = SK_MaxS32; |
| 760 headEdge.fUpperX = SK_MinS32; |
| 761 edge->fPrev = &headEdge; |
| 762 |
| 763 tailEdge.fPrev = last; |
| 764 tailEdge.fNext = nullptr; |
| 765 tailEdge.fUpperY = tailEdge.fLowerY = SK_MaxS32; |
| 766 headEdge.fX = SK_MaxS32; |
| 767 headEdge.fDX = 0; |
| 768 headEdge.fDY = SK_MaxS32; |
| 769 headEdge.fUpperX = SK_MaxS32; |
| 770 last->fNext = &tailEdge; |
| 771 |
| 772 // now edge is the head of the sorted linklist |
| 773 |
| 774 if (clipRect && start_y < clipRect->fTop) { |
| 775 start_y = clipRect->fTop; |
| 776 } |
| 777 if (clipRect && stop_y > clipRect->fBottom) { |
| 778 stop_y = clipRect->fBottom; |
| 779 } |
| 780 |
| 781 if (!path.isInverseFillType() && path.isConvex()) { |
| 782 SkASSERT(count >= 2); // convex walker does not handle missing right e
dges |
| 783 aaa_walk_convex_edges(&headEdge, blitter, start_y, stop_y); |
| 784 } else { |
| 785 SkFAIL("Concave AAA is not yet implemented!"); |
| 786 } |
| 787 } |
| 788 |
| 789 /////////////////////////////////////////////////////////////////////////////// |
| 790 |
| 791 void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter
* blitter) { |
| 792 if (origClip.isEmpty()) { |
| 793 return; |
| 794 } |
| 795 |
| 796 const bool isInverse = path.isInverseFillType(); |
| 797 SkIRect ir; |
| 798 path.getBounds().roundOut(&ir); |
| 799 if (ir.isEmpty()) { |
| 800 if (isInverse) { |
| 801 blitter->blitRegion(origClip); |
| 802 } |
| 803 return; |
| 804 } |
| 805 |
| 806 SkIRect clippedIR; |
| 807 if (isInverse) { |
| 808 // If the path is an inverse fill, it's going to fill the entire |
| 809 // clip, and we care whether the entire clip exceeds our limits. |
| 810 clippedIR = origClip.getBounds(); |
| 811 } else { |
| 812 if (!clippedIR.intersect(ir, origClip.getBounds())) { |
| 813 return; |
| 814 } |
| 815 } |
| 816 |
| 817 // Our antialiasing can't handle a clip larger than 32767, so we restrict |
| 818 // the clip to that limit here. (the runs[] uses int16_t for its index). |
| 819 // |
| 820 // A more general solution (one that could also eliminate the need to |
| 821 // disable aa based on ir bounds (see overflows_short_shift) would be |
| 822 // to tile the clip/target... |
| 823 SkRegion tmpClipStorage; |
| 824 const SkRegion* clipRgn = &origClip; |
| 825 { |
| 826 static const int32_t kMaxClipCoord = 32767; |
| 827 const SkIRect& bounds = origClip.getBounds(); |
| 828 if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) { |
| 829 SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord }; |
| 830 tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op); |
| 831 clipRgn = &tmpClipStorage; |
| 832 } |
| 833 } |
| 834 // for here down, use clipRgn, not origClip |
| 835 |
| 836 SkScanClipper clipper(blitter, clipRgn, ir); |
| 837 const SkIRect* clipRect = clipper.getClipRect(); |
| 838 |
| 839 if (clipper.getBlitter() == nullptr) { // clipped out |
| 840 if (isInverse) { |
| 841 blitter->blitRegion(*clipRgn); |
| 842 } |
| 843 return; |
| 844 } |
| 845 |
| 846 // now use the (possibly wrapped) blitter |
| 847 blitter = clipper.getBlitter(); |
| 848 |
| 849 if (isInverse) { |
| 850 sk_blit_above(blitter, ir, *clipRgn); |
| 851 } |
| 852 |
| 853 SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); |
| 854 |
| 855 AdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); |
| 856 aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRg
n); |
| 857 |
| 858 if (isInverse) { |
| 859 sk_blit_below(blitter, ir, *clipRgn); |
| 860 } |
| 861 } |
| 862 |
| 863 // This almost copies SkScan::AntiFillPath |
| 864 void SkScan::AAAFillPath(const SkPath& path, const SkRasterClip& clip, SkBlitter
* blitter) { |
| 865 if (clip.isEmpty()) { |
| 866 return; |
| 867 } |
| 868 |
| 869 if (clip.isBW()) { |
| 870 AAAFillPath(path, clip.bwRgn(), blitter); |
| 871 } else { |
| 872 SkRegion tmp; |
| 873 SkAAClipBlitter aaBlitter; |
| 874 |
| 875 tmp.setRect(clip.getBounds()); |
| 876 aaBlitter.init(blitter, &clip.aaRgn()); |
| 877 AAAFillPath(path, tmp, &aaBlitter); |
| 878 } |
| 879 } |
OLD | NEW |