Add new GM to demonstrates SkGaussianEdgeShader

This would've caught the incorrect distances in the center bug

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3111

Change-Id: I9461a8865b561cc139a18a5e779e933d7979ee0d
Reviewed-on: https://skia-review.googlesource.com/3111
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/gm/gaussianedge.cpp b/gm/gaussianedge.cpp
new file mode 100644
index 0000000..bed42af
--- /dev/null
+++ b/gm/gaussianedge.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2016 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 "SkRRect.h"
+#include "SkGaussianEdgeShader.h"
+
+//#define VIZ 1
+
+#ifdef VIZ
+#include "SkStroke.h"
+
+static void draw_stroke(SkCanvas* canvas, const SkRRect& rr, const SkPaint& p, SkColor color) {
+    SkPath output;
+
+    if (SkPaint::kFill_Style == p.getStyle()) {
+        output.addRRect(rr);
+    } else {
+        SkPath input;
+        input.addRRect(rr);
+
+        SkStroke stroke(p);
+        stroke.strokePath(input, &output);
+    }
+
+    SkPaint paint;
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setColor(color);
+
+    canvas->drawPath(output, paint);
+}
+
+static void extract_pts(const SkBitmap& bm, SkTDArray<SkPoint>* pts,
+                        int xOff, int width) {
+    pts->rewind();
+
+    for (int x = 0; x < width; ++x) {
+        SkColor color = bm.getColor(xOff+x, 0);    
+
+        pts->append()->set(SkIntToScalar(x), 255.0f-SkColorGetB(color));
+        if (x > 0 && x < width-1) {
+            pts->append()->set(SkIntToScalar(x), 255.0f-SkColorGetB(color));
+        }
+    }
+}
+
+static void draw_row(SkCanvas* canvas, int row, int width) {
+    SkPaint paint;
+    paint.setAntiAlias(true);
+
+    SkBitmap readback;
+
+    if (!canvas->readPixels(SkIRect::MakeXYWH(0, row, width, 1), &readback)) {
+        return;
+    }
+
+    SkTDArray<SkPoint> pts;
+    pts.setReserve(width/3);
+
+    extract_pts(readback, &pts, 0, width/3);
+    paint.setColor(SK_ColorRED);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint);
+
+    extract_pts(readback, &pts, width/3, width/3);
+    paint.setColor(SK_ColorGREEN);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint);
+
+    extract_pts(readback, &pts, 2*width/3, width/3);
+    paint.setColor(SK_ColorBLUE);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint);
+}
+#endif
+
+namespace skiagm {
+
+// This GM exercises the SkGaussianEdgeShader.
+// It draws three columns showing filled, stroked, and stroke and filled rendering.
+// It draws three rows showing a blur radius smaller than, equal to
+// and, finally, double the RRect's corner radius
+// In VIZ mode an extra column is drawn showing the blur ramps (they should all line up).
+class GaussianEdgeGM : public GM {
+public:
+    GaussianEdgeGM() {
+        this->setBGColor(SK_ColorWHITE);
+    }
+
+protected:
+
+    SkString onShortName() override {
+        return SkString("gaussianedge");
+    }
+
+    SkISize onISize() override {
+        int numCols = kNumBaseCols;
+#ifdef VIZ
+        numCols++;
+#endif
+
+        return SkISize::Make(kPad + numCols*(kCellWidth+kPad),
+                             kPad + kNumRows*(kCellWidth+kPad));
+    }
+
+    static void DrawRow(SkCanvas* canvas, int blurRad, int midLine) {
+        SkAutoCanvasRestore acr(canvas, true);
+
+        SkRRect rrects[kNumBaseCols];
+        SkPaint paints[kNumBaseCols];
+
+        {
+            const SkRect r = SkRect::MakeIWH(kRRSize, kRRSize);
+            const SkRRect baseRR = SkRRect::MakeRectXY(r,
+                                                       SkIntToScalar(kRRRad),
+                                                       SkIntToScalar(kRRRad));
+
+            SkPaint basePaint;
+            basePaint.setAntiAlias(true);
+            basePaint.setShader(SkGaussianEdgeShader::Make());
+            basePaint.setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff, 0));
+
+            //----
+            paints[0] = basePaint;
+            rrects[0] = baseRR;
+
+            //----
+            paints[1] = basePaint;
+            paints[1].setStyle(SkPaint::kStroke_Style);
+
+            rrects[1] = baseRR;
+            if (blurRad/2.0f < kRRRad) {
+                rrects[1].inset(blurRad/2.0f, blurRad/2.0f);
+                paints[1].setStrokeWidth(SkIntToScalar(blurRad));
+            } else {
+                SkScalar inset = kRRRad - 0.5f;
+                rrects[1].inset(inset, inset);
+                SkScalar pad = blurRad/2.0f - inset;
+                paints[1].setStrokeWidth(blurRad + 2.0f * pad);                
+                paints[1].setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff,
+                                                  (int)(4.0f*pad)));
+            }
+
+            //----
+            paints[2] = basePaint;
+            paints[2].setStyle(SkPaint::kStrokeAndFill_Style);
+
+            rrects[2] = baseRR;
+            if (blurRad/2.0f < kRRRad) {
+                rrects[2].inset(blurRad/2.0f, blurRad/2.0f);
+                paints[2].setStrokeWidth(SkIntToScalar(blurRad));
+            } else {
+                SkScalar inset = kRRRad - 0.5f;
+                rrects[2].inset(inset, inset);
+                SkScalar pad = blurRad/2.0f - inset;
+                paints[2].setStrokeWidth(blurRad + 2.0f * pad);                
+                paints[2].setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff,
+                                                  (int)(4.0f*pad)));
+            }
+        }
+
+        //----
+        canvas->save();
+            // draw the shadows
+            for (int i = 0; i < kNumBaseCols; ++i) {
+                canvas->drawRRect(rrects[i], paints[i]);
+                canvas->translate(SkIntToScalar(kCellWidth+kPad), 0.0f);
+            }
+
+#ifdef VIZ
+            // draw the visualization of the shadow ramps
+            draw_row(canvas, midLine, 3*(kRRSize+kPad));
+#endif
+        canvas->restore();
+
+#ifdef VIZ
+        const SkColor colors[kNumBaseCols] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+
+        // circle back and draw the stroked geometry (they would mess up the viz otherwise)
+        for (int i = 0; i < kNumBaseCols; ++i) {
+            draw_stroke(canvas, rrects[i], paints[i], colors[i]);
+            canvas->translate(SkIntToScalar(kCellWidth+kPad), 0.0f);
+        }
+#endif
+    }
+
+    void onDraw(SkCanvas* canvas) override {
+        GrDrawContext* drawContext = canvas->internal_private_accessTopLayerDrawContext();
+        if (!drawContext) {
+            skiagm::GM::DrawGpuOnlyMessage(canvas);
+            return;
+        }
+
+        const int blurRadii[kNumRows] = { kRRRad/2, kRRRad, 2*kRRRad };
+
+        canvas->translate(SkIntToScalar(kPad), SkIntToScalar(kPad));
+        for (int i = 0; i < kNumRows; ++i) {
+            DrawRow(canvas, blurRadii[i], kPad+(i*kRRSize)+kRRSize/2);
+            canvas->translate(0.0f, SkIntToScalar(kCellWidth+kPad));
+        }
+    }
+
+private:
+    static const int kNumRows = 3;
+    static const int kNumBaseCols = 3;
+    static const int kPad = 5;
+    static const int kRRSize = 256;
+    static const int kRRRad = 64;
+    static const int kCellWidth = kRRSize;
+
+    typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM(return new GaussianEdgeGM;)
+}