Blur refactoring

https://codereview.chromium.org/21835004/



git-svn-id: http://skia.googlecode.com/svn/trunk/src@10936 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/animator/SkDrawEmboss.cpp b/animator/SkDrawEmboss.cpp
index 5eed370..a0084eb 100644
--- a/animator/SkDrawEmboss.cpp
+++ b/animator/SkDrawEmboss.cpp
@@ -12,22 +12,23 @@
 #if SK_USE_CONDENSED_INFO == 0
 
 const SkMemberInfo SkDrawEmboss::fInfo[] = {
-    SK_MEMBER(ambient, Float),
-    SK_MEMBER_ARRAY(direction, Float),
-    SK_MEMBER(radius, Float),
-    SK_MEMBER(specular, Float)
+    SK_MEMBER(fAmbient, Float),
+    SK_MEMBER_ARRAY(fDirection, Float),
+    SK_MEMBER(fSigma, Float),
+    SK_MEMBER(fSpecular, Float)
 };
 
 #endif
 
 DEFINE_GET_MEMBER(SkDrawEmboss);
 
-SkDrawEmboss::SkDrawEmboss() : radius(-1) {
-    direction.setCount(3);
+SkDrawEmboss::SkDrawEmboss() : fSigma(-1) {
+    fDirection.setCount(3);
 }
 
 SkMaskFilter* SkDrawEmboss::getMaskFilter() {
-    if (radius < 0 || direction.count() !=3)
+    if (fSigma < 0 || fDirection.count() !=3)
         return NULL;
-    return SkBlurMaskFilter::CreateEmboss(direction.begin(), ambient, specular, radius);
+    return SkBlurMaskFilter::CreateEmboss(fSigma, fDirection.begin(), 
+                                          fAmbient, fSpecular);
 }
diff --git a/animator/SkDrawEmboss.h b/animator/SkDrawEmboss.h
index 6e61997..7ffd3ef 100644
--- a/animator/SkDrawEmboss.h
+++ b/animator/SkDrawEmboss.h
@@ -15,10 +15,14 @@
 class SkDrawEmboss : public SkDrawMaskFilter {
     DECLARE_DRAW_MEMBER_INFO(Emboss);
     SkDrawEmboss();
-    virtual SkMaskFilter* getMaskFilter();
+    virtual SkMaskFilter* getMaskFilter() SK_OVERRIDE;
 protected:
-    SkTDScalarArray direction;
-    SkScalar radius, ambient, specular;
+    SkTDScalarArray fDirection;
+    SkScalar        fSigma;
+    SkScalar        fAmbient;
+    SkScalar        fSpecular;
+
+    typedef SkDrawMaskFilter INHERITED;
 };
 
 #endif // SkDrawEmboss_DEFINED
diff --git a/core/SkPicture.cpp b/core/SkPicture.cpp
index 097e0ea..c94641b 100644
--- a/core/SkPicture.cpp
+++ b/core/SkPicture.cpp
@@ -275,6 +275,7 @@
     }
     if (PICTURE_VERSION != info.fVersion
 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
+        // V13 is backwards compatible with V12
         && PRIOR_PICTURE_VERSION != info.fVersion  // TODO: remove when .skps regenerated
 #endif
         ) {
diff --git a/effects/SkBlurDrawLooper.cpp b/effects/SkBlurDrawLooper.cpp
index 9585214..fb0153c 100644
--- a/effects/SkBlurDrawLooper.cpp
+++ b/effects/SkBlurDrawLooper.cpp
@@ -6,6 +6,7 @@
  * found in the LICENSE file.
  */
 #include "SkBlurDrawLooper.h"
+#include "SkBlurMask.h"     // just for SkBlurMask::ConvertRadiusToSigma
 #include "SkBlurMaskFilter.h"
 #include "SkCanvas.h"
 #include "SkColorFilter.h"
@@ -16,11 +17,25 @@
 #include "SkStringUtils.h"
 
 SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
-                                   SkColor color, uint32_t flags)
-    : fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags), fState(kDone) {
+                                   SkColor color, uint32_t flags) {
+    this->init(SkBlurMask::ConvertRadiusToSigma(radius), dx, dy, color, flags);
+}
+
+SkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma, 
+                                   SkScalar dx, SkScalar dy, uint32_t flags) {
+    this->init(sigma, dx, dy, color, flags);
+}
+
+void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy,
+                            SkColor color, uint32_t flags) {
+    fDx = dx;
+    fDy = dy;
+    fBlurColor = color;
+    fBlurFlags = flags;
+    fState = kDone;
 
     SkASSERT(flags <= kAll_BlurFlag);
-    if (radius > 0) {
+    if (sigma > 0) {
         uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ?
             SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
             SkBlurMaskFilter::kNone_BlurFlag;
@@ -29,8 +44,8 @@
             SkBlurMaskFilter::kHighQuality_BlurFlag :
             SkBlurMaskFilter::kNone_BlurFlag;
 
-        fBlur = SkBlurMaskFilter::Create(radius,
-                                         SkBlurMaskFilter::kNormal_BlurStyle,
+        fBlur = SkBlurMaskFilter::Create(SkBlurMaskFilter::kNormal_BlurStyle,
+                                         sigma,
                                          blurFlags);
     } else {
         fBlur = NULL;
diff --git a/effects/SkBlurMask.cpp b/effects/SkBlurMask.cpp
index c946c5e..a8ae1d3 100644
--- a/effects/SkBlurMask.cpp
+++ b/effects/SkBlurMask.cpp
@@ -12,7 +12,19 @@
 #include "SkTemplates.h"
 #include "SkEndian.h"
 
-const SkScalar SkBlurMask::kBlurRadiusFudgeFactor = SkFloatToScalar(.57735f);
+
+SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar 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 = SkFloatToScalar(0.57735f);
+
+    return radius ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
 
 #define UNROLL_SEPARABLE_LOOPS
 
@@ -473,24 +485,40 @@
 
 bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
                       SkScalar radius, Style style, Quality quality,
-                      SkIPoint* margin)
-{
+                      SkIPoint* margin) {
+    return SkBlurMask::BoxBlur(dst, src, 
+                               SkBlurMask::ConvertRadiusToSigma(radius),
+                               style, quality, margin);
+}
+
+bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src,
+                         SkScalar sigma, Style style, Quality quality,
+                         SkIPoint* margin) {
 
     if (src.fFormat != SkMask::kA8_Format) {
         return false;
     }
 
     // Force high quality off for small radii (performance)
-    if (radius < SkIntToScalar(3)) {
+    if (sigma <= SkIntToScalar(2)) {
         quality = kLow_Quality;
     }
 
+    SkScalar passRadius;
+    if (kHigh_Quality == quality) {
+        // For the high quality path the 3 pass box blur kernel width is
+        // 6*rad+1 while the full Gaussian width is 6*sigma.
+        passRadius = sigma - (1/6.0f);
+    } else {
+        // For the low quality path we only attempt to cover 3*sigma of the 
+        // Gaussian blur area (1.5*sigma on each side). The single pass box 
+        // blur's kernel size is 2*rad+1.
+        passRadius = 1.5f*sigma - 0.5f;
+    }
+
     // highQuality: use three box blur passes as a cheap way
     // to approximate a Gaussian blur
     int passCount = (kHigh_Quality == quality) ? 3 : 1;
-    SkScalar passRadius = (kHigh_Quality == quality) ?
-                          SkScalarMul( radius, kBlurRadiusFudgeFactor):
-                          radius;
 
     int rx = SkScalarCeil(passRadius);
     int outerWeight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255);
@@ -510,7 +538,7 @@
         margin->set(padx, pady);
     }
     dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
-        src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
+                     src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
 
     dst->fRowBytes = dst->fBounds.width();
     dst->fFormat = SkMask::kA8_Format;
@@ -651,13 +679,6 @@
     return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
 }
 
-// Compute the size of the array allocated for the profile.
-
-static int compute_profile_size(SkScalar radius) {
-    return SkScalarRoundToInt(radius * 3);
-
-}
-
 /*  compute_profile allocates and fills in an array of floating
     point values between 0 and 255 for the profile signature of
     a blurred half-plane with the given blur radius.  Since we're
@@ -669,13 +690,13 @@
     memory returned in profile_out.
 */
 
-static void compute_profile(SkScalar radius, unsigned int **profile_out) {
-    int size = compute_profile_size(radius);
+static void compute_profile(SkScalar sigma, unsigned int **profile_out) {
+    int size = SkScalarCeilToInt(6*sigma);
 
     int center = size >> 1;
     unsigned int *profile = SkNEW_ARRAY(unsigned int, size);
 
-    float invr = 1.f/radius;
+    float invr = 1.f/(2*sigma);
 
     profile[0] = 255;
     for (int x = 1 ; x < size ; ++x) {
@@ -705,16 +726,17 @@
 }
 
 bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
-                          SkScalar provided_radius, Style style,
+                          SkScalar radius, Style style,
                           SkIPoint *margin, SkMask::CreateMode createMode) {
-    int profile_size;
+    return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius),
+                                dst, src, 
+                                style, margin, createMode);
+}
 
