Complete the implementation of the faster blur; now supports all blur styles and matches the boxfilter approximation visually.  Also change the interpretation of the blur radius to be sigma/2; need to add SK_IGNORE_BLUR_RADIUS_CORRECTNESS to chromium GYP to avoid immediate layout test failures over there.

Review URL: https://codereview.appspot.com/7307076

git-svn-id: http://skia.googlecode.com/svn/trunk@7793 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/blurrect.cpp b/gm/blurrect.cpp
index a5e8cf0..52f177d 100644
--- a/gm/blurrect.cpp
+++ b/gm/blurrect.cpp
@@ -1,9 +1,9 @@
 /*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
+* Copyright 2012 Google Inc.
+*
+* Use of this source code is governed by a BSD-style license that can be
+* found in the LICENSE file.
+*/
 
 #include "gm.h"
 #include "SkBlurMaskFilter.h"
@@ -65,19 +65,18 @@
 };
 
 class BlurRectGM : public skiagm::GM {
-    SkAutoTUnref<SkMaskFilter> fMaskFilter;
-    SkString  fName;
-    PaintProc fPProc;
-    SkAlpha   fAlpha;
+      SkAutoTUnref<SkMaskFilter> fMaskFilter;
+      SkString  fName;
+      PaintProc fPProc;
+      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::kHighQuality_BlurFlag))
+                  , fName(name)
+                  , fPProc(pproc)
+                  , fAlpha(SkToU8(alpha)) {
         fName.appendf("_%s", gBlurStyle2Name[bs]);
     }
 
@@ -131,7 +130,7 @@
             canvas->translate(0, r.height() * 4/3);
         }
     }
-
+private:
     typedef GM INHERITED;
 };
 
@@ -139,17 +138,28 @@
     SkString  fName;
     unsigned int fRectWidth, fRectHeight;
     SkScalar fRadius;
+    SkBlurMask::Style fStyle;
 public:
-    BlurRectCompareGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, float radius)
+    BlurRectCompareGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, float radius, SkBlurMask::Style style)
         : fName(name)
         , fRectWidth(rectWidth)
         , fRectHeight(rectHeight)
         , fRadius(radius)
-    {}
+        , fStyle(style)
+        {}
 
-  int width() const { return fRectWidth; }
-  int height() const { return fRectHeight; }
-  SkScalar radius() const { return fRadius; }
+    int width() const { 
+        return fRectWidth; 
+    }
+    int height() const { 
+        return fRectHeight; 
+    }
+    SkScalar radius() const { 
+        return fRadius; 
+    }
+    SkBlurMask::Style style() const { 
+        return fStyle; 
+    }
 
 protected:
     virtual SkString onShortName() {
@@ -160,21 +170,34 @@
         return SkISize::Make(640, 480);
     }
 
-    virtual void makeMask(SkMask *m, const SkRect&) = 0;
+    virtual bool makeMask(SkMask *m, const SkRect&) = 0;
 
     virtual void onDraw(SkCanvas* canvas) {
-      SkRect r;
-      r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));
+        SkRect r;
+        r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));
 
-      SkMask mask;
+        SkISize canvas_size = canvas->getDeviceSize();
+        int center_x = (canvas_size.fWidth - r.width())/2;
+        int center_y = (canvas_size.fHeight - r.height())/2;
 
-      this->makeMask(&mask, r);
-      SkAutoMaskFreeImage amfi(mask.fImage);
+        SkMask mask;
 
-      SkBitmap bm;
-      bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height());
-      bm.setPixels(mask.fImage);
-      canvas->drawBitmap(bm, 50, 50, NULL);
+        if (!this->makeMask(&mask, r)) {
+            SkPaint paint;
+            r.offset( center_x, center_y );
+            canvas->drawRect(r,paint);
+            return;
+        }
+        SkAutoMaskFreeImage amfi(mask.fImage);
+
+        SkBitmap bm;
+        bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height());
+        bm.setPixels(mask.fImage);
+
+        center_x = (canvas_size.fWidth - mask.fBounds.width())/2;
+        center_y = (canvas_size.fHeight - mask.fBounds.height())/2;
+
+        canvas->drawBitmap(bm, center_x, center_y, NULL);
     }
 
     virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
