Make GrGLEffects use an interface to append their code.

A small step towards encapsulating GrGLShaderBuilder.
Review URL: https://codereview.chromium.org/12547012

git-svn-id: http://skia.googlecode.com/svn/trunk@8018 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkString.h b/include/core/SkString.h
index db32dca..e5a2d30 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -185,6 +185,7 @@
 
     void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
     void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
+    void appendf(const char format[], va_list);
     void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
 
     void remove(size_t offset, size_t length);
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index 5d1b8ce..3f9a99f 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -531,6 +531,13 @@
     this->append(buffer, strlen(buffer));
 }
 
+void SkString::appendf(const char format[], va_list args) {
+    char    buffer[kBufferSize];
+    VSNPRINTF(buffer, kBufferSize, format, args);
+
+    this->append(buffer, strlen(buffer));
+}
+
 void SkString::prependf(const char format[], ...) {
     char    buffer[kBufferSize];
     ARGS_TO_BUFFER(format, buffer, kBufferSize);
diff --git a/src/effects/SkBicubicImageFilter.cpp b/src/effects/SkBicubicImageFilter.cpp
index 992060c..8de68ae 100644
--- a/src/effects/SkBicubicImageFilter.cpp
+++ b/src/effects/SkBicubicImageFilter.cpp
@@ -226,7 +226,6 @@
                                            kMat44f_GrSLType, "Coefficients");
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
-    SkString* code = &builder->fFSCode;
 
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
     const char* coeff = builder->getUniformCStr(fCoefficientsUni);
@@ -250,19 +249,21 @@
                           "\tvec4 c = coefficients * ts;\n"
                           "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
                           &cubicBlendName);
-    code->appendf("\tvec2 coord = %s - %s * vec2(0.5, 0.5);\n", coords, imgInc);
-    code->appendf("\tvec2 f = fract(coord / %s);\n", imgInc);
+    builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5, 0.5);\n", coords, imgInc);
+    builder->fsCodeAppendf("\tvec2 f = fract(coord / %s);\n", imgInc);
     for (int y = 0; y < 4; ++y) {
         for (int x = 0; x < 4; ++x) {
             SkString coord;
             coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1);
-            code->appendf("\tvec4 s%d%d = ", x, y);
-            builder->appendTextureLookup(&builder->fFSCode, samplers[0], coord.c_str());
-            code->appendf(";\n");
+            builder->fsCodeAppendf("\tvec4 s%d%d = ", x, y);
+            builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                         samplers[0],
+                                         coord.c_str());
+            builder->fsCodeAppend(";\n");
         }
-        code->appendf("\tvec4 s%d = %s(%s, f.x, s0%d, s1%d, s2%d, s3%d);\n", y, cubicBlendName.c_str(), coeff, y, y, y, y);
+        builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, s0%d, s1%d, s2%d, s3%d);\n", y, cubicBlendName.c_str(), coeff, y, y, y, y);
     }
-    code->appendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
+    builder->fsCodeAppendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
 }
 
 GrGLEffect::EffectKey GrGLBicubicEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp
index c8c4c1b..ae129eb 100644
--- a/src/effects/SkBlendImageFilter.cpp
+++ b/src/effects/SkBlendImageFilter.cpp
@@ -246,34 +246,39 @@
     GrSLType bgCoordsType =  fBackgroundEffectMatrix.emitCode(
         builder, key, vertexCoords, &bgCoords, NULL, "BG");
 
-    SkString* code = &builder->fFSCode;
     const char* bgColor = "bgColor";
     const char* fgColor = "fgColor";
 
-    code->appendf("\t\tvec4 %s = ", fgColor);
-    builder->appendTextureLookup(code, samplers[0], fgCoords, fgCoordsType);
-    code->append(";\n");
+    builder->fsCodeAppendf("\t\tvec4 %s = ", fgColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                 samplers[0],
+                                 fgCoords,
+                                 fgCoordsType);
+    builder->fsCodeAppend(";\n");
 
-    code->appendf("\t\tvec4 %s = ", bgColor);
-    builder->appendTextureLookup(code, samplers[1], bgCoords, bgCoordsType);
-    code->append(";\n");
+    builder->fsCodeAppendf("\t\tvec4 %s = ", bgColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                 samplers[1],
+                                 bgCoords,
+                                 bgCoordsType);
+    builder->fsCodeAppendf(";\n");
 
-    code->appendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", outputColor, bgColor, fgColor);
+    builder->fsCodeAppendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", outputColor, bgColor, fgColor);
     switch (fMode) {
       case SkBlendImageFilter::kNormal_Mode:
-        code->appendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + %s.rgb;\n", outputColor, fgColor, bgColor, fgColor);
+        builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + %s.rgb;\n", outputColor, fgColor, bgColor, fgColor);
         break;
       case SkBlendImageFilter::kMultiply_Mode:
-        code->appendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb + %s.rgb * %s.rgb;\n", outputColor, fgColor, bgColor, bgColor, fgColor, fgColor, bgColor);
+        builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb + %s.rgb * %s.rgb;\n", outputColor, fgColor, bgColor, bgColor, fgColor, fgColor, bgColor);
         break;
       case SkBlendImageFilter::kScreen_Mode:
-        code->appendf("\t\t%s.rgb = %s.rgb + %s.rgb - %s.rgb * %s.rgb;\n", outputColor, bgColor, fgColor, fgColor, bgColor);
+        builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - %s.rgb * %s.rgb;\n", outputColor, bgColor, fgColor, fgColor, bgColor);
         break;
       case SkBlendImageFilter::kDarken_Mode:
-        code->appendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
+        builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
         break;
       case SkBlendImageFilter::kLighten_Mode:
-        code->appendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
+        builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
         break;
     }
 }
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index 73e9616..b39c5f8 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -414,13 +414,13 @@
             }
             // The max() is to guard against 0 / 0 during unpremul when the incoming color is
             // transparent black.
-            builder->fFSCode.appendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
-            builder->fFSCode.appendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
-                                     outputColor,
-                                     builder->getUniformCStr(fMatrixHandle),
-                                     inputColor,
-                                     builder->getUniformCStr(fVectorHandle));
-            builder->fFSCode.appendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+            builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
+            builder->fsCodeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
+                                   outputColor,
+                                   builder->getUniformCStr(fMatrixHandle),
+                                   inputColor,
+                                   builder->getUniformCStr(fVectorHandle));
+            builder->fsCodeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor);
         }
 
         virtual void setData(const GrGLUniformManager& uniManager,
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index ee0906c..b270501 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -409,36 +409,38 @@
     GrSLType cCoordsType = fColorEffectMatrix.emitCode(
                                 builder, key, vertexCoords, &cCoordsIn, NULL, "COLOR");
 
-    SkString* code = &builder->fFSCode;
     const char* dColor = "dColor";
     const char* cCoords = "cCoords";
     const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use
                                    // a number smaller than that to approximate 0, but
                                    // leave room for 32-bit float GPU rounding errors.
 
-    code->appendf("\t\tvec4 %s = ", dColor);
-    builder->appendTextureLookup(code, samplers[0], dCoordsIn, dCoordsType);
-    code->append(";\n");
+    builder->fsCodeAppendf("\t\tvec4 %s = ", dColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                 samplers[0],
+                                 dCoordsIn,
+                                 dCoordsType);
+    builder->fsCodeAppend(";\n");
 
     // Unpremultiply the displacement
-    code->appendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
-                  dColor, dColor, nearZero, dColor, dColor);
+    builder->fsCodeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
+                           dColor, dColor, nearZero, dColor, dColor);
 
