converted GrRectBlurEffect to SkSL

Bug: skia:
Change-Id: I3a8e16fd2792e6fb5711815d8aad46ae30c2872e
Reviewed-on: https://skia-review.googlesource.com/59163
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/effects/GrAlphaThresholdFragmentProcessor.cpp b/src/effects/GrAlphaThresholdFragmentProcessor.cpp
index e1badf7..5ef0221 100644
--- a/src/effects/GrAlphaThresholdFragmentProcessor.cpp
+++ b/src/effects/GrAlphaThresholdFragmentProcessor.cpp
@@ -34,6 +34,12 @@
         const GrAlphaThresholdFragmentProcessor& _outer =
                 args.fFp.cast<GrAlphaThresholdFragmentProcessor>();
         (void)_outer;
+        auto colorXform = _outer.colorXform();
+        (void)colorXform;
+        auto innerThreshold = _outer.innerThreshold();
+        (void)innerThreshold;
+        auto outerThreshold = _outer.outerThreshold();
+        (void)outerThreshold;
         fColorSpaceHelper.emitCode(args.fUniformHandler, _outer.colorXform().get());
         fInnerThresholdVar = args.fUniformHandler->addUniform(
                 kFragment_GrShaderFlag, kHalf_GrSLType, kDefault_GrSLPrecision, "innerThreshold");
diff --git a/src/effects/GrCircleBlurFragmentProcessor.cpp b/src/effects/GrCircleBlurFragmentProcessor.cpp
index 5a825f4..647afb8 100644
--- a/src/effects/GrCircleBlurFragmentProcessor.cpp
+++ b/src/effects/GrCircleBlurFragmentProcessor.cpp
@@ -263,6 +263,12 @@
         const GrCircleBlurFragmentProcessor& _outer =
                 args.fFp.cast<GrCircleBlurFragmentProcessor>();
         (void)_outer;
