Index: src/core/SkScan_AAAPath.cpp |
diff --git a/src/core/SkScan_AAAPath.cpp b/src/core/SkScan_AAAPath.cpp |
index 147c24c3feafd5013e85a547354e2e463a023a29..76348785280dba71606151148c74be41b8cb3fe1 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 (SkFixedFloorToInt(y) != SkFixedFloorToInt(nextY)) { |
+ 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,13 @@ 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, SkFixedFloorToInt(joinLeft), |
+ SkFixedFloorToInt(joinRite - joinLeft), |
+ fullAlpha, maskRow, isUsingMask); |
+ } |
if (lr > joinRite) { |
int len = SkFixedCeilToInt(lr - joinRite); |
if (len == 1) { |
@@ -880,7 +896,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 +977,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 +1005,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 +1070,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 +1085,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 +1100,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 +1126,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 +1203,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 +1212,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 +1279,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) { |