-    code->appendf("\t\tvec2 %s = %s + %s*(%s.",
-                  cCoords, cCoordsIn, scaleUni, dColor);
+    builder->fsCodeAppendf("\t\tvec2 %s = %s + %s*(%s.",
+                           cCoords, cCoordsIn, scaleUni, dColor);
 
     switch (fXChannelSelector) {
       case SkDisplacementMapEffect::kR_ChannelSelectorType:
-        code->append("r");
+        builder->fsCodeAppend("r");
         break;
       case SkDisplacementMapEffect::kG_ChannelSelectorType:
-        code->append("g");
+        builder->fsCodeAppend("g");
         break;
       case SkDisplacementMapEffect::kB_ChannelSelectorType:
-        code->append("b");
+        builder->fsCodeAppend("b");
         break;
       case SkDisplacementMapEffect::kA_ChannelSelectorType:
-        code->append("a");
+        builder->fsCodeAppend("a");
         break;
       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
       default:
@@ -447,30 +449,33 @@
 
     switch (fYChannelSelector) {
       case SkDisplacementMapEffect::kR_ChannelSelectorType:
-        code->append("r");
+        builder->fsCodeAppend("r");
         break;
       case SkDisplacementMapEffect::kG_ChannelSelectorType:
-        code->append("g");
+        builder->fsCodeAppend("g");
         break;
       case SkDisplacementMapEffect::kB_ChannelSelectorType:
-        code->append("b");
+        builder->fsCodeAppend("b");
         break;
       case SkDisplacementMapEffect::kA_ChannelSelectorType:
-        code->append("a");
+        builder->fsCodeAppend("a");
         break;
       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
       default:
         SkASSERT(!"Unknown Y channel selector");
     }
-    code->append("-vec2(0.5));\t\t");
+    builder->fsCodeAppend("-vec2(0.5));\t\t");
 
     // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
     //         a 0 border color instead of computing if cCoords is out of bounds here.
-    code->appendf(
+    builder->fsCodeAppendf(
         "%s = any(greaterThan(vec4(vec2(0.0), %s), vec4(%s, vec2(1.0)))) ? vec4(0.0) : ",
         outputColor, cCoords, cCoords);
-    builder->appendTextureLookup(code, samplers[1], cCoords, cCoordsType);
-    code->append(";\n");
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                 samplers[1],
+                                 cCoords,
+                                 cCoordsType);
+    builder->fsCodeAppend(";\n");
 }
 
 void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index e195262..177ba09 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -415,7 +415,7 @@
      * the FS. The default of emitLightColor appends the name of the constant light color uniform
      * and so this function only needs to be overridden if the light color varies spatially.
      */
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out, const char* z) = 0;
+    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
     virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
 
     // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
@@ -441,7 +441,7 @@
 public:
     virtual ~GrGLDistantLight() {}
     virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out,  const char* z) SK_OVERRIDE;
+    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
 private:
     typedef GrGLLight INHERITED;
     UniformHandle fDirectionUni;
@@ -453,7 +453,7 @@
 public:
     virtual ~GrGLPointLight() {}
     virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out, const char* z) SK_OVERRIDE;
+    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
 private:
     typedef GrGLLight INHERITED;
     SkPoint3 fLocation;
@@ -466,7 +466,7 @@
 public:
     virtual ~GrGLSpotLight() {}
     virtual void setData(const GrGLUniformManager&, const SkLight* light) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, SkString* out, const char* z) SK_OVERRIDE;
+    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
     virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
 private:
     typedef GrGLLight INHERITED;
@@ -1122,7 +1122,6 @@
                                            kFloat_GrSLType,
                                            "SurfaceScale");
     fLight->emitLightColorUniform(builder);
-    SkString* code = &builder->fFSCode;
     SkString lightFunc;
     this->emitLightFunc(builder, &lightFunc);
     static const GrGLShaderVar gSobelArgs[] =  {
@@ -1176,8 +1175,8 @@
                           interiorNormalBody.c_str(),
                           &interiorNormalName);
 
-    code->appendf("\t\tvec2 coord = %s;\n", coords);
-    code->appendf("\t\tfloat m[9];\n");
+    builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords);
+    builder->fsCodeAppend("\t\tfloat m[9];\n");
 
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
     const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
@@ -1187,21 +1186,25 @@
         for (int dx = -1; dx <= 1; dx++) {
             SkString texCoords;
             texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
-            code->appendf("\t\tm[%d] = ", index++);
-            builder->appendTextureLookup(code, samplers[0], texCoords.c_str());
-            code->appendf(".a;\n");
+            builder->fsCodeAppendf("\t\tm[%d] = ", index++);
+            builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                         samplers[0],
+                                         texCoords.c_str());
+            builder->fsCodeAppend(".a;\n");
         }
     }
-    code->appendf("\t\tvec3 surfaceToLight = ");
+    builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
     SkString arg;
     arg.appendf("%s * m[4]", surfScale);
-    fLight->emitSurfaceToLight(builder, code, arg.c_str());
-    code->append(";\n");
-    code->appendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
-                  outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
+    fLight->emitSurfaceToLight(builder, arg.c_str());
+    builder->fsCodeAppend(";\n");
+    builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
+                           outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
     fLight->emitLightColor(builder, "surfaceToLight");
-    code->append(");\n");
-    GrGLSLMulVarBy4f(code, 2, outputColor, inputColor);
+    builder->fsCodeAppend(");\n");
+    SkString modulate;
+    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+    builder->fsCodeAppend(modulate.c_str());
 }
 
 GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrEffectStage& s,
@@ -1354,7 +1357,7 @@
 
 void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
                                const char *surfaceToLight) {
-    builder->fFSCode.append(builder->getUniformCStr(this->lightColorUni()));
+    builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
 }
 
 void GrGLLight::setData(const GrGLUniformManager& uman,
@@ -1371,13 +1374,11 @@
     setUniformNormal3(uman, fDirectionUni, distantLight->direction());
 }
 
-void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
-                                          SkString* out,
-                                          const char* z) {
+void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
     const char* dir;
     fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
                                         "LightDirection", &dir);
-    out->append(dir);
+    builder->fsCodeAppend(dir);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1390,13 +1391,11 @@
     setUniformPoint3(uman, fLocationUni, pointLight->location());
 }
 
-void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
-                                        SkString* out,
-                                        const char* z) {
+void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
     const char* loc;
     fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType, kVec3f_GrSLType,
                                        "LightLocation", &loc);
-    out->appendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
+    builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1414,13 +1413,12 @@
     setUniformNormal3(uman, fSUni, spotLight->s());
 }
 
-void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder,
-                                       SkString* out,
-                                       const char* z) {
+void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
     const char* location;
     fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                        kVec3f_GrSLType, "LightLocation", &location);
-    out->appendf("normalize(%s - vec3(%s.xy, %s))", location, builder->fragmentPosition(), z);
+    builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
+                           location, builder->fragmentPosition(), z);
 }
 
 void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
@@ -1466,7 +1464,7 @@
                           lightColorBody.c_str(),
                           &fLightColorFunc);
 
-    builder->fFSCode.appendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
+    builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
 }
 
 #endif
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index b577a1d..d8455ad 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -148,36 +148,36 @@
         GrGLShaderBuilder::kVertex_ShaderType,
         kVec2f_GrSLType, "uInset");
 
-    SkString* code = &builder->fFSCode;
+    builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords);
+    builder->fsCodeAppendf("\t\tvec2 zoom_coord = %s + %s / %s;\n",
+                           builder->getUniformCStr(fOffsetVar),
+                            coords,
+                           builder->getUniformCStr(fZoomVar));
 
-    code->appendf("\t\tvec2 coord = %s;\n", coords);
-    code->appendf("\t\tvec2 zoom_coord = %s + %s / %s;\n",
-                  builder->getUniformCStr(fOffsetVar),
-                  coords,
-                  builder->getUniformCStr(fZoomVar));
+    builder->fsCodeAppend("\t\tvec2 delta = min(coord, vec2(1.0, 1.0) - coord);\n");
 
-    code->appendf("\t\tvec2 delta = min(coord, vec2(1.0, 1.0) - coord);\n");
+    builder->fsCodeAppendf("\t\tdelta = delta / %s;\n", builder->getUniformCStr(fInsetVar));
 