+        auto circleRect = _outer.circleRect();
+        (void)circleRect;
+        auto textureRadius = _outer.textureRadius();
+        (void)textureRadius;
+        auto solidRadius = _outer.solidRadius();
+        (void)solidRadius;
         fCircleDataVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
                                                           kDefault_GrSLPrecision, "circleData");
         fragBuilder->codeAppendf(
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index ca7de71..7da4245 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -26,6 +26,7 @@
 #include "GrShaderCaps.h"
 #include "GrStyle.h"
 #include "GrTextureProxy.h"
+#include "effects/GrRectBlurEffect.h"
 #include "effects/GrSimpleTextureEffect.h"
 #include "effects/GrTextureDomain.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
@@ -761,253 +762,6 @@
 
 #if SK_SUPPORT_GPU
 
-class GrGLRectBlurEffect;
-
-class GrRectBlurEffect : public GrFragmentProcessor {
-public:
-    ~GrRectBlurEffect() override { }
-
-    const char* name() const override { return "RectBlur"; }
-
-    static std::unique_ptr<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
-                                                     const SkRect& rect, float sigma) {
-        int doubleProfileSize = SkScalarCeilToInt(12*sigma);
-
-        if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
-            // if the blur sigma is too large so the gaussian overlaps the whole
-            // rect in either direction, fall back to CPU path for now.
-            return nullptr;
-        }
-
-        sk_sp<GrTextureProxy> blurProfile(CreateBlurProfileTexture(resourceProvider, sigma));
-        if (!blurProfile) {
-           return nullptr;
-        }
-        // in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger
-        // than that, the shader math will end up with infinities and result in the blur effect not
-        // working correctly. To avoid this, we switch into highp when the coordinates are too big.
-        // As 2^14 is the minimum range but the actual range can be bigger, we might end up
-        // switching to highp sooner than strictly necessary, but most devices that have a bigger
-        // range for mediump also have mediump being exactly the same as highp (e.g. all non-OpenGL
-        // ES devices), and thus incur no additional penalty for the switch.
-        static const SkScalar kMAX_BLUR_COORD = SkIntToScalar(16000);
-        GrSLPrecision precision;
-        if (SkScalarAbs(rect.top()) > kMAX_BLUR_COORD ||
-            SkScalarAbs(rect.left()) > kMAX_BLUR_COORD ||
-            SkScalarAbs(rect.bottom()) > kMAX_BLUR_COORD ||
-            SkScalarAbs(rect.right()) > kMAX_BLUR_COORD ||
-            SkScalarAbs(rect.width()) > kMAX_BLUR_COORD ||
-            SkScalarAbs(rect.height()) > kMAX_BLUR_COORD) {
-            precision = kHigh_GrSLPrecision;
-        } else {
-            precision = kDefault_GrSLPrecision;
-        }
-
-        return std::unique_ptr<GrFragmentProcessor>(
-                new GrRectBlurEffect(rect, sigma, std::move(blurProfile), precision));
-    }
-
-    std::unique_ptr<GrFragmentProcessor> clone() const override {
-        return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(
-                fRect, fSigma, sk_ref_sp(fBlurProfileSampler.proxy()), fPrecision));
-    }
-
-    const SkRect& getRect() const { return fRect; }
-    float getSigma() const { return fSigma; }
-    GrSLPrecision precision() const { return fPrecision; }
-
-private:
-    GrRectBlurEffect(const SkRect& rect, float sigma,
-                     sk_sp<GrTextureProxy> blurProfile, GrSLPrecision fPrecision);
-
-    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
-    void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
-
-    bool onIsEqual(const GrFragmentProcessor&) const override;
-
-    static sk_sp<GrTextureProxy> CreateBlurProfileTexture(GrResourceProvider*, float sigma);
-
-    SkRect          fRect;
-    float           fSigma;
-    TextureSampler  fBlurProfileSampler;
-    GrSLPrecision   fPrecision;
-
-    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
-
-    typedef GrFragmentProcessor INHERITED;
-};
-
-class GrGLRectBlurEffect : public GrGLSLFragmentProcessor {
-public:
-    void emitCode(EmitArgs&) override;
-
-    static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b);
-
-protected:
-    void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
-
-private:
-    typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
-
-    UniformHandle       fProxyRectUniform;
-    UniformHandle       fProfileSizeUniform;
-
-    typedef GrGLSLFragmentProcessor INHERITED;
-};
-
-void OutputRectBlurProfileLookup(GrGLSLFPFragmentBuilder* fragBuilder,
-                                 GrGLSLFragmentProcessor::SamplerHandle sampler,
-                                 const char *output,
-                                 const char *profileSize, const char *loc,
-                                 const char *blurred_width,
-                                 const char *sharp_width) {
-    fragBuilder->codeAppendf("half %s;", output);
-    fragBuilder->codeAppendf("{");
-    fragBuilder->codeAppendf("half coord = ((abs(%s - 0.5 * %s) - 0.5 * %s)) / %s;",
-                           loc, blurred_width, sharp_width, profileSize);
-    fragBuilder->codeAppendf("%s = ", output);
-    fragBuilder->appendTextureLookup(sampler, "half2(coord,0.5)");
-    fragBuilder->codeAppend(".a;");
-    fragBuilder->codeAppendf("}");
-}
-
-
-void GrGLRectBlurEffect::GenKey(const GrProcessor& proc, const GrShaderCaps&,
-                                GrProcessorKeyBuilder* b) {
-    const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
-
-    b->add32(rbe.precision());
-}
-
-
-void GrGLRectBlurEffect::emitCode(EmitArgs& args) {
-    const GrRectBlurEffect& rbe = args.fFp.cast<GrRectBlurEffect>();
-
-    GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
-
-    const char *rectName;
-    const char *profileSizeName;
-
-    const char* floatType = rbe.precision() == kHigh_GrSLPrecision ? "float" : "half";
-    fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
-                                                   rbe.precision() == kHigh_GrSLPrecision ?
-                                                             kFloat4_GrSLType : kHalf4_GrSLType,
-                                                   "proxyRect",
-                                                   &rectName);
-    fProfileSizeUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
-                                                     kHalf_GrSLType,
-                                                     "profileSize",
-                                                     &profileSizeName);
-
-    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
-
-    if (args.fInputColor) {
-        fragBuilder->codeAppendf("half4 src=%s;", args.fInputColor);
-    } else {
-        fragBuilder->codeAppendf("half4 src=half4(1);");
-    }
-
-    fragBuilder->codeAppendf("%s2 translatedPos = sk_FragCoord.xy - %s.xy;", floatType, rectName);
-    fragBuilder->codeAppendf("%s width = %s.z - %s.x;", floatType, rectName, rectName);
-    fragBuilder->codeAppendf("%s height = %s.w - %s.y;", floatType, rectName, rectName);
-
-    fragBuilder->codeAppendf("%s2 smallDims = half2(width - %s, height - %s);", floatType,
-                             profileSizeName, profileSizeName);
-    fragBuilder->codeAppendf("%s center = 2.0 * floor(%s/2.0 + .25) - 1.0;", floatType,
-                             profileSizeName);
-    fragBuilder->codeAppendf("%s2 wh = smallDims - half2(center,center);", floatType);
-
-    OutputRectBlurProfileLookup(fragBuilder, args.fTexSamplers[0], "horiz_lookup", profileSizeName,
-                                "translatedPos.x", "width", "wh.x");
-    OutputRectBlurProfileLookup(fragBuilder, args.fTexSamplers[0], "vert_lookup", profileSizeName,
-                                "translatedPos.y", "height", "wh.y");
-
-    fragBuilder->codeAppendf("half final = horiz_lookup * vert_lookup;");
-    fragBuilder->codeAppendf("%s = src * final;", args.fOutputColor);
-}
-
-void GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
-                                   const GrFragmentProcessor& proc) {
-    const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
-    SkRect rect = rbe.getRect();
-
-    pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
-    pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
-}
-
-sk_sp<GrTextureProxy> GrRectBlurEffect::CreateBlurProfileTexture(
-                                                            GrResourceProvider* resourceProvider,
-                                                            float sigma) {
-    unsigned int profileSize = SkScalarCeilToInt(6*sigma);
-
-    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
-    GrUniqueKey key;
-    GrUniqueKey::Builder builder(&key, kDomain, 1);
-    builder[0] = profileSize;
-    builder.finish();
-
-    sk_sp<GrTextureProxy> blurProfile(resourceProvider->findOrCreateProxyByUniqueKey(
-                                                                  key, kTopLeft_GrSurfaceOrigin));
-    if (!blurProfile) {
-        GrSurfaceDesc texDesc;
-        texDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
-        texDesc.fWidth = profileSize;
-        texDesc.fHeight = 1;
-        texDesc.fConfig = kAlpha_8_GrPixelConfig;
-
-        std::unique_ptr<uint8_t[]> profile(SkBlurMask::ComputeBlurProfile(sigma));
-
-        blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider,
-                                                   texDesc, SkBudgeted::kYes, profile.get(), 0);
-        if (!blurProfile) {
-            return nullptr;
-        }
-
-        SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin);
-        resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get());
-    }
-
-    return blurProfile;
-}
-
-GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma,
-                                   sk_sp<GrTextureProxy> blurProfile,
-                                   GrSLPrecision precision)
-        : INHERITED(kGrRectBlurEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag)
-        , fRect(rect)
-        , fSigma(sigma)
-        , fBlurProfileSampler(std::move(blurProfile))
-        , fPrecision(precision) {
-    this->addTextureSampler(&fBlurProfileSampler);
-}
-
-void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
-                                             GrProcessorKeyBuilder* b) const {
-    GrGLRectBlurEffect::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
-    return new GrGLRectBlurEffect;
-}
-
-bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
-    const GrRectBlurEffect& s = sBase.cast<GrRectBlurEffect>();
-    return this->getSigma() == s.getSigma() && this->getRect() == s.getRect();
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
-
-#if GR_TEST_UTILS
-std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::TestCreate(GrProcessorTestData* d) {
-    float sigma = d->fRandom->nextRangeF(3,8);
-    float width = d->fRandom->nextRangeF(200,300);
-    float height = d->fRandom->nextRangeF(200,300);
-    return GrRectBlurEffect::Make(d->resourceProvider(),
-                                  SkRect::MakeWH(width, height), sigma);
-}
-#endif
-
 bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
                                                GrRenderTargetContext* renderTargetContext,
                                                GrPaint&& paint,
