Blur refactoring

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



git-svn-id: http://skia.googlecode.com/svn/trunk@10936 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/BlurRectBench.cpp b/bench/BlurRectBench.cpp
index 3d0a896..1f40780 100644
--- a/bench/BlurRectBench.cpp
+++ b/bench/BlurRectBench.cpp
@@ -141,8 +141,8 @@
         SkMask mask;
         mask.fImage = NULL;
         SkBlurMask::Blur(&mask, fSrcMask, this->radius(),
-                                  SkBlurMask::kNormal_Style,
-                                  SkBlurMask::kHigh_Quality);
+                         SkBlurMask::kNormal_Style,
+                         SkBlurMask::kHigh_Quality);
         SkMask::FreeImage(mask.fImage);
     }
 private:
diff --git a/gm/blurrect.cpp b/gm/blurrect.cpp
index 5a18d16..2cb962f 100644
--- a/gm/blurrect.cpp
+++ b/gm/blurrect.cpp
@@ -71,12 +71,12 @@
       SkAlpha   fAlpha;
 public:
     BlurRectGM(const char name[], PaintProc pproc, U8CPU alpha,
-               SkBlurMaskFilter::BlurStyle bs) :
-        fMaskFilter(SkBlurMaskFilter::Create(STROKE_WIDTH/2, bs,
-                    SkBlurMaskFilter::kHighQuality_BlurFlag))
-                  , fName(name)
-                  , fPProc(pproc)
-                  , fAlpha(SkToU8(alpha)) {
+               SkBlurMaskFilter::BlurStyle bs) 
+               : fMaskFilter(SkBlurMaskFilter::Create(STROKE_WIDTH/2, bs,
+                             SkBlurMaskFilter::kHighQuality_BlurFlag))
+               , fName(name)
+               , fPProc(pproc)
+               , fAlpha(SkToU8(alpha)) {
         fName.appendf("_%s", gBlurStyle2Name[bs]);
     }
 
@@ -208,13 +208,12 @@
 
 class BlurRectFastGM: public BlurRectCompareGM {
 public:
-    BlurRectFastGM(const char name[], unsigned int rect_width,
-                   unsigned int rect_height, float blur_radius,
+    BlurRectFastGM(const char name[], unsigned int rectWidth,
+                   unsigned int rectHeight, float blurRadius,
                    SkBlurMask::Style style) :
-        INHERITED(name, rect_width, rect_height, blur_radius, style)
-        {
-
+        INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
         }
+
 protected:
     virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
         return SkBlurMask::BlurRect(m, r, this->radius(), this->style());
diff --git a/gm/blurs.cpp b/gm/blurs.cpp
index 22804c7..988fbe2 100644
--- a/gm/blurs.cpp
+++ b/gm/blurs.cpp
@@ -60,31 +60,29 @@
             for (size_t i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
                 if (gRecs[i].fStyle != NONE) {
                     SkMaskFilter* mf = SkBlurMaskFilter::Create(
-                            SkIntToScalar(20), gRecs[i].fStyle, flags
-                    );
+                            SkIntToScalar(20), gRecs[i].fStyle, flags);
                     paint.setMaskFilter(mf)->unref();
                 } else {
                     paint.setMaskFilter(NULL);
                 }
-                canvas->drawCircle(SkIntToScalar(200 + gRecs[i].fCx*100)
-                                   , SkIntToScalar(200 + gRecs[i].fCy*100)
-                                   , SkIntToScalar(50)
-                                   , paint);
+                canvas->drawCircle(SkIntToScalar(200 + gRecs[i].fCx*100),
+                                   SkIntToScalar(200 + gRecs[i].fCy*100),
+                                   SkIntToScalar(50),
+                                   paint);
             }
             // draw text
             {
                 SkMaskFilter* mf = SkBlurMaskFilter::Create(
-                        SkIntToScalar(4)
-                        , SkBlurMaskFilter::kNormal_BlurStyle
-                        , flags
-                );
+                        SkIntToScalar(4),
+                        SkBlurMaskFilter::kNormal_BlurStyle,
+                        flags);
                 paint.setMaskFilter(mf)->unref();
                 SkScalar x = SkIntToScalar(70);
                 SkScalar y = SkIntToScalar(400);
                 paint.setColor(SK_ColorBLACK);
                 canvas->drawText("Hamburgefons Style", 18, x, y, paint);
-                canvas->drawText("Hamburgefons Style", 18
-                                 , x, y + SkIntToScalar(50), paint);
+                canvas->drawText("Hamburgefons Style", 18,
+                                 x, y + SkIntToScalar(50), paint);
                 paint.setMaskFilter(NULL);
                 paint.setColor(SK_ColorWHITE);
                 x -= SkIntToScalar(2);
diff --git a/gm/circles.cpp b/gm/circles.cpp
index 4513934..1fe114a 100644
--- a/gm/circles.cpp
+++ b/gm/circles.cpp
@@ -83,7 +83,7 @@
                                   SkIntToScalar(10), 0xFF0000FF,
                                   SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                                   SkBlurDrawLooper::kOverrideColor_BlurFlag |
-                                  SkBlurDrawLooper::kHighQuality_BlurFlag );
+                                  SkBlurDrawLooper::kHighQuality_BlurFlag);
         SkAutoUnref aurL0(shadowLooper);
         p.setLooper(shadowLooper);
         fPaints.push_back(p);