-    code->appendf("\t\tdelta = delta / %s;\n", builder->getUniformCStr(fInsetVar));
+    builder->fsCodeAppend("\t\tfloat weight = 0.0;\n");
+    builder->fsCodeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n");
+    builder->fsCodeAppend("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n");
+    builder->fsCodeAppend("\t\t\tfloat dist = length(delta);\n");
+    builder->fsCodeAppend("\t\t\tdist = max(2.0 - dist, 0.0);\n");
+    builder->fsCodeAppend("\t\t\tweight = min(dist * dist, 1.0);\n");
+    builder->fsCodeAppend("\t\t} else {\n");
+    builder->fsCodeAppend("\t\t\tvec2 delta_squared = delta * delta;\n");
+    builder->fsCodeAppend("\t\t\tweight = min(min(delta_squared.s, delta_squared.y), 1.0);\n");
+    builder->fsCodeAppend("\t\t}\n");
 
-    code->appendf("\t\tfloat weight = 0.0;\n");
-    code->appendf("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n");
-    code->appendf("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n");
-    code->appendf("\t\t\tfloat dist = length(delta);\n");
-    code->appendf("\t\t\tdist = max(2.0 - dist, 0.0);\n");
-    code->appendf("\t\t\tweight = min(dist * dist, 1.0);\n");
-    code->appendf("\t\t} else {\n");
-    code->appendf("\t\t\tvec2 delta_squared = delta * delta;\n");
-    code->appendf("\t\t\tweight = min(min(delta_squared.s, delta_squared.y), 1.0);\n");
-    code->appendf("\t\t}\n");
+    builder->fsCodeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n");
+    builder->fsCodeAppend("\t\tvec4 output_color = ");
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "mix_coord");
+    builder->fsCodeAppend(";\n");
 
-    code->appendf("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n");
-    code->appendf("\t\tvec4 output_color = ");
-    builder->appendTextureLookup(code, samplers[0], "mix_coord");
-    code->append(";\n");
-
-    code->appendf("\t\t%s = output_color;", outputColor);
-    GrGLSLMulVarBy4f(code, 2, outputColor, inputColor);
+    builder->fsCodeAppendf("\t\t%s = output_color;", outputColor);
+    SkString modulate;
+    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+    builder->fsCodeAppend(modulate.c_str());
 }
 
 void GrGLMagnifierEffect::setData(const GrGLUniformManager& uman,
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index 0addc23..cda4f28 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -365,7 +365,6 @@
                                 const GrGLShaderBuilder::TextureSampler& sampler,
                                 const char* coord,
                                 SkMatrixConvolutionImageFilter::TileMode tileMode) {
-    SkString* code = &builder->fFSCode;
     SkString clampedCoord;
     switch (tileMode) {
         case SkMatrixConvolutionImageFilter::kClamp_TileMode:
@@ -377,10 +376,10 @@
             coord = clampedCoord.c_str();
             break;
         case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode:
-            code->appendf("clamp(%s, 0.0, 1.0) != %s ? vec4(0, 0, 0, 0) : ", coord, coord);
+            builder->fsCodeAppendf("clamp(%s, 0.0, 1.0) != %s ? vec4(0, 0, 0, 0) : ", coord, coord);
             break;
     }
-    builder->appendTextureLookup(code, sampler, coord);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, sampler, coord);
 }
 
 void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
@@ -403,8 +402,6 @@
     fBiasUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                    kFloat_GrSLType, "Bias");
 
-    SkString* code = &builder->fFSCode;
-
     const char* target = builder->getUniformCStr(fTargetUni);
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
     const char* kernel = builder->getUniformCStr(fKernelUni);
@@ -413,31 +410,31 @@
     int kWidth = fKernelSize.width();
     int kHeight = fKernelSize.height();
 
-    code->appendf("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
-    code->appendf("\t\tvec2 coord = %s - %s * %s;\n", coords, target, imgInc);
-    code->appendf("\t\tfor (int y = 0; y < %d; y++) {\n", kHeight);
-    code->appendf("\t\t\tfor (int x = 0; x < %d; x++) {\n", kWidth);
-    code->appendf("\t\t\t\tfloat k = %s[y * %d + x];\n", kernel, kWidth);
-    code->appendf("\t\t\t\tvec2 coord2 = coord + vec2(x, y) * %s;\n", imgInc);
-    code->appendf("\t\t\t\tvec4 c = ");
+    builder->fsCodeAppend("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
+    builder->fsCodeAppendf("\t\tvec2 coord = %s - %s * %s;\n", coords, target, imgInc);
+    builder->fsCodeAppendf("\t\tfor (int y = 0; y < %d; y++) {\n", kHeight);
+    builder->fsCodeAppendf("\t\t\tfor (int x = 0; x < %d; x++) {\n", kWidth);
+    builder->fsCodeAppendf("\t\t\t\tfloat k = %s[y * %d + x];\n", kernel, kWidth);
+    builder->fsCodeAppendf("\t\t\t\tvec2 coord2 = coord + vec2(x, y) * %s;\n", imgInc);
+    builder->fsCodeAppend("\t\t\t\tvec4 c = ");
     appendTextureLookup(builder, samplers[0], "coord2", fTileMode);
-    code->appendf(";\n");
+    builder->fsCodeAppend(";\n");
     if (!fConvolveAlpha) {
-        code->appendf("\t\t\t\tc.rgb /= c.a;\n");
+        builder->fsCodeAppend("\t\t\t\tc.rgb /= c.a;\n");
     }
-    code->appendf("\t\t\t\tsum += c * k;\n");
-    code->appendf("\t\t\t}\n");
-    code->appendf("\t\t}\n");
+    builder->fsCodeAppend("\t\t\t\tsum += c * k;\n");
+    builder->fsCodeAppend("\t\t\t}\n");
+    builder->fsCodeAppend("\t\t}\n");
     if (fConvolveAlpha) {
-        code->appendf("\t\t%s = sum * %s + %s;\n", outputColor, gain, bias);
-        code->appendf("\t\t%s.rgb = clamp(%s.rgb, 0.0, %s.a);\n", outputColor, outputColor, outputColor);
+        builder->fsCodeAppendf("\t\t%s = sum * %s + %s;\n", outputColor, gain, bias);
+        builder->fsCodeAppendf("\t\t%s.rgb = clamp(%s.rgb, 0.0, %s.a);\n", outputColor, outputColor, outputColor);
     } else {
-        code->appendf("\t\tvec4 c = ");
+        builder->fsCodeAppend("\t\tvec4 c = ");
         appendTextureLookup(builder, samplers[0], coords, fTileMode);
-        code->appendf(";\n");
-        code->appendf("\t\t%s.a = c.a;\n", outputColor);
-        code->appendf("\t\t%s.rgb = sum.rgb * %s + %s;\n", outputColor, gain, bias);
-        code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+        builder->fsCodeAppend(";\n");
+        builder->fsCodeAppendf("\t\t%s.a = c.a;\n", outputColor);
+        builder->fsCodeAppendf("\t\t%s.rgb = sum.rgb * %s + %s;\n", outputColor, gain, bias);
+        builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
     }
 }
 
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index b40130b..7bb4c93 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -324,16 +324,14 @@
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
 
-    SkString* code = &builder->fFSCode;
-
     const char* func;
     switch (fType) {
         case GrMorphologyEffect::kErode_MorphologyType:
-            code->appendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor);
+            builder->fsCodeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor);
             func = "min";
             break;
         case GrMorphologyEffect::kDilate_MorphologyType:
-            code->appendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
+            builder->fsCodeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
             func = "max";
             break;
         default:
@@ -343,14 +341,16 @@
     }
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
 
-    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
-    code->appendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
-    code->appendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
-    builder->appendTextureLookup(&builder->fFSCode, samplers[0], "coord");
-    code->appendf(");\n");
-    code->appendf("\t\t\tcoord += %s;\n", imgInc);
-    code->appendf("\t\t}\n");
-    GrGLSLMulVarBy4f(code, 2, outputColor, inputColor);
+    builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
+    builder->fsCodeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
+    builder->fsCodeAppendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "coord");
+    builder->fsCodeAppend(");\n");
+    builder->fsCodeAppendf("\t\t\tcoord += %s;\n", imgInc);
+    builder->fsCodeAppend("\t\t}\n");
+    SkString modulate;
+    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+    builder->fsCodeAppend(modulate.c_str());
 }
 
 GrGLEffect::EffectKey GrGLMorphologyEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index cf7ddc5..16f2876 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -289,39 +289,38 @@
 
     static const float kColorScaleFactor = 255.0f / 256.0f;
     static const float kColorOffsetFactor = 1.0f / 512.0f;