diff --git a/src/gpu/effects/GrArithmeticFP.cpp b/src/gpu/effects/GrArithmeticFP.cpp
index bc73b45..fec3fbf 100644
--- a/src/gpu/effects/GrArithmeticFP.cpp
+++ b/src/gpu/effects/GrArithmeticFP.cpp
@@ -23,6 +23,16 @@
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         const GrArithmeticFP& _outer = args.fFp.cast<GrArithmeticFP>();
         (void)_outer;
+        auto k1 = _outer.k1();
+        (void)k1;
+        auto k2 = _outer.k2();
+        (void)k2;
+        auto k3 = _outer.k3();
+        (void)k3;
+        auto k4 = _outer.k4();
+        (void)k4;
+        auto enforcePMColor = _outer.enforcePMColor();
+        (void)enforcePMColor;
         fKVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
                                                  kDefault_GrSLPrecision, "k");
         SkString _child0("_child0");
diff --git a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
index 551adea..2e42b23 100644
--- a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
@@ -24,6 +24,8 @@
         const GrBlurredEdgeFragmentProcessor& _outer =
                 args.fFp.cast<GrBlurredEdgeFragmentProcessor>();
         (void)_outer;
+        auto mode = _outer.mode();
+        (void)mode;
         fragBuilder->codeAppendf(
                 "half factor = half(1.0 - float(%s.w));\n@switch (%d) {\n    case 0:\n        "
                 "factor = half(exp(float(float(-factor * factor) * 4.0)) - "
diff --git a/src/gpu/effects/GrCircleEffect.cpp b/src/gpu/effects/GrCircleEffect.cpp
index 3c0e11b..b181669 100644
--- a/src/gpu/effects/GrCircleEffect.cpp
+++ b/src/gpu/effects/GrCircleEffect.cpp
@@ -23,6 +23,12 @@
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         const GrCircleEffect& _outer = args.fFp.cast<GrCircleEffect>();
         (void)_outer;
+        auto edgeType = _outer.edgeType();
+        (void)edgeType;
+        auto center = _outer.center();
+        (void)center;
+        auto radius = _outer.radius();
+        (void)radius;
         prevRadius = -1.0;
         fCircleVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
                                                       kDefault_GrSLPrecision, "circle");
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 0d2a139..d8c9044 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -23,6 +23,8 @@
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         const GrConfigConversionEffect& _outer = args.fFp.cast<GrConfigConversionEffect>();
         (void)_outer;