-    float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor));
-
-    // adjust blur radius to match interpretation from boxfilter code
-    radius = (radius + .5f) * 2.f;
-
-    profile_size = compute_profile_size(radius);
+bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, 
+                          const SkRect &src, Style style,
+                          SkIPoint *margin, SkMask::CreateMode createMode) {
+    int profile_size = SkScalarCeilToInt(6*sigma);
 
     int pad = profile_size/2;
     if (margin) {
@@ -745,7 +767,7 @@
     }
     unsigned int *profile = NULL;
 
-    compute_profile(radius, &profile);
+    compute_profile(sigma, &profile);
     SkAutoTDeleteArray<unsigned int> ada(profile);
 
     size_t dstSize = dst->computeImageSize();
@@ -775,8 +797,8 @@
         if (profile_size <= sw) {
             horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w);
         } else {
-            float span = float(sw)/radius;
-            float giX = 1.5f - (x+.5f)/radius;
+            float span = float(sw)/(2*sigma);
+            float giX = 1.5f - (x+.5f)/(2*sigma);
             horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span)));
         }
     }
@@ -786,8 +808,8 @@
         if (profile_size <= sh) {
             profile_y = profile_lookup(profile, y, dstHeight, h);
         } else {
-            float span = float(sh)/radius;
-            float giY = 1.5f - (y+.5f)/radius;
+            float span = float(sh)/(2*sigma);
+            float giY = 1.5f - (y+.5f)/(2*sigma);
             profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegral(giY + span)));
         }
 