-    SkString* code = &builder->fFSCode;
     if (NULL == inputColor) {
         // the input color is solid white (all ones).
         static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
-        code->appendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
-                      kMaxValue, kMaxValue, kMaxValue, kMaxValue);
+        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
+                               kMaxValue, kMaxValue, kMaxValue, kMaxValue);
 
     } else {
-        code->appendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
-        code->appendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
-        code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
-                      kColorScaleFactor,
-                      kColorOffsetFactor, kColorOffsetFactor,
-                      kColorOffsetFactor, kColorOffsetFactor);
+        builder->fsCodeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
+        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
+        builder->fsCodeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
+                              kColorScaleFactor,
+                              kColorOffsetFactor, kColorOffsetFactor,
+                              kColorOffsetFactor, kColorOffsetFactor);
     }
 
-    code->appendf("\t\t%s.a = ", outputColor);
-    builder->appendTextureLookup(code, samplers[0], "vec2(coord.a, 0.125)");
-    code->append(";\n");
+    builder->fsCodeAppendf("\t\t%s.a = ", outputColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.a, 0.125)");
+    builder->fsCodeAppend(";\n");
 
-    code->appendf("\t\t%s.r = ", outputColor);
-    builder->appendTextureLookup(code, samplers[0], "vec2(coord.r, 0.375)");
-    code->append(";\n");
+    builder->fsCodeAppendf("\t\t%s.r = ", outputColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.r, 0.375)");
+    builder->fsCodeAppend(";\n");
 
-    code->appendf("\t\t%s.g = ", outputColor);
-    builder->appendTextureLookup(code, samplers[0], "vec2(coord.g, 0.625)");
-    code->append(";\n");
+    builder->fsCodeAppendf("\t\t%s.g = ", outputColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.g, 0.625)");
+    builder->fsCodeAppend(";\n");
 
-    code->appendf("\t\t%s.b = ", outputColor);
-    builder->appendTextureLookup(code, samplers[0], "vec2(coord.b, 0.875)");
-    code->append(";\n");
+    builder->fsCodeAppendf("\t\t%s.b = ", outputColor);
+    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.b, 0.875)");
+    builder->fsCodeAppend(";\n");
 
-    code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+    builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
 }
 
 GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrEffectStage&, const GrGLCaps&) {
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 261ad8f..1158dcf 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -787,13 +787,15 @@
                                          const char* inputColor,
                                          const GrGLShaderBuilder::TextureSampler& sampler) {
 
-    SkString* code = &builder->fFSCode;
-    code->appendf("\tvec2 coord = vec2(%s, %s);\n",
-                  gradientTValue,
-                  builder->getUniformVariable(fFSYUni).c_str());
-    code->appendf("\t%s = ", outputColor);
-    builder->appendTextureLookupAndModulate(code, inputColor, sampler, "coord");
-    code->append(";\n");
+    builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n",
+                           gradientTValue,
+                           builder->getUniformVariable(fFSYUni).c_str());
+    builder->fsCodeAppendf("\t%s = ", outputColor);
+    builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
+                                            inputColor,
+                                            sampler,
+                                            "coord");
+    builder->fsCodeAppend(";\n");
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index 1496033..f56e7b4 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -513,7 +513,6 @@
 
     // VS
     {
-        SkString* code = &builder->fVSCode;
         SkString p2; // distance between centers
         SkString p3; // start radius
         SkString p5; // difference in radii (r1 - r0)
@@ -525,15 +524,14 @@
         // part of the quadratic as a varying.
         if (kVec2f_GrSLType == coordsVaryingType) {
             // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5])
-            code->appendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n",
-                          fVSVaryingName, p2.c_str(),
-                          vsCoordsVarying, p3.c_str(), p5.c_str());
+            builder->vsCodeAppendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n",
+                                   fVSVaryingName, p2.c_str(),
+                                   vsCoordsVarying, p3.c_str(), p5.c_str());
         }
     }
 
     // FS
     {
-        SkString* code = &builder->fFSCode;
 
         SkString cName("c");
         SkString ac4Name("ac4");
@@ -563,92 +561,92 @@
             bVar = fFSVaryingName;
         } else {
             bVar = "b";
-            code->appendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n",
-                          bVar.c_str(), p2.c_str(), fsCoords,
-                          p3.c_str(), p5.c_str());
+            builder->fsCodeAppendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n",
+                                   bVar.c_str(), p2.c_str(), fsCoords,
+                                   p3.c_str(), p5.c_str());
         }
 
         // output will default to transparent black (we simply won't write anything
         // else to it if invalid, instead of discarding or returning prematurely)
-        code->appendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
+        builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
 
         // c = (x^2)+(y^2) - params[4]
-        code->appendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(),
-                      fsCoords, fsCoords,
-                      p4.c_str());
+        builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(),
+                               fsCoords, fsCoords,
+                               p4.c_str());
 
         // Non-degenerate case (quadratic)
         if (!fIsDegenerate) {
 
             // ac4 = params[0] * c
-            code->appendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(),
-                          cName.c_str());
+            builder->fsCodeAppendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(),
+                                   cName.c_str());
 
             // d = b^2 - ac4
-            code->appendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(),
-                          bVar.c_str(), bVar.c_str(), ac4Name.c_str());
+            builder->fsCodeAppendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(),
+                                   bVar.c_str(), bVar.c_str(), ac4Name.c_str());
 
             // only proceed if discriminant is >= 0
-            code->appendf("\tif (%s >= 0.0) {\n", dName.c_str());
+            builder->fsCodeAppendf("\tif (%s >= 0.0) {\n", dName.c_str());
 
             // intermediate value we'll use to compute the roots
             // q = -0.5 * (b +/- sqrt(d))
-            code->appendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)"
-                          " * sqrt(%s));\n", qName.c_str(), bVar.c_str(),
-                          bVar.c_str(), dName.c_str());
+            builder->fsCodeAppendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)"
+                                   " * sqrt(%s));\n", qName.c_str(), bVar.c_str(),
+                                   bVar.c_str(), dName.c_str());
 
             // compute both roots
             // r0 = q * params[1]
-            code->appendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(),
-                          qName.c_str(), p1.c_str());
+            builder->fsCodeAppendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(),
+                                   qName.c_str(), p1.c_str());
             // r1 = c / q
-            code->appendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
-                          cName.c_str(), qName.c_str());
+            builder->fsCodeAppendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
+                                   cName.c_str(), qName.c_str());
 
             // Note: If there are two roots that both generate radius(t) > 0, the
             // Canvas spec says to choose the larger t.
 
             // so we'll look at the larger one first:
-            code->appendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
-                          r0Name.c_str(), r1Name.c_str());
+            builder->fsCodeAppendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
+                                   r0Name.c_str(), r1Name.c_str());
 
             // if r(t) > 0, then we're done; t will be our x coordinate
-            code->appendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
-                          p5.c_str(), p3.c_str());
+            builder->fsCodeAppendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
+                                   p5.c_str(), p3.c_str());
 
-            code->appendf("\t\t");
+            builder->fsCodeAppend("\t\t");
             this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
 
             // otherwise, if r(t) for the larger root was <= 0, try the other root
-            code->appendf("\t\t} else {\n");
-            code->appendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
-                          r0Name.c_str(), r1Name.c_str());
+            builder->fsCodeAppend("\t\t} else {\n");
+            builder->fsCodeAppendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
+                                   r0Name.c_str(), r1Name.c_str());
 
             // if r(t) > 0 for the smaller root, then t will be our x coordinate
-            code->appendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
-                          tName.c_str(), p5.c_str(), p3.c_str());
+            builder->fsCodeAppendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
+                                   tName.c_str(), p5.c_str(), p3.c_str());
 
-            code->appendf("\t\t\t");
+            builder->fsCodeAppend("\t\t\t");
             this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
 
             // end if (r(t) > 0) for smaller root
-            code->appendf("\t\t\t}\n");
+            builder->fsCodeAppend("\t\t\t}\n");
             // end if (r(t) > 0), else, for larger root
-            code->appendf("\t\t}\n");
+            builder->fsCodeAppend("\t\t}\n");
             // end if (discriminant >= 0)