+        auto pmConversion = _outer.pmConversion();
+        (void)pmConversion;
 
         fragBuilder->forceHighPrecision();
         fragBuilder->codeAppendf(
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
index 2498ffc..88b8bdb 100644
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ b/src/gpu/effects/GrDitherEffect.cpp
@@ -23,6 +23,8 @@
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         const GrDitherEffect& _outer = args.fFp.cast<GrDitherEffect>();
         (void)_outer;
+        auto rangeType = _outer.rangeType();
+        (void)rangeType;
         fragBuilder->codeAppendf(
                 "half value;\nhalf range;\n@switch (%d) {\n    case 0:\n        range = "
                 "0.0039215686274509803;\n        break;\n    case 1:\n        range = "
diff --git a/src/gpu/effects/GrEllipseEffect.cpp b/src/gpu/effects/GrEllipseEffect.cpp
index 8621c9a..61b8f96 100644
--- a/src/gpu/effects/GrEllipseEffect.cpp
+++ b/src/gpu/effects/GrEllipseEffect.cpp
@@ -23,6 +23,12 @@
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         const GrEllipseEffect& _outer = args.fFp.cast<GrEllipseEffect>();
         (void)_outer;
+        auto edgeType = _outer.edgeType();
+        (void)edgeType;
+        auto center = _outer.center();
+        (void)center;
+        auto radii = _outer.radii();
+        (void)radii;
         prevRadii = half2(-1.0);
         useScale = sk_Caps.floatPrecisionVaries;
         fEllipseVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
diff --git a/src/gpu/effects/GrRectBlurEffect.cpp b/src/gpu/effects/GrRectBlurEffect.cpp
new file mode 100644
index 0000000..3b2d8a1
--- /dev/null
+++ b/src/gpu/effects/GrRectBlurEffect.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * This file was autogenerated from GrRectBlurEffect.fp; do not modify.
+ */
+#include "GrRectBlurEffect.h"
+#if SK_SUPPORT_GPU
+#include "glsl/GrGLSLColorSpaceXformHelper.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "SkSLCPP.h"
+#include "SkSLUtil.h"
+class GrGLSLRectBlurEffect : public GrGLSLFragmentProcessor {
+public:
+    GrGLSLRectBlurEffect() {}
+    void emitCode(EmitArgs& args) override {
+        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+        const GrRectBlurEffect& _outer = args.fFp.cast<GrRectBlurEffect>();
+        (void)_outer;
+        auto rect = _outer.rect();
+        (void)rect;
+        auto sigma = _outer.sigma();
+        (void)sigma;
+        highPrecision = ((((abs(rect.left()) > 16000.0 || abs(rect.top()) > 16000.0) ||
+                           abs(rect.right()) > 16000.0) ||
+                          abs(rect.bottom()) > 16000.0) ||
+                         abs(rect.right() - rect.left()) > 16000.0) ||
+                        abs(rect.bottom() - rect.top()) > 16000.0;
+        fRectVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
+                                                    kDefault_GrSLPrecision, "rect");
+        if (!highPrecision) {
+            fProxyRectHalfVar =
+                    args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf4_GrSLType,
+                                                     kDefault_GrSLPrecision, "proxyRectHalf");
+        }
+        if (highPrecision) {
+            fProxyRectFloatVar =
+                    args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType,
+                                                     kDefault_GrSLPrecision, "proxyRectFloat");
+        }
+        fProfileSizeVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
+                                                           kDefault_GrSLPrecision, "profileSize");
+        fragBuilder->codeAppendf(
+                "bool highPrecision = %s;\n@if (highPrecision) {\n    float2 translatedPos = "
+                "sk_FragCoord.xy - %s.xy;\n    float width = %s.z - %s.x;\n    float height = %s.w "
+                "- %s.y;\n    float2 smallDims = float2(width - float(%s), height - float(%s));\n  "
+                "  float center = 2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0;\n    float2 wh "
+                "= smallDims - float2(center, center);\n    half hcoord = "
+                "half((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / float(%s));\n    half "
+                "hlookup = texture(%s, float2(float(hcoord), 0.5)).%s.w",
+                (highPrecision ? "true" : "false"), args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str());
+        fragBuilder->codeAppendf(
+                ";\n    half vcoord = half((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y) / "
+                "float(%s));\n    half vlookup = texture(%s, float2(float(vcoord), 0.5)).%s.w;\n   "
+                " %s = (%s * hlookup) * vlookup;\n} else {\n    half2 translatedPos = "
+                "half2(sk_FragCoord.xy - %s.xy);\n    half width = half(%s.z - %s.x);\n    half "
+                "height = half(%s.w - %s.y);\n    half2 smallDims = half2(width - %s, height - "
+                "%s);\n    half center = half(2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0);\n "
+                "   half2 wh = smallDims - half2(float2(floa",
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)",
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fRectVar),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar));
+        fragBuilder->codeAppendf(
+                "t(center), float(center)));\n    half hcoord = "
+                "half((abs(float(float(translatedPos.x) - 0.5 * float(width))) - 0.5 * "
+                "float(wh.x)) / float(%s));\n    half hlookup = texture(%s, float2(float(hcoord), "
+                "0.5)).%s.w;\n    half vcoord = half((abs(float(float(translatedPos.y) - 0.5 * "
+                "float(height))) - 0.5 * float(wh.y)) / float(%s));\n    half vlookup = "
+                "texture(%s, float2(float(vcoord), 0.5)).%s.w;\n    %s = (%s * hlookup) * "
+                "vlookup;\n}\n",
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fUniformHandler->getUniformCStr(fProfileSizeVar),
+                fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
+                fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
+                args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)");
+    }
+
+private:
+    void onSetData(const GrGLSLProgramDataManager& pdman,
+                   const GrFragmentProcessor& _proc) override {
+        const GrRectBlurEffect& _outer = _proc.cast<GrRectBlurEffect>();
+        {
+            const SkRect rectValue = _outer.rect();
+            pdman.set4fv(fRectVar, 1, (float*)&rectValue);
+        }
+        UniformHandle& rect = fRectVar;
+        (void)rect;
+        auto sigma = _outer.sigma();
+        (void)sigma;
+        UniformHandle& blurProfile = fBlurProfileVar;
+        (void)blurProfile;
+        UniformHandle& proxyRectHalf = fProxyRectHalfVar;
+        (void)proxyRectHalf;
+        UniformHandle& proxyRectFloat = fProxyRectFloatVar;
+        (void)proxyRectFloat;
+        UniformHandle& profileSize = fProfileSizeVar;
+        (void)profileSize;
+
+        pdman.set1f(profileSize, SkScalarCeilToScalar(6 * sigma));
+    }
+    bool highPrecision;
+    UniformHandle fProxyRectHalfVar;
+    UniformHandle fProxyRectFloatVar;
+    UniformHandle fProfileSizeVar;
+    UniformHandle fRectVar;
+    UniformHandle fBlurProfileVar;
+};
+GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
+    return new GrGLSLRectBlurEffect();
+}
+void GrRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+                                             GrProcessorKeyBuilder* b) const {}
+bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
+    const GrRectBlurEffect& that = other.cast<GrRectBlurEffect>();
+    (void)that;
+    if (fRect != that.fRect) return false;
+    if (fSigma != that.fSigma) return false;
+    if (fBlurProfile != that.fBlurProfile) return false;
+    return true;
+}
+GrRectBlurEffect::GrRectBlurEffect(const GrRectBlurEffect& src)
+        : INHERITED(kGrRectBlurEffect_ClassID, src.optimizationFlags())
+        , fRect(src.fRect)
+        , fSigma(src.fSigma)
+        , fBlurProfile(src.fBlurProfile) {
+    this->addTextureSampler(&fBlurProfile);
+}
+std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::clone() const {
+    return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(*this));
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::TestCreate(GrProcessorTestData* data) {
+    float sigma = data->fRandom->nextRangeF(3, 8);
+    float width = data->fRandom->nextRangeF(200, 300);
+    float height = data->fRandom->nextRangeF(200, 300);
+    return GrRectBlurEffect::Make(data->resourceProvider(), SkRect::MakeWH(width, height), sigma);
+}
+#endif
+#endif
diff --git a/src/gpu/effects/GrRectBlurEffect.fp b/src/gpu/effects/GrRectBlurEffect.fp
new file mode 100644
index 0000000..fe5d59e
--- /dev/null
+++ b/src/gpu/effects/GrRectBlurEffect.fp
@@ -0,0 +1,123 @@
+@header {
+    #include "GrResourceProvider.h"
+    #include "../effects/SkBlurMask.h"
+}
+
+in uniform float4 rect;
+in float sigma;
+in uniform sampler2D blurProfile;
+
+// in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger than
+// that, the shader math will end up with infinities and result in the blur effect not working
+// correctly. To avoid this, we switch into highp when the coordinates are too big. As 2^14 is the
+// minimum range but the actual range can be bigger, we might end up switching to highp sooner than
+// strictly necessary, but most devices that have a bigger range for mediump also have mediump being
+// exactly the same as highp (e.g. all non-OpenGL ES devices), and thus incur no additional penalty
+// for the switch.
+layout(key) bool highPrecision = abs(rect.x) > 16000 || abs(rect.y) > 16000 ||
+                                 abs(rect.z) > 16000 || abs(rect.w) > 16000 ||
+                                 abs(rect.z - rect.x) > 16000 || abs(rect.w - rect.y) > 16000;
+
+layout(when=!highPrecision) uniform half4 proxyRectHalf;
+layout(when=highPrecision) uniform float4 proxyRectFloat;
+uniform half profileSize;
+
+
+@class {
+    static sk_sp<GrTextureProxy> CreateBlurProfileTexture(GrResourceProvider* resourceProvider,
+                                                          float sigma) {
+        unsigned int profileSize = SkScalarCeilToInt(6 * sigma);
+
+        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+        GrUniqueKey key;
+        GrUniqueKey::Builder builder(&key, kDomain, 1);
+        builder[0] = profileSize;
+        builder.finish();
+
+        sk_sp<GrTextureProxy> blurProfile(resourceProvider->findOrCreateProxyByUniqueKey(
+                                                                    key, kTopLeft_GrSurfaceOrigin));
+        if (!blurProfile) {
+            GrSurfaceDesc texDesc;
+            texDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
+            texDesc.fWidth = profileSize;
+            texDesc.fHeight = 1;
+            texDesc.fConfig = kAlpha_8_GrPixelConfig;
+
+            std::unique_ptr<uint8_t[]> profile(SkBlurMask::ComputeBlurProfile(sigma));
+
+            blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider,
+                                                       texDesc, SkBudgeted::kYes, profile.get(), 0);
+            if (!blurProfile) {
+                return nullptr;
+            }
+
+            SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin);
+            resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get());
+        }
+
+        return blurProfile;
+    }
+}
+
+@make {
+     static std::unique_ptr<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
+                                                      const SkRect& rect, float sigma) {
+         int doubleProfileSize = SkScalarCeilToInt(12*sigma);
+
+         if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
+             // if the blur sigma is too large so the gaussian overlaps the whole
+             // rect in either direction, fall back to CPU path for now.
+             return nullptr;
+         }
+
+         sk_sp<GrTextureProxy> blurProfile(CreateBlurProfileTexture(resourceProvider, sigma));
+         if (!blurProfile) {
+            return nullptr;
+         }
+
+         return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(rect, sigma,
+                                                                          std::move(blurProfile)));
+     }
+}
+
+void main() {
+    @if (highPrecision) {
+        float2 translatedPos = sk_FragCoord.xy - rect.xy;
+        float width = rect.z - rect.x;
+        float height = rect.w - rect.y;
+        float2 smallDims = float2(width - profileSize, height - profileSize);
+        float center = 2 * floor(profileSize / 2 + 0.25) - 1;
+        float2 wh = smallDims - float2(center, center);
+        half hcoord = ((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x)) / profileSize;
+        half hlookup = texture(blurProfile, float2(hcoord, 0.5)).a;
+        half vcoord = ((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y)) / profileSize;
+        half vlookup = texture(blurProfile, float2(vcoord, 0.5)).a;
+        sk_OutColor = sk_InColor * hlookup * vlookup;
+    } else {
+        half2 translatedPos = sk_FragCoord.xy - rect.xy;
+        half width = rect.z - rect.x;
+        half height = rect.w - rect.y;
+        half2 smallDims = half2(width - profileSize, height - profileSize);
+        half center = 2 * floor(profileSize / 2 + 0.25) - 1;
+        half2 wh = smallDims - float2(center, center);
+        half hcoord = ((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x)) / profileSize;
+        half hlookup = texture(blurProfile, float2(hcoord, 0.5)).a;
+        half vcoord = ((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y)) / profileSize;
+        half vlookup = texture(blurProfile, float2(vcoord, 0.5)).a;
+        sk_OutColor = sk_InColor * hlookup * vlookup;
+    }
+}
+
+@setData(pdman) {
+    pdman.set1f(profileSize, SkScalarCeilToScalar(6 * sigma));
+}
+
+@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag }
+
+@test(data) {
+    float sigma = data->fRandom->nextRangeF(3,8);
+    float width = data->fRandom->nextRangeF(200,300);
+    float height = data->fRandom->nextRangeF(200,300);
+    return GrRectBlurEffect::Make(data->resourceProvider(),
+                                  SkRect::MakeWH(width, height), sigma);
+}
diff --git a/src/gpu/effects/GrRectBlurEffect.h b/src/gpu/effects/GrRectBlurEffect.h
new file mode 100644
index 0000000..7a8bc2c
--- /dev/null
+++ b/src/gpu/effects/GrRectBlurEffect.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * This file was autogenerated from GrRectBlurEffect.fp; do not modify.
+ */
+#ifndef GrRectBlurEffect_DEFINED
+#define GrRectBlurEffect_DEFINED
+#include "SkTypes.h"
+#if SK_SUPPORT_GPU
+
+#include "GrResourceProvider.h"
+#include "../effects/SkBlurMask.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+#include "GrColorSpaceXform.h"
+class GrRectBlurEffect : public GrFragmentProcessor {
+public:
+    static sk_sp<GrTextureProxy> CreateBlurProfileTexture(GrResourceProvider* resourceProvider,
+                                                          float sigma) {
+        unsigned int profileSize = SkScalarCeilToInt(6 * sigma);
+
+        static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
+        GrUniqueKey key;
+        GrUniqueKey::Builder builder(&key, kDomain, 1);
+        builder[0] = profileSize;
+        builder.finish();
+
+        sk_sp<GrTextureProxy> blurProfile(
+                resourceProvider->findOrCreateProxyByUniqueKey(key, kTopLeft_GrSurfaceOrigin));
+        if (!blurProfile) {
+            GrSurfaceDesc texDesc;
+            texDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
+            texDesc.fWidth = profileSize;
+            texDesc.fHeight = 1;
+            texDesc.fConfig = kAlpha_8_GrPixelConfig;
+
+            std::unique_ptr<uint8_t[]> profile(SkBlurMask::ComputeBlurProfile(sigma));
+
+            blurProfile = GrSurfaceProxy::MakeDeferred(resourceProvider, texDesc, SkBudgeted::kYes,
+                                                       profile.get(), 0);
+            if (!blurProfile) {
+                return nullptr;
+            }
+
+            SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin);
+            resourceProvider->assignUniqueKeyToProxy(key, blurProfile.get());
+        }
+
+        return blurProfile;
+    }
+    SkRect rect() const { return fRect; }
+    float sigma() const { return fSigma; }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(GrResourceProvider* resourceProvider,
+                                                     const SkRect& rect, float sigma) {
+        int doubleProfileSize = SkScalarCeilToInt(12 * sigma);
+
+        if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
+            // if the blur sigma is too large so the gaussian overlaps the whole
+            // rect in either direction, fall back to CPU path for now.
+            return nullptr;
+        }
+
+        sk_sp<GrTextureProxy> blurProfile(CreateBlurProfileTexture(resourceProvider, sigma));
+        if (!blurProfile) {
+            return nullptr;
+        }
+
+        return std::unique_ptr<GrFragmentProcessor>(
+                new GrRectBlurEffect(rect, sigma, std::move(blurProfile)));
+    }
+    GrRectBlurEffect(const GrRectBlurEffect& src);
+    std::unique_ptr<GrFragmentProcessor> clone() const override;
+    const char* name() const override { return "RectBlurEffect"; }
+
+private:
+    GrRectBlurEffect(SkRect rect, float sigma, sk_sp<GrTextureProxy> blurProfile)
+            : INHERITED(kGrRectBlurEffect_ClassID,
+                        (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag)
+            , fRect(rect)
+            , fSigma(sigma)
+            , fBlurProfile(std::move(blurProfile)) {
+        this->addTextureSampler(&fBlurProfile);
+    }
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+    SkRect fRect;
+    float fSigma;
+    TextureSampler fBlurProfile;
+    typedef GrFragmentProcessor INHERITED;
+};
+#endif
+#endif
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 2c44ce4..c3634f5 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -23,6 +23,10 @@
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
         const GrSimpleTextureEffect& _outer = args.fFp.cast<GrSimpleTextureEffect>();
         (void)_outer;