@@ -834,22 +856,24 @@
     return true;
 }
 
+bool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar radius,
+                                 Style style, SkIPoint* margin) {
+    return BlurGroundTruth(ConvertRadiusToSigma(radius), dst, src, style, margin);
+}
 // The "simple" blur is a direct implementation of separable convolution with a discrete
 // gaussian kernel.  It's "ground truth" in a sense; too slow to be used, but very
 // useful for correctness comparisons.
 
-bool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar provided_radius,
-                            Style style, SkIPoint* margin) {
+bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src,
+                                 Style style, SkIPoint* margin) {
 
     if (src.fFormat != SkMask::kA8_Format) {
         return false;
     }
 
-    float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor));
-    float stddev = SkScalarToFloat(radius) /2.0f;
-    float variance = stddev * stddev;
+    float variance = sigma * sigma;
 
-    int windowSize = SkScalarCeil(stddev*4);
+    int windowSize = SkScalarCeil(sigma*4);
     // round window size up to nearest odd number
     windowSize |= 1;
 
diff --git a/effects/SkBlurMask.h b/effects/SkBlurMask.h
index 36d7800..f49cd12 100644
--- a/effects/SkBlurMask.h
+++ b/effects/SkBlurMask.h
@@ -29,27 +29,37 @@
         kHigh_Quality   //!< three pass box blur (similar to gaussian)
     };
 
-    static bool BlurRect(SkMask *dst, const SkRect &src,
-                         SkScalar radius, Style style,
+    static bool BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src,
+                         Style style,
                          SkIPoint *margin = NULL,
-                         SkMask::CreateMode createMode=SkMask::kComputeBoundsAndRenderImage_CreateMode);
-    static bool Blur(SkMask* dst, const SkMask& src,
-                     SkScalar radius, Style style, Quality quality,
-                     SkIPoint* margin = NULL);
+                         SkMask::CreateMode createMode =
+                                                SkMask::kComputeBoundsAndRenderImage_CreateMode);
+    static bool BoxBlur(SkMask* dst, const SkMask& src,
+                        SkScalar sigma, Style style, Quality quality,
+                        SkIPoint* margin = NULL);
 
     // the "ground truth" blur does a gaussian convolution; it's slow
     // but useful for comparison purposes.
+    static bool BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src,
+                                Style style,
+                                SkIPoint* margin = NULL);
 
+    // DEPRECATED - radius-based
+    static bool BlurRect(SkMask *dst, const SkRect &src,
+                         SkScalar radius, Style style,
+                         SkIPoint *margin = NULL,
+                         SkMask::CreateMode createMode = 
+                                                SkMask::kComputeBoundsAndRenderImage_CreateMode);
+    // DEPRECATED - radius-based
+    static bool Blur(SkMask* dst, const SkMask& src,
+                     SkScalar radius, Style style, Quality quality,
+                     SkIPoint* margin = NULL);
+    // DEPRECATED - radius-based
     static bool BlurGroundTruth(SkMask* dst, const SkMask& src,
-                           SkScalar provided_radius, Style style,
-                           SkIPoint* margin = NULL);
+                                SkScalar radius, Style style,
+                                SkIPoint* margin = NULL);
 
-    // scale factor for the blur radius to match the behavior of the all existing blur
-    // code (both on the CPU and the GPU).  This magic constant is  1/sqrt(3).
-    // TODO: get rid of this fudge factor and move any required fudging up into
-    // the calling library
-    static const SkScalar kBlurRadiusFudgeFactor;
-
+    static SkScalar ConvertRadiusToSigma(SkScalar radius);
 };
 
 #endif