-            code->appendf("\t}\n");
+            builder->fsCodeAppend("\t}\n");
         } else {
 
             // linear case: t = -c/b
-            code->appendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
-                          cName.c_str(), bVar.c_str());
+            builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
+                                   cName.c_str(), bVar.c_str());
 
             // if r(t) > 0, then t will be the x coordinate
-            code->appendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
-                          p5.c_str(), p3.c_str());
-            code->appendf("\t");
+            builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
+                                   p5.c_str(), p3.c_str());
+            builder->fsCodeAppend("\t");
             this->emitColorLookup(builder, tName.c_str(), outputColor, inputColor, samplers[0]);
-            code->appendf("\t}\n");
+            builder->fsCodeAppend("\t}\n");
         }
     }
 }
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 6bb475a..40e2ac3 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -560,7 +560,6 @@
 
     // VS
     {
-        SkString* code = &builder->fVSCode;
         SkString p2;
         SkString p3;
         builder->getUniformVariable(fVSParamUni).appendArrayAccess(2, &p2);
@@ -570,15 +569,14 @@
         // part of the quadratic as a varying.
         if (kVec2f_GrSLType == coordsVaryingType) {
             // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
-            code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
-                          fVSVaryingName, p2.c_str(),
-                          vsCoordsVarying, p3.c_str());
+            builder->vsCodeAppendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
+                                   fVSVaryingName, p2.c_str(),
+                                   vsCoordsVarying, p3.c_str());
         }
     }
 
     // FS
     {
-        SkString* code = &builder->fFSCode;
         SkString cName("c");
         SkString ac4Name("ac4");
         SkString rootName("root");
@@ -603,31 +601,31 @@
             bVar = fFSVaryingName;
         } else {
             bVar = "b";
-            code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
-                          bVar.c_str(), p2.c_str(), fsCoords, p3.c_str());
+            builder->fsCodeAppendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
+                                   bVar.c_str(), p2.c_str(), fsCoords, p3.c_str());
         }
 
         // c = (x^2)+(y^2) - params[4]
-        code->appendf("\tfloat %s = dot(%s, %s) - %s;\n",
-                      cName.c_str(),
-                      fsCoords,
-                      fsCoords,
-                      p4.c_str());
+        builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
+                               cName.c_str(),
+                               fsCoords,
+                               fsCoords,
+                               p4.c_str());
 
         // If we aren't degenerate, emit some extra code, and accept a slightly
         // more complex coord.
         if (!fIsDegenerate) {
 
             // ac4 = 4.0 * params[0] * c
-            code->appendf("\tfloat %s = %s * 4.0 * %s;\n",
-                          ac4Name.c_str(), p0.c_str(),
-                          cName.c_str());
+            builder->fsCodeAppendf("\tfloat %s = %s * 4.0 * %s;\n",
+                                   ac4Name.c_str(), p0.c_str(),
+                                   cName.c_str());
 
             // root = sqrt(b^2-4ac)
             // (abs to avoid exception due to fp precision)
-            code->appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
-                          rootName.c_str(), bVar.c_str(), bVar.c_str(),
-                          ac4Name.c_str());
+            builder->fsCodeAppendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
+                                   rootName.c_str(), bVar.c_str(), bVar.c_str(),
+                                   ac4Name.c_str());
 
             // t is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
             t.printf("(-%s + %s * %s) * %s", bVar.c_str(), p5.c_str(),
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 1dd51c8..f2c5d09 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -31,31 +31,34 @@
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
         const char* coords;
         GrSLType coordsType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coords);
-        builder->fFSCode.appendf("\t\t%s = ", outputColor);
-        builder->appendTextureLookup(&builder->fFSCode, samplers[0], coords, coordsType);
-        builder->fFSCode.append(";\n");
+        builder->fsCodeAppendf("\t\t%s = ", outputColor);
+        builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                     samplers[0],
+                                     coords,
+                                     coordsType);
+        builder->fsCodeAppend(";\n");
         if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) {
             GrAssert(fSwapRedAndBlue);
-            builder->fFSCode.appendf("\t%s = %s.bgra;\n", outputColor, outputColor);
+            builder->fsCodeAppendf("\t%s = %s.bgra;\n", outputColor, outputColor);
         } else {
             const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb";
             switch (fPMConversion) {
                 case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
-                    builder->fFSCode.appendf(
+                    builder->fsCodeAppendf(
                         "\t\t%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
-                    builder->fFSCode.appendf(
+                    builder->fsCodeAppendf(
                         "\t\t%s = vec4(floor(%s.%s * %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
-                    builder->fFSCode.appendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
+                    builder->fsCodeAppendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
-                    builder->fFSCode.appendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
+                    builder->fsCodeAppendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 default:
@@ -63,7 +66,9 @@
                     break;
             }
         }
-        GrGLSLMulVarBy4f(&builder->fFSCode, 2, outputColor, inputColor);
+        SkString modulate;
+        GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+        builder->fsCodeAppend(modulate.c_str());
     }
 
     void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 12c32f0..1c0e8f5 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -65,15 +65,14 @@
                                              kVec2f_GrSLType, "ImageIncrement");
     fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
                                           kFloat_GrSLType, "Kernel", this->width());
-    SkString* code = &builder->fFSCode;
 
-    code->appendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
+    builder->fsCodeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
 
     int width = this ->width();
     const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni);
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
 
-    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
+    builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
 
     // Manually unroll loop because some drivers don't; yields 20-30% speedup.
     for (int i = 0; i < width; i++) {
@@ -81,12 +80,14 @@
         SkString kernelIndex;
         index.appendS32(i);
         kernel.appendArrayAccess(index.c_str(), &kernelIndex);
-        code->appendf("\t\t%s += ", outputColor);
-        builder->appendTextureLookup(&builder->fFSCode, samplers[0], "coord");
-        code->appendf(" * %s;\n", kernelIndex.c_str());
-        code->appendf("\t\tcoord += %s;\n", imgInc);
+        builder->fsCodeAppendf("\t\t%s += ", outputColor);
+        builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "coord");
+        builder->fsCodeAppendf(" * %s;\n", kernelIndex.c_str());
+        builder->fsCodeAppendf("\t\tcoord += %s;\n", imgInc);
     }
-    GrGLSLMulVarBy4f(&builder->fFSCode, 2, outputColor, inputColor);
+    SkString modulate;
+    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+    builder->fsCodeAppend(modulate.c_str());
 }
 
 void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 0fe083b..58ac3c0 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -27,13 +27,13 @@
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
         const char* coordName;
         GrSLType coordType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coordName);
-        builder->fFSCode.appendf("\t%s = ", outputColor);
-        builder->appendTextureLookupAndModulate(&builder->fFSCode,
+        builder->fsCodeAppendf("\t%s = ", outputColor);
+        builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
                                                 inputColor,
                                                 samplers[0],
                                                 coordName,
                                                 coordType);
-        builder->fFSCode.append(";\n");
+        builder->fsCodeAppend(";\n");
     }
 
     static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp
index 3c70951..851bdcc 100644
--- a/src/gpu/effects/GrTextureDomainEffect.cpp
+++ b/src/gpu/effects/GrTextureDomainEffect.cpp
@@ -59,15 +59,15 @@
                                     kVec4f_GrSLType, "TexDom", &domain);
     if (GrTextureDomainEffect::kClamp_WrapMode == effect.wrapMode()) {
 
-        builder->fFSCode.appendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n",
-                               coords, domain, domain);
+        builder->fsCodeAppendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n",
+                                coords, domain, domain);
 
-        builder->fFSCode.appendf("\t%s = ", outputColor);
-        builder->appendTextureLookupAndModulate(&builder->fFSCode,
+        builder->fsCodeAppendf("\t%s = ", outputColor);
+        builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
                                                 inputColor,
                                                 samplers[0],
                                                 "clampCoord");