+        auto colorXform = _outer.colorXform();
+        (void)colorXform;
+        auto matrix = _outer.matrix();
+        (void)matrix;
         fColorSpaceHelper.emitCode(args.fUniformHandler, _outer.colorXform().get());
         SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);
         fragBuilder->codeAppendf(
diff --git a/src/sksl/SkSLCPP.h b/src/sksl/SkSLCPP.h
index 808e832..d679908 100644
--- a/src/sksl/SkSLCPP.h
+++ b/src/sksl/SkSLCPP.h
@@ -10,8 +10,11 @@
 
 // functions used by CPP programs created by skslc
 
+#include <cmath>
 #include "SkPoint.h"
 
+using std::abs;
+
 // macros to make sk_Caps.<cap name> work from C++ code
 #define sk_Caps (*args.fShaderCaps)
 
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index a7008400..0b2ef78 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -148,10 +148,15 @@
         this->write(type.name() + "(%f, %f)");
         fFormatArgs.push_back(cppCode + ".fX");
         fFormatArgs.push_back(cppCode + ".fY");
+    } else if (type == *fContext.fFloat4_Type || type == *fContext.fHalf4_Type) {
+        this->write(type.name() + "(%f, %f, %f, %f)");
+        fFormatArgs.push_back(cppCode + ".left()");
+        fFormatArgs.push_back(cppCode + ".top()");
+        fFormatArgs.push_back(cppCode + ".right()");
+        fFormatArgs.push_back(cppCode + ".bottom()");
     } else {
-        this->write(type.name());
-        this->write("\n");
-        ABORT("unsupported runtime value type\n");
+        printf("unsupported runtime value type '%s'\n", String(type.fName).c_str());
+        ASSERT(false);
     }
 }
 