@@ -186,33 +209,94 @@
 class BlurRectFastGM: public BlurRectCompareGM {
 public:
     BlurRectFastGM(const char name[], unsigned int rect_width,
-                   unsigned int rect_height, float blur_radius) :
-        BlurRectCompareGM(name, rect_width, rect_height, blur_radius) {}
+                   unsigned int rect_height, float blur_radius,
+                   SkBlurMask::Style style) :
+        INHERITED(name, rect_width, rect_height, blur_radius, style) 
+        {
+            
+        }
 protected:
-    virtual void makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
-        SkBlurMask::BlurRect(m, r, radius(), SkBlurMask::kNormal_Style,
-                             SkBlurMask::kHigh_Quality );
+    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
+        return SkBlurMask::BlurRect(m, r, this->radius(), this->style());
     }
+private:
+    typedef BlurRectCompareGM INHERITED;
 };
 
 class BlurRectSlowGM: public BlurRectCompareGM {
 public:
-  BlurRectSlowGM(const char name[], unsigned int rect_width, unsigned int rect_height, float blur_radius) :
-    BlurRectCompareGM( name, rect_width, rect_height, blur_radius ) {}
+    BlurRectSlowGM(const char name[], unsigned int rect_width, unsigned int rect_height, 
+                   float blur_radius, SkBlurMask::Style style) :
+        INHERITED(name, rect_width, rect_height, blur_radius, style) 
+        {
+            
+        }
 protected:
-    virtual void makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
+    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
         SkMask src;
         r.roundOut(&src.fBounds);
         src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
         src.fFormat = SkMask::kA8_Format;
         src.fRowBytes = src.fBounds.width();
-        src.fImage = SkMask::AllocImage( src.computeTotalImageSize() );
+        src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
         SkAutoMaskFreeImage amfi(src.fImage);
 
         memset(src.fImage, 0xff, src.computeTotalImageSize());
 
-        SkBlurMask::BlurSeparable(m, src, radius()/2, SkBlurMask::kNormal_Style, SkBlurMask::kHigh_Quality);
+        return SkBlurMask::BlurSeparable(m, src, this->radius(), this->style(), this->getQuality());
     }
+
+    virtual SkBlurMask::Quality getQuality() {
+        return SkBlurMask::kHigh_Quality;
+    }
+private:
+    typedef BlurRectCompareGM INHERITED;
+};
+
+class BlurRectSlowLowGM: public BlurRectSlowGM {
+public:
+    BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 
+                      float blurRadius, SkBlurMask::Style style) :
+        INHERITED(name, rectWidth, rectHeight, blurRadius, style) 
+        {
+            
+        }
+protected:
+    virtual SkBlurMask::Quality getQuality() SK_OVERRIDE {
+        return SkBlurMask::kLow_Quality;
+    }
+private:
+    typedef BlurRectSlowGM INHERITED;
+};
+
+class BlurRectGroundTruthGM: public BlurRectCompareGM {
+public:
+    BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight, 
+                          float blurRadius, SkBlurMask::Style style) :
+        INHERITED(name, rectWidth, rectHeight, blurRadius, style)
+        {
+            
+        }
+protected:
+    virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
+        SkMask src;
+        r.roundOut(&src.fBounds);
+        src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
+        src.fFormat = SkMask::kA8_Format;
+        src.fRowBytes = src.fBounds.width();
+        src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
+        SkAutoMaskFreeImage amfi(src.fImage);
+
+        memset(src.fImage, 0xff, src.computeTotalImageSize());
+
+        return SkBlurMask::BlurGroundTruth(m, src, this->radius(), this->style());
+    }
+
+    virtual SkBlurMask::Quality getQuality() {
+        return SkBlurMask::kHigh_Quality;
+    }
+private:
+    typedef BlurRectCompareGM INHERITED;
 };
 
 
@@ -223,12 +307,73 @@
 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kOuter_BlurStyle);)
 DEF_GM(return new BlurRectGM("blurrect", NULL, 0xFF, SkBlurMaskFilter::kInner_BlurStyle);)
 
-DEF_GM(return new BlurRectFastGM("blurrect_fast_100_100_10", 100, 100, 10);)
-DEF_GM(return new BlurRectFastGM("blurrect_fast_100_100_2", 100, 100, 2);)
-DEF_GM(return new BlurRectFastGM("blurrect_fast_10_10_100", 10, 10, 100);)
-DEF_GM(return new BlurRectFastGM("blurrect_fast_10_100_10", 10, 100, 10);)
+// regular size rects, blurs should be small enough not to completely overlap.
 