-        builder->fFSCode.append(";\n");
+        builder->fsCodeAppend(";\n");
     } else {
         GrAssert(GrTextureDomainEffect::kDecal_WrapMode == effect.wrapMode());
 
@@ -78,24 +78,30 @@
             // may return undefined results". This appears to be an issue with
             // the 'any' call since even the simple "result=black; if (any())
             // result=white;" code fails to compile.
-            builder->fFSCode.appendf("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
-            builder->fFSCode.appendf("\tvec4 inside = ");
-            builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplers[0], coords);
-            builder->fFSCode.appendf(";\n");
+            builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
+            builder->fsCodeAppend("\tvec4 inside = ");
+            builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
+                                                    inputColor,
+                                                    samplers[0],
+                                                    coords);
+            builder->fsCodeAppend(";\n");
 
-            builder->fFSCode.appendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n",
-                                     coords, domain, domain, domain);
-            builder->fFSCode.appendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n",
-                                     coords, domain, domain, domain);
-            builder->fFSCode.appendf("\tfloat blend = step(1.0, max(x, y));\n");
-            builder->fFSCode.appendf("\t%s = mix(inside, outside, blend);\n", outputColor);
+            builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n",
+                                   coords, domain, domain, domain);
+            builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n",
+                                   coords, domain, domain, domain);
+            builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n");
+            builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outputColor);
         } else {
-            builder->fFSCode.append("\tbvec4 outside;\n");
-            builder->fFSCode.appendf("\toutside.xy = lessThan(%s, %s.xy);\n", coords, domain);
-            builder->fFSCode.appendf("\toutside.zw = greaterThan(%s, %s.zw);\n", coords, domain);
-            builder->fFSCode.appendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outputColor);
-            builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplers[0], coords);
-            builder->fFSCode.append(";\n");
+            builder->fsCodeAppend("\tbvec4 outside;\n");
+            builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", coords, domain);
+            builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", coords, domain);
+            builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outputColor);
+            builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
+                                                    inputColor,
+                                                    samplers[0],
+                                                    coords);
+            builder->fsCodeAppend(";\n");
         }
     }
 }
diff --git a/src/gpu/gl/GrGLEffectMatrix.cpp b/src/gpu/gl/GrGLEffectMatrix.cpp
index 5fdde2c..c37098e 100644
--- a/src/gpu/gl/GrGLEffectMatrix.cpp
+++ b/src/gpu/gl/GrGLEffectMatrix.cpp
@@ -93,20 +93,20 @@
     switch (fUniType) {
         case kVoid_GrSLType:
             GrAssert(kVec2f_GrSLType == varyingType);
-            builder->fVSCode.appendf("\t%s = %s;\n", vsVaryingName, vertexCoords);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, vertexCoords);
             break;
         case kVec2f_GrSLType:
             GrAssert(kVec2f_GrSLType == varyingType);
-            builder->fVSCode.appendf("\t%s = %s + %s;\n", vsVaryingName, uniName, vertexCoords);
+            builder->vsCodeAppendf("\t%s = %s + %s;\n", vsVaryingName, uniName, vertexCoords);
             break;
         case kMat33f_GrSLType: {
             GrAssert(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
             if (kVec2f_GrSLType == varyingType) {
-                builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
-                                         vsVaryingName, uniName, vertexCoords);
+                builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
+                                       vsVaryingName, uniName, vertexCoords);
             } else {
-                builder->fVSCode.appendf("\t%s = %s * vec3(%s, 1);\n",
-                                         vsVaryingName, uniName, vertexCoords);
+                builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
+                                       vsVaryingName, uniName, vertexCoords);
             }
             break;
         }
@@ -150,8 +150,8 @@
             suffixedCoordName.append(suffix);
             coordName = suffixedCoordName.c_str();
         }
-        builder->fFSCode.appendf("\tvec2 %s = %s.xy / %s.z;",
-                                    coordName, fsVaryingName, fsVaryingName);
+        builder->fsCodeAppendf("\tvec2 %s = %s.xy / %s.z;",
+                               coordName, fsVaryingName, fsVaryingName);
         if (NULL != fsCoordName) {
             *fsCoordName = coordName;
         }
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 5c88441..2b6ccbd 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -398,7 +398,8 @@
  * Adds a line to the fragment shader code which modifies the color by
  * the specified color filter.
  */
-void add_color_filter(SkString* fsCode, const char * outputVar,
+void add_color_filter(GrGLShaderBuilder* builder,
+                      const char * outputVar,
                       SkXfermode::Coeff uniformCoeff,
                       SkXfermode::Coeff colorCoeff,
                       const char* filterColor,
@@ -407,9 +408,9 @@
     blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor);
     blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor);
 
-    fsCode->appendf("\t%s = ", outputVar);
-    GrGLSLAdd4f(fsCode, colorStr.c_str(), constStr.c_str());
-    fsCode->append(";\n");
+    SkString sum;
+    GrGLSLAdd4f(&sum, colorStr.c_str(), constStr.c_str());
+    builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str());
 }
 }
 
@@ -421,64 +422,64 @@
         builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
                                           GrGLShaderVar::kAttribute_TypeModifier,
                                           EDGE_ATTR_NAME);
-        builder->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
+        builder->vsCodeAppendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
         switch (fDesc.fVertexEdgeType) {
         case GrDrawState::kHairLine_EdgeType:
-            builder->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", builder->fragmentPosition(), fsName);
-            builder->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            builder->fsCodeAppendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", builder->fragmentPosition(), fsName);
+            builder->fsCodeAppendf("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             break;
         case GrDrawState::kQuad_EdgeType:
-            builder->fFSCode.append("\tfloat edgeAlpha;\n");
+            builder->fsCodeAppendf("\tfloat edgeAlpha;\n");
             // keep the derivative instructions outside the conditional
-            builder->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
+            builder->fsCodeAppendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
             // today we know z and w are in device space. We could use derivatives
-            builder->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
-            builder->fFSCode.append ("\t} else {\n");
-            builder->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
-                                     "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
-                                     fsName, fsName);
-            builder->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
-            builder->fFSCode.append("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
-                                    "\t}\n");
+            builder->fsCodeAppendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
+            builder->fsCodeAppendf ("\t} else {\n");
+            builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                   "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                    fsName, fsName);
+            builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+            builder->fsCodeAppendf("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
+                                   "\t}\n");
             if (kES2_GrGLBinding == fContext.info().binding()) {
-                builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
+                builder->fHeader.append("#extension GL_OES_standard_derivatives: enable\n");
             }
             break;
         case GrDrawState::kHairQuad_EdgeType:
-            builder->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
-                                     "\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
-                                     fsName, fsName);
-            builder->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
-            builder->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
-            builder->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            builder->fsCodeAppendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                   "\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                   fsName, fsName);
+            builder->fsCodeAppendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+            builder->fsCodeAppend("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
+            builder->fsCodeAppend("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             if (kES2_GrGLBinding == fContext.info().binding()) {
                 builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
             }
             break;
         case GrDrawState::kCircle_EdgeType:
-            builder->fFSCode.append("\tfloat edgeAlpha;\n");
-            builder->fFSCode.appendf("\tfloat d = distance(%s.xy, %s.xy);\n", builder->fragmentPosition(), fsName);
-            builder->fFSCode.appendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
-            builder->fFSCode.appendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
-            builder->fFSCode.append("\tedgeAlpha = outerAlpha * innerAlpha;\n");
+            builder->fsCodeAppend("\tfloat edgeAlpha;\n");
+            builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n", builder->fragmentPosition(), fsName);
+            builder->fsCodeAppendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
+            builder->fsCodeAppendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
+            builder->fsCodeAppend("\tedgeAlpha = outerAlpha * innerAlpha;\n");
             break;
         case GrDrawState::kEllipse_EdgeType:
-            builder->fFSCode.append("\tfloat edgeAlpha;\n");
-            builder->fFSCode.appendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName);
-            builder->fFSCode.appendf("\toffset.y *= %s.w;\n", fsName);
-            builder->fFSCode.append("\tfloat d = length(offset);\n");
-            builder->fFSCode.appendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
+            builder->fsCodeAppend("\tfloat edgeAlpha;\n");
+            builder->fsCodeAppendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName);
+            builder->fsCodeAppendf("\toffset.y *= %s.w;\n", fsName);
+            builder->fsCodeAppend("\tfloat d = length(offset);\n");
+            builder->fsCodeAppendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
             break;
         default:
             GrCrash("Unknown Edge Type!");
             break;
         }
         if (fDesc.fDiscardIfOutsideEdge) {
-            builder->fFSCode.appendf("\tif (edgeAlpha <= 0.0) {\n\t\tdiscard;\n\t}\n");
+            builder->fsCodeAppend("\tif (edgeAlpha <= 0.0) {\n\t\tdiscard;\n\t}\n");
         }
         *coverageVar = "edgeAlpha";
         return true;