@@ -180,7 +185,26 @@
     this->write(to_string((int32_t) i.fValue));
 }
 
+void CPPCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
+    if (fCPPMode) {
+        ASSERT(swizzle.fComponents.size() == 1); // no support for multiple swizzle components yet
+        this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
+        switch (swizzle.fComponents[0]) {
+            case 0: this->write(".left()");   break;
+            case 1: this->write(".top()");    break;
+            case 2: this->write(".right()");  break;
+            case 3: this->write(".bottom()"); break;
+        }
+    } else {
+        INHERITED::writeSwizzle(swizzle);
+    }
+}
+
 void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
+    if (fCPPMode) {
+        this->write(ref.fVariable.fName);
+        return;
+    }
     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
         case SK_INCOLOR_BUILTIN:
             this->write("%s");
@@ -434,15 +458,22 @@
             for (const auto& raw : decls->fVars) {
                 VarDeclaration& decl = (VarDeclaration&) *raw;
                 if (is_private(*decl.fVar) && decl.fValue) {
-                    this->writef("%s = %s;\n",
-                                 String(decl.fVar->fName).c_str(),
-                                 decl.fValue->description().c_str());
+                    this->writef("%s = ", String(decl.fVar->fName).c_str());
+                    fCPPMode = true;
+                    this->writeExpression(*decl.fValue, kAssignment_Precedence);
+                    fCPPMode = false;
+                    this->write(";\n");
                 }
             }
         }
     }
 }
 
