Chromium Code Reviews| Index: src/core/SkScan_AAAPath.cpp |
| diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp |
| index 147c24c3feafd5013e85a547354e2e463a023a29..1a3b1ed222ab0cd56592d5086e4e93dbf5275a6f 100644 |
| --- a/src/core/SkScan_AAAPath.cpp |
| +++ b/src/core/SkScan_AAAPath.cpp |
| @@ -273,6 +273,19 @@ public: |
| int getWidth() override; |
| + // This should only be called when forceRLE = true which implies that SkAAClip |
| + // is calling us. |
| + // SkAAClip requires that we blit in scan-line order so we have to flush |
| + // for each row in order. Without this, we may have the first row unflushed, |
| + // then blit the 2nd and the 3rd row with full alpha (so we won't flush the first row); |
| + // finally when we blit the fourth row, we trigger the first row to flush, and this |
| + // would cause SkAAClip to crash. |
| + inline void flush_if_y_changed(SkFixed y, SkFixed nextY) { |
| + if ((y >> 16) != (nextY >> 16)) { |
|
caryclark
2016/10/20 16:58:14
maybe overly wordy, but a macro like SkFixedFloorT
liyuqian
2016/10/20 17:19:50
Thanks, done.
|
| + this->flush(); |
| + } |
| + } |
| + |
| private: |
| SkBlitter* fRealBlitter; |
| @@ -721,10 +734,6 @@ static inline void blit_trapezoid_row(AdditiveBlitter* blitter, int y, |
| SkFixed joinLeft = SkFixedCeilToFixed(ll); |
| SkFixed joinRite = SkFixedFloorToFixed(ur); |
| if (joinLeft <= joinRite) { // There's a rect from joinLeft to joinRite that we can blit |
| - if (joinLeft < joinRite) { |
| - blit_full_alpha(blitter, y, joinLeft >> 16, (joinRite - joinLeft) >> 16, fullAlpha, |
| - maskRow, isUsingMask); |
| - } |
| if (ul < joinLeft) { |
| int len = SkFixedCeilToInt(joinLeft - ul); |
| if (len == 1) { |
| @@ -741,6 +750,12 @@ static inline void blit_trapezoid_row(AdditiveBlitter* blitter, int y, |
| fullAlpha, maskRow, isUsingMask); |
| } |
| } |
| + // SkAAClip requires that we blit from left to right. |
| + // Hence we must blit [ul, joinLeft] before blitting [joinLeft, joinRite] |
| + if (joinLeft < joinRite) { |
| + blit_full_alpha(blitter, y, joinLeft >> 16, (joinRite - joinLeft) >> 16, fullAlpha, |
| + maskRow, isUsingMask); |
| + } |
| if (lr > joinRite) { |
| int len = SkFixedCeilToInt(lr - joinRite); |
| if (len == 1) { |
| @@ -880,7 +895,7 @@ static inline bool isSmoothEnough(SkAnalyticEdge* leftE, SkAnalyticEdge* riteE, |
| static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitter* blitter, |
| int start_y, int stop_y, SkFixed leftBound, SkFixed riteBound, |
| - bool isUsingMask) { |
| + bool isUsingMask, bool forceRLE) { |
| validate_sort((SkAnalyticEdge*)prevHead->fNext); |
| SkAnalyticEdge* leftE = (SkAnalyticEdge*) prevHead->fNext; |
| @@ -961,24 +976,27 @@ static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitt |
| } |
| if (fullRite >= fullLeft) { |
| - // Blit all full-height rows from fullTop to fullBot |
| - if (fullBot > fullTop) { |
| - blitter->getRealBlitter()->blitAntiRect(fullLeft - 1, fullTop, |
| - fullRite - fullLeft, fullBot - fullTop, |
| - f2a(partialLeft), f2a(partialRite)); |
| - } |
| - |
| if (partialTop > 0) { // blit first partial row |
| if (partialLeft > 0) { |
| blitter->blitAntiH(fullLeft - 1, fullTop - 1, |
| f2a(SkFixedMul_lowprec(partialTop, partialLeft))); |
| } |
| + blitter->blitAntiH(fullLeft, fullTop - 1, fullRite - fullLeft, |
| + f2a(partialTop)); |
| if (partialRite > 0) { |
| blitter->blitAntiH(fullRite, fullTop - 1, |
| f2a(SkFixedMul_lowprec(partialTop, partialRite))); |
| } |
| - blitter->blitAntiH(fullLeft, fullTop - 1, fullRite - fullLeft, |
| - f2a(partialTop)); |
| + if (forceRLE) { |
| + ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, y + partialTop); |
| + } |
| + } |
| + |
| + // Blit all full-height rows from fullTop to fullBot |
| + if (fullBot > fullTop) { |
| + blitter->getRealBlitter()->blitAntiRect(fullLeft - 1, fullTop, |
| + fullRite - fullLeft, fullBot - fullTop, |
| + f2a(partialLeft), f2a(partialRite)); |
| } |
| if (partialBot > 0) { // blit last partial row |
| @@ -986,25 +1004,28 @@ static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitt |
| blitter->blitAntiH(fullLeft - 1, fullBot, |
| f2a(SkFixedMul_lowprec(partialBot, partialLeft))); |
| } |
| + blitter->blitAntiH(fullLeft, fullBot, fullRite - fullLeft, f2a(partialBot)); |
| if (partialRite > 0) { |
| blitter->blitAntiH(fullRite, fullBot, |
| f2a(SkFixedMul_lowprec(partialBot, partialRite))); |
| } |
| - blitter->blitAntiH(fullLeft, fullBot, fullRite - fullLeft, f2a(partialBot)); |
| } |
| } else { // left and rite are within the same pixel |
| if (partialTop > 0) { |
| blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop - 1, 1, |
| f2a(SkFixedMul_lowprec(partialTop, rite - left))); |
| - } |
| - if (partialBot > 0) { |
| - blitter->getRealBlitter()->blitV(fullLeft - 1, fullBot, 1, |
| - f2a(SkFixedMul_lowprec(partialBot, rite - left))); |
| + if (forceRLE) { |
| + ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, y + partialTop); |
| + } |
| } |
| if (fullBot >= fullTop) { |
| blitter->getRealBlitter()->blitV(fullLeft - 1, fullTop, fullBot - fullTop, |
| f2a(rite - left)); |
| } |
| + if (partialBot > 0) { |
| + blitter->getRealBlitter()->blitV(fullLeft - 1, fullBot, 1, |
| + f2a(SkFixedMul_lowprec(partialBot, rite - left))); |
| + } |
| } |
| y = local_bot_fixed; |
| @@ -1048,6 +1069,9 @@ static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitt |
| blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, |
| nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY, |
| getPartialAlpha(0xFF, dY), maskRow, isUsingMask); |
| + if (forceRLE) { |
| + ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY); |
| + } |
| left = nextLeft; rite = nextRite; y = nextY; |
| } |
| @@ -1060,6 +1084,9 @@ static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitt |
| blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, |
| nextLeft & kSnapMask, nextRite & kSnapMask, |
| leftE->fDY, riteE->fDY, 0xFF, maskRow, isUsingMask); |
| + if (forceRLE) { |
| + ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, nextY); |
| + } |
| left = nextLeft; rite = nextRite; y = nextY; |
| } |
| } |
| @@ -1072,11 +1099,15 @@ static inline void aaa_walk_convex_edges(SkAnalyticEdge* prevHead, AdditiveBlitt |
| SkASSERT(dY <= SK_Fixed1); |
| // Smooth jumping to integer y may make the last nextLeft/nextRite out of bound. |
| // Take them back into the bound here. |
| - SkFixed nextLeft = SkTMax(left + SkFixedMul_lowprec(dLeft, dY), leftBound); |
| - SkFixed nextRite = SkTMin(rite + SkFixedMul_lowprec(dRite, dY), riteBound); |
| + // Note that we substract kSnapHalf later so we have to add them to leftBound/riteBound |
| + SkFixed nextLeft = SkTMax(left + SkFixedMul_lowprec(dLeft, dY), leftBound + kSnapHalf); |
| + SkFixed nextRite = SkTMin(rite + SkFixedMul_lowprec(dRite, dY), riteBound + kSnapHalf); |
| blit_trapezoid_row(blitter, y >> 16, left & kSnapMask, rite & kSnapMask, |
| nextLeft & kSnapMask, nextRite & kSnapMask, leftE->fDY, riteE->fDY, |
| getPartialAlpha(0xFF, dY), maskRow, isUsingMask); |
| + if (forceRLE) { |
| + ((RunBasedAdditiveBlitter*)blitter)->flush_if_y_changed(y, local_bot_fixed); |
| + } |
| left = nextLeft; rite = nextRite; y = local_bot_fixed; |
| left -= kSnapHalf; rite -= kSnapHalf; |
| } |
| @@ -1094,7 +1125,8 @@ END_WALK: |
| } |
| void SkScan::aaa_fill_path(const SkPath& path, const SkIRect* clipRect, AdditiveBlitter* blitter, |
| - int start_y, int stop_y, const SkRegion& clipRgn, bool isUsingMask) { |
| + int start_y, int stop_y, const SkRegion& clipRgn, bool isUsingMask, |
| + bool forceRLE) { // forceRLE implies that SkAAClip is calling us |
| SkASSERT(blitter); |
| if (path.isInverseFillType() || !path.isConvex()) { |
| @@ -1170,7 +1202,8 @@ void SkScan::aaa_fill_path(const SkPath& path, const SkIRect* clipRect, Additive |
| if (!path.isInverseFillType() && path.isConvex()) { |
| SkASSERT(count >= 2); // convex walker does not handle missing right edges |
| aaa_walk_convex_edges(&headEdge, blitter, start_y, stop_y, |
| - rect.fLeft << 16, rect.fRight << 16, isUsingMask); |
| + rect.fLeft << 16, rect.fRight << 16, isUsingMask, |
| + forceRLE); |
| } else { |
| SkFAIL("Concave AAA is not yet implemented!"); |
| } |
| @@ -1178,7 +1211,8 @@ void SkScan::aaa_fill_path(const SkPath& path, const SkIRect* clipRect, Additive |
| /////////////////////////////////////////////////////////////////////////////// |
| -void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter) { |
| +void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter, |
| + bool forceRLE) { |
| if (origClip.isEmpty()) { |
| return; |
| } |
| @@ -1244,12 +1278,14 @@ void SkScan::AAAFillPath(const SkPath& path, const SkRegion& origClip, SkBlitter |
| SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop); |
| - if (MaskAdditiveBlitter::canHandleRect(ir) && !isInverse) { |
| + if (MaskAdditiveBlitter::canHandleRect(ir) && !isInverse && !forceRLE) { |
| MaskAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); |
| - aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRgn, true); |
| + aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRgn, true, |
| + forceRLE); |
| } else { |
| RunBasedAdditiveBlitter additiveBlitter(blitter, ir, *clipRgn, isInverse); |
| - aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRgn, false); |
| + aaa_fill_path(path, clipRect, &additiveBlitter, ir.fTop, ir.fBottom, *clipRgn, false, |
| + forceRLE); |
| } |
| if (isInverse) { |