@@ -496,7 +497,7 @@
                 COL_ATTR_NAME);
             const char *vsName, *fsName;
             builder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
-            builder->fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
+            builder->vsCodeAppendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
             *inColor = fsName;
             } break;
         case GrGLProgram::Desc::kUniform_ColorInput: {
@@ -522,8 +523,8 @@
     fUniformHandles.fCoverageUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                                        kVec4f_GrSLType, "Coverage", &covUniName);
     if (inOutCoverage->size()) {
-        builder->fFSCode.appendf("\tvec4 uniCoverage = %s * %s;\n",
-                                  covUniName, inOutCoverage->c_str());
+        builder->fsCodeAppendf("\tvec4 uniCoverage = %s * %s;\n",
+                               covUniName, inOutCoverage->c_str());
         *inOutCoverage = "uniCoverage";
     } else {
         *inOutCoverage = covUniName;
@@ -531,17 +532,16 @@
 }
 
 namespace {
-void gen_attribute_coverage(GrGLShaderBuilder* segments,
+void gen_attribute_coverage(GrGLShaderBuilder* builder,
                             SkString* inOutCoverage) {
-    segments->fVSAttrs.push_back().set(kVec4f_GrSLType,
-                                       GrGLShaderVar::kAttribute_TypeModifier,
-                                       COV_ATTR_NAME);
+    builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
+                                      GrGLShaderVar::kAttribute_TypeModifier,
+                                      COV_ATTR_NAME);
     const char *vsName, *fsName;
-    segments->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
-    segments->fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
+    builder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
+    builder->vsCodeAppendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
     if (inOutCoverage->size()) {
-        segments->fFSCode.appendf("\tvec4 attrCoverage = %s * %s;\n",
-                                  fsName, inOutCoverage->c_str());
+        builder->fsCodeAppendf("\tvec4 attrCoverage = %s * %s;\n", fsName, inOutCoverage->c_str());
         *inOutCoverage = "attrCoverage";
     } else {
         *inOutCoverage = fsName;
@@ -549,27 +549,28 @@
 }
 }
 
-void GrGLProgram::genGeometryShader(GrGLShaderBuilder* segments) const {
+void GrGLProgram::genGeometryShader(GrGLShaderBuilder* builder) const {
 #if GR_GL_EXPERIMENTAL_GS
+    // TODO: The builder should add all this glue code.
     if (fDesc.fExperimentalGS) {
         GrAssert(fContext.info().glslGeneration() >= k150_GrGLSLGeneration);
-        segments->fGSHeader.append("layout(triangles) in;\n"
+        builder->fGSHeader.append("layout(triangles) in;\n"
                                    "layout(triangle_strip, max_vertices = 6) out;\n");
-        segments->fGSCode.append("\tfor (int i = 0; i < 3; ++i) {\n"
-                                 "\t\tgl_Position = gl_in[i].gl_Position;\n");
+        builder->gsCodeAppend("\tfor (int i = 0; i < 3; ++i) {\n"
+                              "\t\tgl_Position = gl_in[i].gl_Position;\n");
         if (fDesc.fEmitsPointSize) {
-            segments->fGSCode.append("\t\tgl_PointSize = 1.0;\n");
+            builder->gsCodeAppend("\t\tgl_PointSize = 1.0;\n");
         }
-        GrAssert(segments->fGSInputs.count() == segments->fGSOutputs.count());
-        int count = segments->fGSInputs.count();
+        GrAssert(builder->fGSInputs.count() == builder->fGSOutputs.count());
+        int count = builder->fGSInputs.count();
         for (int i = 0; i < count; ++i) {
-            segments->fGSCode.appendf("\t\t%s = %s[i];\n",
-                                      segments->fGSOutputs[i].getName().c_str(),
-                                      segments->fGSInputs[i].getName().c_str());
+            builder->gsCodeAppendf("\t\t%s = %s[i];\n",
+                                   builder->fGSOutputs[i].getName().c_str(),
+                                   builder->fGSInputs[i].getName().c_str());
         }
-        segments->fGSCode.append("\t\tEmitVertex();\n"
-                                 "\t}\n"
-                                 "\tEndPrimitive();\n");
+        builder->gsCodeAppend("\t\tEmitVertex();\n"
+                              "\t}\n"
+                              "\tEndPrimitive();\n");
     }
 #endif
 }
@@ -758,9 +759,9 @@
                                                         kMat33f_GrSLType, "ViewM", &viewMName);
 
 
-    builder.fVSCode.appendf("\tvec3 pos3 = %s * vec3(%s, 1);\n"
-                            "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n",
-                            viewMName, builder.positionAttribute().getName().c_str());
+    builder.vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n"
+                          "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n",
+                          viewMName, builder.positionAttribute().getName().c_str());
 
     // incoming color to current stage being processed.
     SkString inColor;
@@ -771,7 +772,7 @@
 
     // we output point size in the GS if present
     if (fDesc.fEmitsPointSize && !builder.fUsesGS){
-        builder.fVSCode.append("\tgl_PointSize = 1.0;\n");
+        builder.vsCodeAppend("\tgl_PointSize = 1.0;\n");
     }
 
     // add texture coordinates that are used to the list of vertex attr decls
@@ -793,7 +794,7 @@
                 // create var to hold stage result
                 outColor = "color";
                 outColor.appendS32(s);
-                builder.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
+                builder.fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
 
                 const char* inCoords;
                 // figure out what our input coords are
@@ -840,15 +841,13 @@
     bool wroteFragColorZero = false;
     if (SkXfermode::kZero_Coeff == uniformCoeff &&
         SkXfermode::kZero_Coeff == colorCoeff) {
-        builder.fFSCode.appendf("\t%s = %s;\n",
-                                colorOutput.getName().c_str(),
-                                GrGLSLZerosVecf(4));
+        builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), GrGLSLZerosVecf(4));
         wroteFragColorZero = true;
     } else if (SkXfermode::kDst_Mode != fDesc.fColorFilterXfermode) {
-        builder.fFSCode.append("\tvec4 filteredColor;\n");
+        builder.fsCodeAppend("\tvec4 filteredColor;\n");
         const char* color = adjustInColor(inColor);
-        add_color_filter(&builder.fFSCode, "filteredColor", uniformCoeff,
-                       colorCoeff, colorFilterColorUniName, color);
+        add_color_filter(&builder, "filteredColor", uniformCoeff,
+                         colorCoeff, colorFilterColorUniName, color);
         inColor = "filteredColor";
     }
 
@@ -887,7 +886,7 @@
                     // create var to hold stage output
                     outCoverage = "coverage";
                     outCoverage.appendS32(s);
-                    builder.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
+                    builder.fsCodeAppendf("\tvec4 %s;\n", outCoverage.c_str());
 
                     const char* inCoords;
                     // figure out what our input coords are
@@ -902,8 +901,8 @@
                     // stages don't know how to deal with a scalar input. (Maybe they should. We
                     // could pass a GrGLShaderVar)
                     if (inCoverageIsScalar) {
-                        builder.fFSCode.appendf("\tvec4 %s4 = vec4(%s);\n",
-                                                inCoverage.c_str(), inCoverage.c_str());
+                        builder.fsCodeAppendf("\tvec4 %s4 = vec4(%s);\n",
+                                              inCoverage.c_str(), inCoverage.c_str());
                         inCoverage.append("4");
                     }
                     builder.setCurrentStage(s);