diff --git a/effects/SkBlurMaskFilter.cpp b/effects/SkBlurMaskFilter.cpp
index b54c330..8833358 100644
--- a/effects/SkBlurMaskFilter.cpp
+++ b/effects/SkBlurMaskFilter.cpp
@@ -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,24 +323,7 @@
 
 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
                                              SkRect* dst) const {
-    SkScalar gpuPad, rasterPad;
-
-    {
-        // 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);
+    SkScalar pad = 3.0f * fSigma;
 
     dst->set(src.fLeft  - pad, src.fTop    - pad,
              src.fRight + pad, src.fBottom + pad);
@@ -359,16 +331,27 @@
 
 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);
-
-    float sigma = SkScalarToFloat(xformedRadius) * kBLUR_SIGMA_SCALE;
+    SkScalar xformedSigma = this->computeXformedSigma(context->getMatrix());
+    SkASSERT(xformedSigma > 0);
 
     // 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] = {
diff --git a/effects/SkEmbossMaskFilter.cpp b/effects/SkEmbossMaskFilter.cpp
index 391cba5..315b8cb 100644
--- a/effects/SkEmbossMaskFilter.cpp
+++ b/effects/SkEmbossMaskFilter.cpp
@@ -26,6 +26,12 @@
 SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
                                              SkScalar ambient, SkScalar specular,
                                              SkScalar blurRadius) {
+    return SkBlurMaskFilter::CreateEmboss(SkBlurMask::ConvertRadiusToSigma(blurRadius),
+                                          direction, ambient, specular);
+}
+
+SkMaskFilter* SkBlurMaskFilter::CreateEmboss(SkScalar blurSigma, const SkScalar direction[3],
+                                             SkScalar ambient, SkScalar specular) {
     if (direction == NULL) {
         return NULL;
     }
@@ -42,7 +48,7 @@
     light.fAmbient = SkToU8(am);
     light.fSpecular = SkToU8(sp);
 
-    return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
+    return SkNEW_ARGS(SkEmbossMaskFilter, (blurSigma, light));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -56,27 +62,34 @@
     }
 }
 
-SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
-        : fLight(light), fBlurRadius(blurRadius) {
+SkEmbossMaskFilter::SkEmbossMaskFilter(SkScalar blurSigma, const Light& light)
+        : fBlurSigma(blurSigma), fLight(light) {
     normalize(fLight.fDirection);
 }
 
+SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
+        : fLight(light) {
+    normalize(fLight.fDirection);
+
+    fBlurSigma = SkBlurMask::ConvertRadiusToSigma(blurRadius);
+}
+
 SkMask::Format SkEmbossMaskFilter::getFormat() const {
     return SkMask::k3D_Format;
 }
 
 bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
-                            const SkMatrix& matrix, SkIPoint* margin) const {
-    SkScalar radius = matrix.mapRadius(fBlurRadius);
+                                    const SkMatrix& matrix, SkIPoint* margin) const {
+    SkScalar sigma = matrix.mapRadius(fBlurSigma);
 
-    if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style,
-                          SkBlurMask::kLow_Quality)) {
+    if (!SkBlurMask::BoxBlur(dst, src, sigma, SkBlurMask::kInner_Style,
+                             SkBlurMask::kLow_Quality)) {
         return false;
     }
 
     dst->fFormat = SkMask::k3D_Format;
     if (margin) {
-        margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
+        margin->set(SkScalarCeil(3*sigma), SkScalarCeil(3*sigma));
     }
 
     if (src.fImage == NULL) {
@@ -121,7 +134,18 @@
     SkASSERT(buffer.getArrayCount() == sizeof(Light));
     buffer.readByteArray(&fLight);
     SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
-    fBlurRadius = buffer.readScalar();
+    fBlurSigma = 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 (fBlurSigma > 0) {
+        fBlurSigma = SkBlurMask::ConvertRadiusToSigma(fBlurSigma);
+    } else {
+        fBlurSigma = -fBlurSigma;
+    }
+#endif
 }
 
 void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
@@ -130,7 +154,7 @@
     Light tmpLight = fLight;
     tmpLight.fPad = 0;    // for the font-cache lookup to be clean
     buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
-    buffer.writeScalar(fBlurRadius);
+    buffer.writeScalar(-fBlurSigma);
 }
 
 #ifdef SK_DEVELOPER
@@ -148,8 +172,8 @@
     str->appendf("ambient: %d specular: %d ",
         fLight.fAmbient, fLight.fSpecular);
 
-    str->append("blurRadius: ");
-    str->appendScalar(fBlurRadius);
+    str->append("blurSigma: ");
+    str->appendScalar(fBlurSigma);
     str->append(")");
 }
 #endif