diff --git a/gm/rects.cpp b/gm/rects.cpp
index eee92b3..f2fa989 100644
--- a/gm/rects.cpp
+++ b/gm/rects.cpp
@@ -88,7 +88,7 @@
                                       SkIntToScalar(10), SK_ColorWHITE,
                                       SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                                       SkBlurDrawLooper::kOverrideColor_BlurFlag |
-                                      SkBlurDrawLooper::kHighQuality_BlurFlag );
+                                      SkBlurDrawLooper::kHighQuality_BlurFlag);
             SkAutoUnref aurL0(shadowLooper);
             p.setLooper(shadowLooper);
             fPaints.push_back(p);
diff --git a/gm/shadows.cpp b/gm/shadows.cpp
index 2fb1615..d7a1254 100644
--- a/gm/shadows.cpp
+++ b/gm/shadows.cpp
@@ -50,33 +50,33 @@
                               SkIntToScalar(10), 0xFF0000FF,
                               SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                               SkBlurDrawLooper::kOverrideColor_BlurFlag |
-                              SkBlurDrawLooper::kHighQuality_BlurFlag );
+                              SkBlurDrawLooper::kHighQuality_BlurFlag);
     SkAutoUnref aurL0(shadowLoopers[0]);
     shadowLoopers[1] =
         new SkBlurDrawLooper (SkIntToScalar(10), SkIntToScalar(5),
                               SkIntToScalar(10), 0xFF0000FF,
                               SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
-                              SkBlurDrawLooper::kOverrideColor_BlurFlag );
+                              SkBlurDrawLooper::kOverrideColor_BlurFlag);
     SkAutoUnref aurL1(shadowLoopers[1]);
     shadowLoopers[2] =
         new SkBlurDrawLooper (SkIntToScalar(5), SkIntToScalar(5),
                               SkIntToScalar(10), 0xFF000000,
                               SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
-                              SkBlurDrawLooper::kHighQuality_BlurFlag  );
+                              SkBlurDrawLooper::kHighQuality_BlurFlag);
     SkAutoUnref aurL2(shadowLoopers[2]);
     shadowLoopers[3] =
         new SkBlurDrawLooper (SkIntToScalar(5), SkIntToScalar(-5),
                               SkIntToScalar(-10), 0x7FFF0000,
                               SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                               SkBlurDrawLooper::kOverrideColor_BlurFlag |
-                              SkBlurDrawLooper::kHighQuality_BlurFlag  );
+                              SkBlurDrawLooper::kHighQuality_BlurFlag);
     SkAutoUnref aurL3(shadowLoopers[3]);
     shadowLoopers[4] =
         new SkBlurDrawLooper (SkIntToScalar(0), SkIntToScalar(5),
                               SkIntToScalar(5), 0xFF000000,
                               SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
                               SkBlurDrawLooper::kOverrideColor_BlurFlag |
-                              SkBlurDrawLooper::kHighQuality_BlurFlag  );
+                              SkBlurDrawLooper::kHighQuality_BlurFlag);
     SkAutoUnref aurL4(shadowLoopers[4]);
 
     static const struct {
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 95034c2..39fd7c0 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -209,6 +209,7 @@
     // V11: modify how readBitmap and writeBitmap store their info.
     // V12: add conics to SkPath, use new SkPathRef flattening
     // V13: add flag to drawBitmapRectToRect
+    //      parameterize blurs by sigma rather than radius
 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
     static const uint32_t PRIOR_PICTURE_VERSION = 12;  // TODO: remove when .skps regenerated
 #endif
diff --git a/include/effects/SkBlurDrawLooper.h b/include/effects/SkBlurDrawLooper.h
index e968857..8e0c2dd 100644
--- a/include/effects/SkBlurDrawLooper.h
+++ b/include/effects/SkBlurDrawLooper.h
@@ -35,6 +35,10 @@
         kAll_BlurFlag               = 0x07
     };
 