-DEF_GM(return new BlurRectSlowGM("blurrect_slow_100_100_10", 100, 100, 10);)
-DEF_GM(return new BlurRectSlowGM("blurrect_slow_100_100_2", 100, 100, 2);)
-DEF_GM(return new BlurRectSlowGM("blurrect_slow_10_10_100", 10, 10, 100);)
-DEF_GM(return new BlurRectSlowGM("blurrect_slow_10_100_10", 10, 100, 10);)
+DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_normal_fast", 25, 100, 2,  SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_normal_fast", 25, 100, 20, SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_normal_slow", 25, 100, 2,  SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_normal_slow", 25, 100, 20, SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_inner_fast", 25, 100, 2,  SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_inner_fast", 25, 100, 20, SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_inner_slow", 25, 100, 2,  SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_inner_slow", 25, 100, 20, SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectFastGM( "blurrect_25_100_2_outer_fast", 25, 100, 2,  SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_25_100_20_outer_fast", 25, 100, 20, SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_25_100_2_outer_slow", 25, 100, 2,  SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_25_100_20_outer_slow", 25, 100, 20, SkBlurMask::kOuter_Style);)
+
+// skinny tall rects, blurs overlap in X but not y
+
+DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_normal_fast", 5, 100, 2 , SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_normal_fast", 5, 100, 20, SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_normal_slow", 5, 100, 2 , SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_normal_slow", 5, 100, 20, SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_inner_fast", 5, 100, 2 , SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_inner_fast", 5, 100, 20, SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_inner_slow", 5, 100, 2 , SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_inner_slow", 5, 100, 20, SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectFastGM( "blurrect_5_100_2_outer_fast", 5, 100, 2 , SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_5_100_20_outer_fast", 5, 100, 20, SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_5_100_2_outer_slow", 5, 100, 2 , SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_5_100_20_outer_slow", 5, 100, 20, SkBlurMask::kOuter_Style);)
+
+// tiny rects, blurs overlap in X and Y
+
+DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_normal_fast", 5, 5, 2 , SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_normal_fast", 5, 5, 20, SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_normal_slow", 5, 5, 2 , SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_normal_slow", 5, 5, 20, SkBlurMask::kNormal_Style);)
+DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_inner_fast", 5, 5, 2 , SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_inner_fast", 5, 5, 20, SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_inner_slow", 5, 5, 2 , SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_inner_slow", 5, 5, 20, SkBlurMask::kInner_Style);)
+DEF_GM(return new BlurRectFastGM( "blurrect_5_5_2_outer_fast", 5, 5, 2 , SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectFastGM("blurrect_5_5_20_outer_fast", 5, 5, 20, SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectSlowGM( "blurrect_5_5_2_outer_slow", 5, 5, 2 , SkBlurMask::kOuter_Style);)
+DEF_GM(return new BlurRectSlowGM("blurrect_5_5_20_outer_slow", 5, 5, 20, SkBlurMask::kOuter_Style);)
+
+
+#if 0
+// dont' need to GM the gaussian convolution; it's slow and intended
+// as a ground truth comparison only.  Leaving these here in case we
+// ever want to turn these back on for debugging reasons.
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_1_simple", 25, 100, 1);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_2_simple", 25, 100, 2);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_3_simple", 25, 100, 3);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_4_simple", 25, 100, 4);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_5_simple", 25, 100, 5);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_6_simple", 25, 100, 6);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_7_simple", 25, 100, 7);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_8_simple", 25, 100, 8);)
+DEF_GM(return new BlurRectGroundTruthGM( "blurrect_25_100_9_simple", 25, 100, 9);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_10_simple", 25, 100, 10);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_11_simple", 25, 100, 11);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_12_simple", 25, 100, 12);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_13_simple", 25, 100, 13);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_14_simple", 25, 100, 14);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_15_simple", 25, 100, 15);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_16_simple", 25, 100, 16);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_17_simple", 25, 100, 17);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_18_simple", 25, 100, 18);)
+DEF_GM(return new BlurRectGroundTruthGM("blurrect_25_100_19_simple", 25, 100, 19);)
+#endif