@@ -939,13 +938,11 @@
                 }
             }
             if (outputIsZero) {
-                builder.fFSCode.appendf("\t%s = %s;\n",
-                                        dual_source_output_name(),
-                                        GrGLSLZerosVecf(4));
+                builder.fsCodeAppendf("\t%s = %s;\n", dual_source_output_name(), GrGLSLZerosVecf(4));
             } else {
-                builder.fFSCode.appendf("\t%s =", dual_source_output_name());
-                GrGLSLModulate4f(&builder.fFSCode, coeff.c_str(), inCoverage.c_str());
-                builder.fFSCode.append(";\n");
+                SkString modulate;
+                GrGLSLModulate4f(&modulate, coeff.c_str(), inCoverage.c_str());
+                builder.fsCodeAppendf("\t%s = %s;\n", dual_source_output_name(), modulate.c_str());
             }
             dualSourceOutputWritten = true;
         }
@@ -956,13 +953,11 @@
 
     if (!wroteFragColorZero) {
         if (coverageIsZero) {
-            builder.fFSCode.appendf("\t%s = %s;\n",
-                                    colorOutput.getName().c_str(),
-                                    GrGLSLZerosVecf(4));
+            builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), GrGLSLZerosVecf(4));
         } else {
-            builder.fFSCode.appendf("\t%s = ", colorOutput.getName().c_str());
-            GrGLSLModulate4f(&builder.fFSCode, inColor.c_str(), inCoverage.c_str());
-            builder.fFSCode.append(";\n");
+            SkString modulate;
+            GrGLSLModulate4f(&modulate, inColor.c_str(), inCoverage.c_str());
+            builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), modulate.c_str());
         }
     }
 
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 021f56d..08ef28e 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -101,6 +101,42 @@
     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
 }
 
+void GrGLShaderBuilder::codeAppendf(ShaderType type, const char format[], va_list args) {
+    SkString* string;
+    switch (type) {
+        case kVertex_ShaderType:
+            string = &fVSCode;
+            break;
+        case kGeometry_ShaderType:
+            string = &fGSCode;
+            break;
+        case kFragment_ShaderType:
+            string = &fFSCode;
+            break;
+        default:
+            GrCrash("Invalid shader type");
+    }
+    string->appendf(format, args);
+}
+
+void GrGLShaderBuilder::codeAppend(ShaderType type, const char* str) {
+    SkString* string;
+    switch (type) {
+        case kVertex_ShaderType:
+            string = &fVSCode;
+            break;
+        case kGeometry_ShaderType:
+            string = &fGSCode;
+            break;
+        case kFragment_ShaderType:
+            string = &fFSCode;
+            break;
+        default:
+            GrCrash("Invalid shader type");
+    }
+    string->append(str);
+}
+
 void GrGLShaderBuilder::appendTextureLookup(SkString* out,
                                             const GrGLShaderBuilder::TextureSampler& sampler,
                                             const char* coordName,
@@ -115,16 +151,24 @@
     append_swizzle(out, *sampler.textureAccess(), fCtxInfo.caps());
 }
 
+void GrGLShaderBuilder::appendTextureLookup(ShaderType type,
+                                            const GrGLShaderBuilder::TextureSampler& sampler,
+                                            const char* coordName,
+                                            GrSLType varyingType) {
+    GrAssert(kFragment_ShaderType == type);
+    this->appendTextureLookup(&fFSCode, sampler, coordName, varyingType);
+}
+
 void GrGLShaderBuilder::appendTextureLookupAndModulate(
-                                            SkString* out,
+                                            ShaderType type,
                                             const char* modulation,
                                             const GrGLShaderBuilder::TextureSampler& sampler,
                                             const char* coordName,
-                                            GrSLType varyingType) const {
-    GrAssert(NULL != out);
+                                            GrSLType varyingType) {
+    GrAssert(kFragment_ShaderType == type);
     SkString lookup;
     this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
-    GrGLSLModulate4f(out, modulation, lookup.c_str());
+    GrGLSLModulate4f(&fFSCode, modulation, lookup.c_str());
 }
 
 GrBackendEffectFactory::EffectKey GrGLShaderBuilder::KeyForTextureAccess(
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index ce1e6d1..08b3ef5 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -14,6 +14,8 @@
 #include "gl/GrGLSL.h"
 #include "gl/GrGLUniformManager.h"
 
+#include <stdarg.h>
+
 class GrGLContextInfo;
 
 /**
@@ -80,6 +82,34 @@
 
     GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&);
 
+    /**
+     * Called by GrGLEffects to add code to one of the shaders.
+     */
+    void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+        va_list args;
+        va_start(args, format);
+        this->codeAppendf(kVertex_ShaderType, format, args);
+        va_end(args);
+    }
+
+    void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+        va_list args;
+        va_start(args, format);
+        this->codeAppendf(kGeometry_ShaderType, format, args);
+        va_end(args);
+    }
+
+    void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+        va_list args;
+        va_start(args, format);
+        this->codeAppendf(kFragment_ShaderType, format, args);
+        va_end(args);
+    }
+
+    void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); }
+    void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); }
+    void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); }
+
     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
         order of the result depends on the GrTextureAccess associated with the TextureSampler. */
@@ -88,15 +118,23 @@
                              const char* coordName,
                              GrSLType coordType = kVec2f_GrSLType) const;
 
+    /** Version of above that appends the result to the shader code rather than an SkString.
+        Currently the shader type must be kFragment */
+    void appendTextureLookup(ShaderType,
+                             const TextureSampler&,
+                             const char* coordName,
+                             GrSLType coordType = kVec2f_GrSLType);
+
+
     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
         always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
         float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
         called. */
-    void appendTextureLookupAndModulate(SkString* out,
+    void appendTextureLookupAndModulate(ShaderType,
                                         const char* modulation,
                                         const TextureSampler&,
                                         const char* coordName,
-                                        GrSLType coordType = kVec2f_GrSLType) const;
+                                        GrSLType coordType = kVec2f_GrSLType);
 
     /** Emits a helper function outside of main(). Currently ShaderType must be
         kFragment_ShaderType. */
@@ -190,6 +228,9 @@
     const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
 
 private:
+    void codeAppendf(ShaderType type, const char format[], va_list args);
+    void codeAppend(ShaderType type, const char* str);
+
     typedef GrTAllocator<GrGLShaderVar> VarArray;
 
     void appendDecls(const VarArray&, SkString*) const;
@@ -209,9 +250,6 @@
     VarArray    fFSInputs;
     SkString    fGSHeader; // layout qualifiers specific to GS
     VarArray    fFSOutputs;
-    SkString    fVSCode;
-    SkString    fGSCode;
-    SkString    fFSCode;
     bool        fUsesGS;
 
 private:
@@ -225,6 +263,10 @@
     SkString                            fFSFunctions;
     SkString                            fFSHeader;
 
+    SkString                            fFSCode;
+    SkString                            fVSCode;
+    SkString                            fGSCode;
+
     bool                                fSetupFragPosition;
     GrGLUniformManager::UniformHandle   fRTHeightUniform;
 
diff --git a/src/ports/SkDebug_stdio.cpp b/src/ports/SkDebug_stdio.cpp
index 318269e..8ff27ad 100644
--- a/src/ports/SkDebug_stdio.cpp
+++ b/src/ports/SkDebug_stdio.cpp
@@ -9,16 +9,12 @@
 
 #include "SkTypes.h"
 
-static const size_t kBufferSize = 2048;
-
 #include <stdarg.h>
 #include <stdio.h>
 
 void SkDebugf(const char format[], ...) {
-    char    buffer[kBufferSize + 1];
     va_list args;
     va_start(args, format);
-    vsnprintf(buffer, kBufferSize, format, args);
+    vfprintf(stderr, format, args);
     va_end(args);
-    fprintf(stderr, "%s", buffer);
 }
diff --git a/src/ports/SkDebug_win.cpp b/src/ports/SkDebug_win.cpp
index 4b340b0..30fe2b5 100644
--- a/src/ports/SkDebug_win.cpp
+++ b/src/ports/SkDebug_win.cpp
@@ -21,8 +21,8 @@
     va_list args;
     va_start(args, format);
     vsnprintf(buffer, kBufferSize, format, args);
+    vprintf(format, args);
     va_end(args);
 
     OutputDebugStringA(buffer);
-    printf(buffer);
 }