+    SkBlurDrawLooper(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy,
+                     uint32_t flags = kNone_BlurFlag);
+
+    // DEPRECATED - radius-based
     SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy, SkColor color,
                      uint32_t flags = kNone_BlurFlag);
     virtual ~SkBlurDrawLooper();
@@ -64,6 +68,8 @@
     };
     State   fState;
 
+    void init(SkScalar sigma, SkScalar dx, SkScalar dy, SkColor color, uint32_t flags);
+
     typedef SkDrawLooper INHERITED;
 };
 
diff --git a/include/effects/SkBlurMaskFilter.h b/include/effects/SkBlurMaskFilter.h
index 2ab321a..81c0ceb 100644
--- a/include/effects/SkBlurMaskFilter.h
+++ b/include/effects/SkBlurMaskFilter.h
@@ -33,27 +33,39 @@
         kAll_BlurFlag = 0x03
     };
 
-    /** Create a blur maskfilter.
-        @param radius   The radius to extend the blur from the original mask. Must be > 0.
-        @param style    The BlurStyle to use
-        @param flags    Flags to use - defaults to none
-        @return The new blur maskfilter
-    */
+    /**
+     *  DEPRECATED - radius-based
+     */
     static SkMaskFilter* Create(SkScalar radius, BlurStyle style,
                                 uint32_t flags = kNone_BlurFlag);
 
+    /** Create a blur maskfilter.
+        @param style    The BlurStyle to use
+        @param sigma    Standard deviation of the Gaussian blur to apply. Must be > 0.
+        @param flags    Flags to use - defaults to none
+        @return The new blur maskfilter
+    */
+    static SkMaskFilter* Create(BlurStyle style, SkScalar sigma,
+                                uint32_t flags = kNone_BlurFlag);
+
     /** Create an emboss maskfilter
+        @param blurSigma    standard deviation of the Gaussian blur to apply 
+                            before applying lighting (e.g. 3)
         @param direction    array of 3 scalars [x, y, z] specifying the direction of the light source
         @param ambient      0...1 amount of ambient light
         @param specular     coefficient for specular highlights (e.g. 8)
-        @param blurRadius   amount to blur before applying lighting (e.g. 3)
         @return the emboss maskfilter
     */
-    static SkMaskFilter* CreateEmboss(  const SkScalar direction[3],
-                                        SkScalar ambient, SkScalar specular,
-                                        SkScalar blurRadius);
+    static SkMaskFilter* CreateEmboss(SkScalar blurSigma, const SkScalar direction[3],
+                                      SkScalar ambient, SkScalar specular);
+
+    // DEPRECATED - radius-based
+    static SkMaskFilter* CreateEmboss(const SkScalar direction[3],
+                                      SkScalar ambient, SkScalar specular,
+                                      SkScalar blurRadius);
 
     SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
+
 private:
     SkBlurMaskFilter(); // can't be instantiated
 };
diff --git a/include/effects/SkEmbossMaskFilter.h b/include/effects/SkEmbossMaskFilter.h
index c667920..4b5bd6f 100644
--- a/include/effects/SkEmbossMaskFilter.h
+++ b/include/effects/SkEmbossMaskFilter.h
@@ -23,6 +23,9 @@
         uint8_t     fSpecular;      // exponent, 4.4 right now
     };
 
+    SkEmbossMaskFilter(SkScalar blurSigma, const Light& light);
+
+    // DEPRECATED - radius-based
     SkEmbossMaskFilter(const Light& light, SkScalar blurRadius);
 
     // overrides from SkMaskFilter
@@ -41,7 +44,7 @@
 
 private:
     Light       fLight;
-    SkScalar    fBlurRadius;
+    SkScalar    fBlurSigma;
 
     typedef SkMaskFilter INHERITED;
 };
diff --git a/samplecode/SampleAll.cpp b/samplecode/SampleAll.cpp
index 01fbe0f..de99be7 100644
--- a/samplecode/SampleAll.cpp
+++ b/samplecode/SampleAll.cpp
@@ -80,7 +80,8 @@
 
 static void r0(SkLayerRasterizer* rast, SkPaint& p) {
     p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
-                                             SkBlurMaskFilter::kNormal_BlurStyle))->unref();
+                                             SkBlurMaskFilter::kNormal_BlurStyle, 
+                                             SkBlurMaskFilter::kNone_BlurFlag))->unref();
     rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
 
     p.setMaskFilter(NULL);
@@ -254,7 +255,10 @@
 
 #if 1
     SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
-    paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();
+    paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, 
+                                                        SK_Scalar1/4, 
+                                                        SkIntToScalar(4), 
+                                                        SkIntToScalar(3)))->unref();
     paint->setColor(SK_ColorBLUE);
 #endif
 }
@@ -383,8 +387,7 @@
         light.fAmbient        = 0x48;
         light.fSpecular        = 0x80;
         SkScalar radius = SkIntToScalar(12)/5;
-        SkEmbossMaskFilter* embossFilter = new SkEmbossMaskFilter(light,
-            radius);
+        SkEmbossMaskFilter* embossFilter = new SkEmbossMaskFilter(light, radius);
 
         SkXfermode* xfermode = SkXfermode::Create(SkXfermode::kXor_Mode);
         SkColorFilter* lightingFilter = SkColorFilter::CreateLightingFilter(
diff --git a/samplecode/SampleXfermodesBlur.cpp b/samplecode/SampleXfermodesBlur.cpp
index ec5909b..a4ca9e7 100644
--- a/samplecode/SampleXfermodesBlur.cpp
+++ b/samplecode/SampleXfermodesBlur.cpp
@@ -46,7 +46,8 @@
     void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha,
                    SkScalar x, SkScalar y) {
         SkPaint p;
-        SkMaskFilter* mf = SkBlurMaskFilter::Create(5, SkBlurMaskFilter::kNormal_BlurStyle, 0);
+        SkMaskFilter* mf = SkBlurMaskFilter::Create(5, SkBlurMaskFilter::kNormal_BlurStyle, 
+                                                    SkBlurMaskFilter::kNone_BlurFlag);
         p.setMaskFilter(mf)->unref();
 
         SkScalar ww = SkIntToScalar(W);
diff --git a/src/animator/SkDrawEmboss.cpp b/src/animator/SkDrawEmboss.cpp
index 5eed370..a0084eb 100644
--- a/src/animator/SkDrawEmboss.cpp
+++ b/src/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/src/animator/SkDrawEmboss.h b/src/animator/SkDrawEmboss.h
index 6e61997..7ffd3ef 100644
--- a/src/animator/SkDrawEmboss.h
+++ b/src/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/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 097e0ea..c94641b 100644
--- a/src/core/SkPicture.cpp
+++ b/src/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/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp
index 9585214..fb0153c 100644
--- a/src/effects/SkBlurDrawLooper.cpp
+++ b/src/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/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp
index c946c5e..a8ae1d3 100644
--- a/src/effects/SkBlurMask.cpp
+++ b/src/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/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h
index 36d7800..f49cd12 100644
--- a/src/effects/SkBlurMask.h
+++ b/src/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/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index b54c330..8833358 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/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/src/effects/SkEmbossMaskFilter.cpp b/src/effects/SkEmbossMaskFilter.cpp
index 391cba5..315b8cb 100644
--- a/src/effects/SkEmbossMaskFilter.cpp
+++ b/src/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