+static bool is_accessible(const Variable& var) {
+    return Type::kSampler_Kind != var.fType.kind() &&
+           Type::kOther_Kind != var.fType.kind();
+}
+
 void CPPCodeGenerator::writeCodeAppend(const String& code) {
     // codeAppendf can only handle appending 1024 bytes at a time, so we need to break the string
     // into chunks. Unfortunately we can't tell exactly how long the string is going to end up,
@@ -484,6 +515,22 @@
     this->writef("        const %s& _outer = args.fFp.cast<%s>();\n"
                  "        (void) _outer;\n",
                  fFullName.c_str(), fFullName.c_str());
+    for (const auto& p : fProgram.fElements) {
+        if (ProgramElement::kVar_Kind == p->fKind) {
+            const VarDeclarations* decls = (const VarDeclarations*) p.get();
+            for (const auto& raw : decls->fVars) {
+                VarDeclaration& decl = (VarDeclaration&) *raw;
+                String nameString(decl.fVar->fName);
+                const char* name = nameString.c_str();
+                if (SectionAndParameterHelper::IsParameter(*decl.fVar) &&
+                    is_accessible(*decl.fVar)) {
+                    this->writef("        auto %s = _outer.%s();\n"
+                                 "        (void) %s;\n",
+                                 name, name, name);
+                }
+            }
+        }
+    }
     this->writePrivateVarValues();
     for (const auto u : uniforms) {
         this->addUniform(*u);
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index ea4d030..a93b885 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -41,6 +41,8 @@
 
     void writeIntLiteral(const IntLiteral& i) override;
 
+    void writeSwizzle(const Swizzle& swizzle) override;
+
     void writeVariableReference(const VariableReference& ref) override;
 
     String getSamplerHandle(const Variable& var);
@@ -87,6 +89,8 @@
     std::vector<String> fFormatArgs;
     std::set<int> fWrittenTransformedCoords;
     bool fNeedColorSpaceHelper = false;
+    // if true, we are writing a C++ expression instead of a GLSL expression
+    bool fCPPMode = false;
 
     typedef GLSLCodeGenerator INHERITED;
 };
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 7c736b3..e9a63ac 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -142,7 +142,7 @@
 
     void writeFieldAccess(const FieldAccess& f);
 
-    void writeSwizzle(const Swizzle& swizzle);
+    virtual void writeSwizzle(const Swizzle& swizzle);
 
     static Precedence GetBinaryPrecedence(Token::Kind op);
 
diff --git a/src/sksl/ir/SkSLLayout.h b/src/sksl/ir/SkSLLayout.h
index 8bf0472..dc67628 100644
--- a/src/sksl/ir/SkSLLayout.h
+++ b/src/sksl/ir/SkSLLayout.h
@@ -232,18 +232,6 @@
             result += separator + "when = " + fWhen;
             separator = ", ";
         }
-        switch (fKey) {
-            case kNo_Key:
-                break;
-            case kKey_Key:
-                result += separator + "key";
-                separator = ", ";
-                break;
-            case kIdentity_Key:
-                result += separator + "key=identity";
-                separator = ", ";
-                break;
-        }
         if (result.size() > 0) {
             result = "layout (" + result + ")";
         }