Index: src/effects/SkBlurMaskFilter.cpp |
=================================================================== |
--- src/effects/SkBlurMaskFilter.cpp (revision 10932) |
+++ src/effects/SkBlurMaskFilter.cpp (working copy) |
@@ -24,8 +24,7 @@ |
class SkBlurMaskFilterImpl : public SkMaskFilter { |
public: |
- SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle, |
- uint32_t flags); |
+ SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t flags); |
// overrides from SkMaskFilter |
virtual SkMask::Format getFormat() const SK_OVERRIDE; |
@@ -60,37 +59,26 @@ |
// To avoid unseemly allocation requests (esp. for finite platforms like |
// handset) we limit the radius so something manageable. (as opposed to |
// a request like 10,000) |
- static const SkScalar kMAX_BLUR_RADIUS; |
- // This constant approximates the scaling done in the software path's |
- // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). |
- // IMHO, it actually should be 1: we blur "less" than we should do |
- // according to the CSS and canvas specs, simply because Safari does the same. |
- // Firefox used to do the same too, until 4.0 where they fixed it. So at some |
- // point we should probably get rid of these scaling constants and rebaseline |
- // all the blur tests. |
- static const SkScalar kBLUR_SIGMA_SCALE; |
+ static const SkScalar kMAX_BLUR_SIGMA; |
- SkScalar fRadius; |
+ SkScalar fSigma; |
SkBlurMaskFilter::BlurStyle fBlurStyle; |
uint32_t fBlurFlags; |
SkBlurMaskFilterImpl(SkFlattenableReadBuffer&); |
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; |
-#if SK_SUPPORT_GPU |
- SkScalar computeXformedRadius(const SkMatrix& ctm) const { |
+ |
+ SkScalar computeXformedSigma(const SkMatrix& ctm) const { |
bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag); |
- SkScalar xformedRadius = ignoreTransform ? fRadius |
- : ctm.mapRadius(fRadius); |
- return SkMinScalar(xformedRadius, kMAX_BLUR_RADIUS); |
+ SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma); |
+ return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA); |
} |
-#endif |
typedef SkMaskFilter INHERITED; |
}; |
-const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_RADIUS = SkIntToScalar(128); |
-const SkScalar SkBlurMaskFilterImpl::kBLUR_SIGMA_SCALE = SkFloatToScalar(0.6f); |
+const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128); |
SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius, |
SkBlurMaskFilter::BlurStyle style, |
@@ -101,15 +89,29 @@ |
return NULL; |
} |
- return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags)); |
+ SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius); |
+ |
+ return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags)); |
} |
+SkMaskFilter* SkBlurMaskFilter::Create(SkBlurMaskFilter::BlurStyle style, |
+ SkScalar sigma, |
+ uint32_t flags) { |
+ // use !(sigma > 0) instead of sigma <= 0 to reject NaN values |
+ if (!(sigma > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount |
+ || flags > SkBlurMaskFilter::kAll_BlurFlag) { |
+ return NULL; |
+ } |
+ |
+ return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags)); |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
-SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius, |
+SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, |
SkBlurMaskFilter::BlurStyle style, |
uint32_t flags) |
- : fRadius(radius), fBlurStyle(style), fBlurFlags(flags) { |
+ : fSigma(sigma), fBlurStyle(style), fBlurFlags(flags) { |
#if 0 |
fGamma = NULL; |
if (gammaScale) { |
@@ -120,7 +122,7 @@ |
SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale); |
} |
#endif |
- SkASSERT(radius >= 0); |
+ SkASSERT(fSigma >= 0); |
SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount); |
SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag); |
} |
@@ -132,35 +134,22 @@ |
bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, |
const SkMatrix& matrix, |
SkIPoint* margin) const{ |
- SkScalar radius; |
- if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) { |
- radius = fRadius; |
- } else { |
- radius = matrix.mapRadius(fRadius); |
- } |
+ SkScalar sigma = this->computeXformedSigma(matrix); |
- radius = SkMinScalar(radius, kMAX_BLUR_RADIUS); |
SkBlurMask::Quality blurQuality = |
(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ? |
SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality; |
- return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle, |
- blurQuality, margin); |
+ return SkBlurMask::BoxBlur(dst, src, sigma, (SkBlurMask::Style)fBlurStyle, |
+ blurQuality, margin); |
} |
bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r, |
const SkMatrix& matrix, |
SkIPoint* margin, SkMask::CreateMode createMode) const{ |
- SkScalar radius; |
- if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) { |
- radius = fRadius; |
- } else { |
- radius = matrix.mapRadius(fRadius); |
- } |
+ SkScalar sigma = computeXformedSigma(matrix); |
- radius = SkMinScalar(radius, kMAX_BLUR_RADIUS); |
- |
- return SkBlurMask::BlurRect(dst, r, radius, (SkBlurMask::Style)fBlurStyle, |
+ return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle, |
margin, createMode); |
} |
@@ -334,41 +323,35 @@ |
void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, |
SkRect* dst) const { |
- SkScalar gpuPad, rasterPad; |
+ SkScalar pad = 3.0f * fSigma; |
- { |
- // GPU path |
- SkScalar sigma = SkScalarMul(fRadius, kBLUR_SIGMA_SCALE); |
- gpuPad = sigma * 3.0f; |
- } |
- |
- { |
- // raster path |
- SkScalar radius = SkScalarMul(fRadius, SkBlurMask::kBlurRadiusFudgeFactor); |
- |
- radius = (radius + .5f) * 2.f; |
- |
- rasterPad = SkIntToScalar(SkScalarRoundToInt(radius * 3)/2); |
- } |
- |
- SkScalar pad = SkMaxScalar(gpuPad, rasterPad); |
- |
dst->set(src.fLeft - pad, src.fTop - pad, |
src.fRight + pad, src.fBottom + pad); |
} |
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer) |
: SkMaskFilter(buffer) { |
- fRadius = buffer.readScalar(); |
+ fSigma = buffer.readScalar(); |
+#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO |
+ // Fixing this must be done in two stages. When the skps are recaptured in V13, |
+ // remove the ConvertRadiusToSigma but retain the absolute value. |
+ // At the same time, switch the code in flatten to write a positive value. |
+ // When the skps are captured in V14 the absolute value can be removed. |
+ if (fSigma > 0) { |
+ fSigma = SkBlurMask::ConvertRadiusToSigma(fSigma); |
+ } else { |
+ fSigma = -fSigma; |
+ } |
+#endif |
fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt(); |
fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag; |
- SkASSERT(fRadius >= 0); |
+ SkASSERT(fSigma >= 0); |
SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount); |
} |
void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const { |
this->INHERITED::flatten(buffer); |
- buffer.writeScalar(fRadius); |
+ buffer.writeScalar(-fSigma); |
buffer.writeInt(fBlurStyle); |
buffer.writeUInt(fBlurFlags); |
} |
@@ -379,17 +362,17 @@ |
const SkIRect& clipBounds, |
const SkMatrix& ctm, |
SkRect* maskRect) const { |
- SkScalar xformedRadius = this->computeXformedRadius(ctm); |
- if (xformedRadius <= 0) { |
+ SkScalar xformedSigma = this->computeXformedSigma(ctm); |
+ if (xformedSigma <= 0) { |
return false; |
} |
- static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64); |
- static const SkScalar kMIN_GPU_BLUR_RADIUS = SkIntToScalar(32); |
+ static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64); |
+ static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32); |
if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE && |
srcBounds.height() <= kMIN_GPU_BLUR_SIZE && |
- xformedRadius <= kMIN_GPU_BLUR_RADIUS) { |
+ xformedSigma <= kMIN_GPU_BLUR_SIGMA) { |
// We prefer to blur small rect with small radius via CPU. |
return false; |
} |
@@ -399,7 +382,7 @@ |
return true; |
} |
- float sigma3 = 3 * SkScalarToFloat(xformedRadius) * kBLUR_SIGMA_SCALE; |
+ float sigma3 = 3 * SkScalarToFloat(xformedSigma); |
SkRect clipRect = SkRect::MakeFromIRect(clipBounds); |
SkRect srcRect(srcBounds); |
@@ -422,16 +405,14 @@ |
GrContext::AutoWideOpenIdentityDraw awo(context, NULL); |
- SkScalar xformedRadius = this->computeXformedRadius(context->getMatrix()); |
- SkASSERT(xformedRadius > 0); |
+ SkScalar xformedSigma = this->computeXformedSigma(context->getMatrix()); |
+ SkASSERT(xformedSigma > 0); |
- float sigma = SkScalarToFloat(xformedRadius) * kBLUR_SIGMA_SCALE; |
- |
// If we're doing a normal blur, we can clobber the pathTexture in the |
// gaussianBlur. Otherwise, we need to save it for later compositing. |
bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle); |
*result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc, |
- clipRect, false, sigma, sigma); |
+ clipRect, false, xformedSigma, xformedSigma); |
if (NULL == *result) { |
return false; |
} |
@@ -469,8 +450,8 @@ |
void SkBlurMaskFilterImpl::toString(SkString* str) const { |
str->append("SkBlurMaskFilterImpl: ("); |
- str->append("radius: "); |
- str->appendScalar(fRadius); |
+ str->append("sigma: "); |
+ str->appendScalar(fSigma); |
str->append(" "); |
static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = { |