skslc can now be compiled with no Skia dependencies, in preparation for its eventual
role in Skia's build process.

This reverts commit bcf35f86d50b784b165de703b404998dd4299f6a.

BUG=skia:

Change-Id: Id0a12dfc4d804d69a3c6bf60fed37e89ee130f02
Reviewed-on: https://skia-review.googlesource.com/10802
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Ben Wagner <benjaminwagner@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 7d4ac6d..1801c32 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1484,13 +1484,12 @@
 
   if (skia_enable_gpu) {
     test_app("skslc") {
+      defines = [ "SKSL_STANDALONE" ]
       sources = [
         "src/sksl/SkSLMain.cpp",
       ]
-      deps = [
-        ":flags",
-        ":skia",
-      ]
+      sources += skia_sksl_sources
+      include_dirs = [ "src/sksl" ]
     }
   }
 }
diff --git a/bench/GLBench.cpp b/bench/GLBench.cpp
index 0fcd56f..f043c95 100644
--- a/bench/GLBench.cpp
+++ b/bench/GLBench.cpp
@@ -67,7 +67,7 @@
 
 GrGLuint GLBench::CompileShader(const GrGLContext* context, const char* sksl, GrGLenum type) {
     const GrGLInterface* gl = context->interface();
-    SkString glsl;
+    SkSL::String glsl;
     SkSL::Program::Settings settings;
     settings.fCaps = context->caps()->shaderCaps();
     std::unique_ptr<SkSL::Program> program = context->compiler()->convertProgram(
diff --git a/fuzz/fuzz.cpp b/fuzz/fuzz.cpp
index d156680..8374f95 100644
--- a/fuzz/fuzz.cpp
+++ b/fuzz/fuzz.cpp
@@ -558,7 +558,7 @@
 #if SK_SUPPORT_GPU
 static void fuzz_sksl2glsl(sk_sp<SkData> bytes) {
     SkSL::Compiler compiler;
-    SkString output;
+    SkSL::String output;
     SkSL::Program::Settings settings;
     sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
     settings.fCaps = caps.get();
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 748466f..a1cab82 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -13,6 +13,7 @@
   "$_src/sksl/SkSLParser.cpp",
   "$_src/sksl/SkSLGLSLCodeGenerator.cpp",
   "$_src/sksl/SkSLSPIRVCodeGenerator.cpp",
+  "$_src/sksl/SkSLString.cpp",
   "$_src/sksl/SkSLUtil.cpp",
   "$_src/sksl/lex.layout.cpp",
   "$_src/sksl/ir/SkSLSymbolTable.cpp",
diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
index 46530f2..e3d2def 100644
--- a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
@@ -48,7 +48,7 @@
     }
 #endif
 
-    SkString glsl;
+    SkSL::String glsl;
     if (type == GR_GL_VERTEX_SHADER || type == GR_GL_FRAGMENT_SHADER) {
         SkSL::Compiler& compiler = *glCtx.compiler();
         std::unique_ptr<SkSL::Program> program;
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index 1a73f9a..1fdf69c 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -283,7 +283,7 @@
         SkASSERT(false);
     }
     *outInputs = program->fInputs;
-    SkString code;
+    SkSL::String code;
     if (!gpu->shaderCompiler()->toSPIRV(*program, &code)) {
         SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
         return false;
diff --git a/src/sksl/README b/src/sksl/README
index 25b07c1..5e8e21b 100644
--- a/src/sksl/README
+++ b/src/sksl/README
@@ -1,7 +1,7 @@
 Overview
 ========
 
-SkSL ("Skia Shading Language") is a variant of GLSL which is used as Skia's 
+SkSL ("Skia Shading Language") is a variant of GLSL which is used as Skia's
 internal shading language. SkSL is, at its heart, a single standardized version
 of GLSL which avoids all of the various version and dialect differences found
 in GLSL "in the wild", but it does bring a few of its own changes to the table.
@@ -15,7 +15,7 @@
 SkSL is based on GLSL 4.5. For the most part, write SkSL exactly as you would
 desktop GLSL, and the SkSL compiler will take care of version and dialect
 differences (for instance, you always use "in" and "out", and skslc will handle
-translating them to "varying" and "attribute" as appropriate). Be aware of the 
+translating them to "varying" and "attribute" as appropriate). Be aware of the
 following differences between SkSL and GLSL:
 
 * GLSL caps can be referenced via the syntax 'sk_Caps.<name>', e.g.
@@ -36,11 +36,11 @@
 * use sk_VertexID instead of gl_VertexID
 * the fragment coordinate is sk_FragCoord, and is always relative to the upper
   left.
-* lowp, mediump, and highp are always permitted (but will only be respected if 
+* lowp, mediump, and highp are always permitted (but will only be respected if
   you run on a device which supports them)
 * you do not need to include ".0" to make a number a float (meaning that
   "vec2(x, y) * 4" is perfectly legal in SkSL, unlike GLSL where it would often
-  have to be expressed "vec2(x, y) * 4.0". There is no performance penalty for 
+  have to be expressed "vec2(x, y) * 4.0". There is no performance penalty for
   this, as the number is converted to a float at compile time)
 * type suffixes on numbers (1.0f, 0xFFu) are both unnecessary and unsupported
 * creating a smaller vector from a larger vector (e.g. vec2(vec3(1))) is
diff --git a/src/sksl/SkSLCFGGenerator.cpp b/src/sksl/SkSLCFGGenerator.cpp
index 28533df..e2c0380 100644
--- a/src/sksl/SkSLCFGGenerator.cpp
+++ b/src/sksl/SkSLCFGGenerator.cpp
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #include "SkSLCFGGenerator.h"
 
 #include "ir/SkSLConstructor.h"
diff --git a/src/sksl/SkSLCFGGenerator.h b/src/sksl/SkSLCFGGenerator.h
index 337fdfa..0a03d69 100644
--- a/src/sksl/SkSLCFGGenerator.h
+++ b/src/sksl/SkSLCFGGenerator.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_CFGGENERATOR
 #define SKSL_CFGGENERATOR
 
diff --git a/src/sksl/SkSLCodeGenerator.h b/src/sksl/SkSLCodeGenerator.h
index 111e73a..f6f9905 100644
--- a/src/sksl/SkSLCodeGenerator.h
+++ b/src/sksl/SkSLCodeGenerator.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_CODEGENERATOR
 #define SKSL_CODEGENERATOR
 
@@ -18,7 +18,7 @@
  */
 class CodeGenerator {
 public:
-    CodeGenerator(const Program* program, ErrorReporter* errors, SkWStream* out)
+    CodeGenerator(const Program* program, ErrorReporter* errors, OutputStream* out)
     : fProgram(*program)
     , fErrors(*errors)
     , fOut(out) {}
@@ -31,7 +31,7 @@
 
     const Program& fProgram;
     ErrorReporter& fErrors;
-    SkWStream* fOut;
+    OutputStream* fOut;
 };
 
 } // namespace
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 08b49e6..ea87e99 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -19,7 +19,6 @@
 #include "ir/SkSLSymbolTable.h"
 #include "ir/SkSLUnresolvedFunction.h"
 #include "ir/SkSLVarDeclarations.h"
-#include "SkMutex.h"
 
 #ifdef SK_ENABLE_SPIRV_VALIDATION
 #include "spirv-tools/libspirv.hpp"
@@ -77,17 +76,17 @@
     ADD_TYPE(BVec3);
     ADD_TYPE(BVec4);
     ADD_TYPE(Mat2x2);
-    types->addWithoutOwnership(SkString("mat2x2"), fContext.fMat2x2_Type.get());
+    types->addWithoutOwnership(String("mat2x2"), fContext.fMat2x2_Type.get());
     ADD_TYPE(Mat2x3);
     ADD_TYPE(Mat2x4);
     ADD_TYPE(Mat3x2);
     ADD_TYPE(Mat3x3);
-    types->addWithoutOwnership(SkString("mat3x3"), fContext.fMat3x3_Type.get());
+    types->addWithoutOwnership(String("mat3x3"), fContext.fMat3x3_Type.get());
     ADD_TYPE(Mat3x4);
     ADD_TYPE(Mat4x2);
     ADD_TYPE(Mat4x3);
     ADD_TYPE(Mat4x4);
-    types->addWithoutOwnership(SkString("mat4x4"), fContext.fMat4x4_Type.get());
+    types->addWithoutOwnership(String("mat4x4"), fContext.fMat4x4_Type.get());
     ADD_TYPE(GenType);
     ADD_TYPE(GenDType);
     ADD_TYPE(GenIType);
@@ -147,14 +146,14 @@
     ADD_TYPE(GSampler2DArrayShadow);
     ADD_TYPE(GSamplerCubeArrayShadow);
 
-    SkString skCapsName("sk_Caps");
-    Variable* skCaps = new Variable(Position(), Modifiers(), skCapsName, 
+    String skCapsName("sk_Caps");
+    Variable* skCaps = new Variable(Position(), Modifiers(), skCapsName,
                                     *fContext.fSkCaps_Type, Variable::kGlobal_Storage);
     fIRGenerator->fSymbolTable->add(skCapsName, std::unique_ptr<Symbol>(skCaps));
 
     Modifiers::Flag ignored1;
     std::vector<std::unique_ptr<ProgramElement>> ignored2;
-    this->internalConvertProgram(SkString(SKSL_INCLUDE), &ignored1, &ignored2);
+    this->internalConvertProgram(String(SKSL_INCLUDE), &ignored1, &ignored2);
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     ASSERT(!fErrorCount);
 }
@@ -351,7 +350,7 @@
                     p = (*cfg.fBlocks[i].fNodes[0].fExpression)->fPosition;
                     break;
             }
-            this->error(p, SkString("unreachable"));
+            this->error(p, String("unreachable"));
         }
     }
     if (fErrorCount) {
@@ -389,12 +388,12 @@
     // check for missing return
     if (f.fDeclaration.fReturnType != *fContext.fVoid_Type) {
         if (cfg.fBlocks[cfg.fExit].fEntrances.size()) {
-            this->error(f.fPosition, SkString("function can exit without returning a value"));
+            this->error(f.fPosition, String("function can exit without returning a value"));
         }
     }
 }
 
-void Compiler::internalConvertProgram(SkString text,
+void Compiler::internalConvertProgram(String text,
                                       Modifiers::Flag* defaultPrecision,
                                       std::vector<std::unique_ptr<ProgramElement>>* result) {
     Parser parser(text, *fTypes, *this);
@@ -457,7 +456,7 @@
     }
 }
 
-std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, SkString text,
+std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, String text,
                                                   const Program::Settings& settings) {
     fErrorText = "";
     fErrorCount = 0;
@@ -466,13 +465,13 @@
     Modifiers::Flag ignored;
     switch (kind) {
         case Program::kVertex_Kind:
-            this->internalConvertProgram(SkString(SKSL_VERT_INCLUDE), &ignored, &elements);
+            this->internalConvertProgram(String(SKSL_VERT_INCLUDE), &ignored, &elements);
             break;
         case Program::kFragment_Kind:
-            this->internalConvertProgram(SkString(SKSL_FRAG_INCLUDE), &ignored, &elements);
+            this->internalConvertProgram(String(SKSL_FRAG_INCLUDE), &ignored, &elements);
             break;
         case Program::kGeometry_Kind:
-            this->internalConvertProgram(SkString(SKSL_GEOM_INCLUDE), &ignored, &elements);
+            this->internalConvertProgram(String(SKSL_GEOM_INCLUDE), &ignored, &elements);
             break;
     }
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
@@ -490,23 +489,22 @@
     return result;
 }
 
-bool Compiler::toSPIRV(const Program& program, SkWStream& out) {
+bool Compiler::toSPIRV(const Program& program, OutputStream& out) {
 #ifdef SK_ENABLE_SPIRV_VALIDATION
-    SkDynamicMemoryWStream buffer;
+    StringStream buffer;
     SPIRVCodeGenerator cg(&fContext, &program, this, &buffer);
     bool result = cg.generateCode();
     if (result) {
-        sk_sp<SkData> data(buffer.detachAsData());
         spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
-        SkASSERT(0 == data->size() % 4);
+        ASSERT(0 == buffer.size() % 4);
         auto dumpmsg = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) {
             SkDebugf("SPIR-V validation error: %s\n", m);
         };
         tools.SetMessageConsumer(dumpmsg);
         // Verify that the SPIR-V we produced is valid. If this assert fails, check the logs prior
         // to the failure to see the validation errors.
-        SkAssertResult(tools.Validate((const uint32_t*) data->data(), data->size() / 4));
-        out.write(data->data(), data->size());
+        ASSERT_RESULT(tools.Validate((const uint32_t*) buffer.data(), buffer.size() / 4));
+        out.write(buffer.data(), buffer.size());
     }
 #else
     SPIRVCodeGenerator cg(&fContext, &program, this, &out);
@@ -516,41 +514,39 @@
     return result;
 }
 
-bool Compiler::toSPIRV(const Program& program, SkString* out) {
-    SkDynamicMemoryWStream buffer;
+bool Compiler::toSPIRV(const Program& program, String* out) {
+    StringStream buffer;
     bool result = this->toSPIRV(program, buffer);
     if (result) {
-        sk_sp<SkData> data(buffer.detachAsData());
-        *out = SkString((const char*) data->data(), data->size());
+        *out = String(buffer.data(), buffer.size());
     }
     return result;
 }
 
-bool Compiler::toGLSL(const Program& program, SkWStream& out) {
+bool Compiler::toGLSL(const Program& program, OutputStream& out) {
     GLSLCodeGenerator cg(&fContext, &program, this, &out);
     bool result = cg.generateCode();
     this->writeErrorCount();
     return result;
 }
 
-bool Compiler::toGLSL(const Program& program, SkString* out) {
-    SkDynamicMemoryWStream buffer;
+bool Compiler::toGLSL(const Program& program, String* out) {
+    StringStream buffer;
     bool result = this->toGLSL(program, buffer);
     if (result) {
-        sk_sp<SkData> data(buffer.detachAsData());
-        *out = SkString((const char*) data->data(), data->size());
+        *out = String(buffer.data(), buffer.size());
     }
     return result;
 }
 
 
-void Compiler::error(Position position, SkString msg) {
+void Compiler::error(Position position, String msg) {
     fErrorCount++;
     fErrorText += "error: " + position.description() + ": " + msg.c_str() + "\n";
 }
 
-SkString Compiler::errorText() {
-    SkString result = fErrorText;
+String Compiler::errorText() {
+    String result = fErrorText;
     return result;
 }
 
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index ec02c5a..7e3c83e 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_COMPILER
 #define SKSL_COMPILER
 
@@ -42,20 +42,20 @@
 
     ~Compiler() override;
 
-    std::unique_ptr<Program> convertProgram(Program::Kind kind, SkString text,
+    std::unique_ptr<Program> convertProgram(Program::Kind kind, String text,
                                             const Program::Settings& settings);
 
-    bool toSPIRV(const Program& program, SkWStream& out);
+    bool toSPIRV(const Program& program, OutputStream& out);
 
-    bool toSPIRV(const Program& program, SkString* out);
+    bool toSPIRV(const Program& program, String* out);
 
-    bool toGLSL(const Program& program, SkWStream& out);
+    bool toGLSL(const Program& program, OutputStream& out);
 
-    bool toGLSL(const Program& program, SkString* out);
+    bool toGLSL(const Program& program, String* out);
 
-    void error(Position position, SkString msg) override;
+    void error(Position position, String msg) override;
 
-    SkString errorText();
+    String errorText();
 
     void writeErrorCount();
 
@@ -73,17 +73,17 @@
 
     void scanCFG(const FunctionDefinition& f);
 
-    void internalConvertProgram(SkString text,
+    void internalConvertProgram(String text,
                                 Modifiers::Flag* defaultPrecision,
                                 std::vector<std::unique_ptr<ProgramElement>>* result);
 
     std::shared_ptr<SymbolTable> fTypes;
     IRGenerator* fIRGenerator;
-    SkString fSkiaVertText; // FIXME store parsed version instead
+    String fSkiaVertText; // FIXME store parsed version instead
 
     Context fContext;
     int fErrorCount;
-    SkString fErrorText;
+    String fErrorText;
 };
 
 } // namespace
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index df651bc..450baa5 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_CONTEXT
 #define SKSL_CONTEXT
 
@@ -19,114 +19,114 @@
 class Context {
 public:
     Context()
-    : fInvalid_Type(new Type(SkString("<INVALID>")))
-    , fVoid_Type(new Type(SkString("void")))
-    , fDouble_Type(new Type(SkString("double"), true))
-    , fDVec2_Type(new Type(SkString("dvec2"), *fDouble_Type, 2))
-    , fDVec3_Type(new Type(SkString("dvec3"), *fDouble_Type, 3))
-    , fDVec4_Type(new Type(SkString("dvec4"), *fDouble_Type, 4))
-    , fFloat_Type(new Type(SkString("float"), true, { fDouble_Type.get() }))
-    , fVec2_Type(new Type(SkString("vec2"), *fFloat_Type, 2))
-    , fVec3_Type(new Type(SkString("vec3"), *fFloat_Type, 3))
-    , fVec4_Type(new Type(SkString("vec4"), *fFloat_Type, 4))
-    , fUInt_Type(new Type(SkString("uint"), true, { fFloat_Type.get(), fDouble_Type.get() }))
-    , fUVec2_Type(new Type(SkString("uvec2"), *fUInt_Type, 2))
-    , fUVec3_Type(new Type(SkString("uvec3"), *fUInt_Type, 3))
-    , fUVec4_Type(new Type(SkString("uvec4"), *fUInt_Type, 4))
-    , fInt_Type(new Type(SkString("int"), true, { fUInt_Type.get(), fFloat_Type.get(),
+    : fInvalid_Type(new Type(String("<INVALID>")))
+    , fVoid_Type(new Type(String("void")))
+    , fDouble_Type(new Type(String("double"), true))
+    , fDVec2_Type(new Type(String("dvec2"), *fDouble_Type, 2))
+    , fDVec3_Type(new Type(String("dvec3"), *fDouble_Type, 3))
+    , fDVec4_Type(new Type(String("dvec4"), *fDouble_Type, 4))
+    , fFloat_Type(new Type(String("float"), true, { fDouble_Type.get() }))
+    , fVec2_Type(new Type(String("vec2"), *fFloat_Type, 2))
+    , fVec3_Type(new Type(String("vec3"), *fFloat_Type, 3))
+    , fVec4_Type(new Type(String("vec4"), *fFloat_Type, 4))
+    , fUInt_Type(new Type(String("uint"), true, { fFloat_Type.get(), fDouble_Type.get() }))
+    , fUVec2_Type(new Type(String("uvec2"), *fUInt_Type, 2))
+    , fUVec3_Type(new Type(String("uvec3"), *fUInt_Type, 3))
+    , fUVec4_Type(new Type(String("uvec4"), *fUInt_Type, 4))
+    , fInt_Type(new Type(String("int"), true, { fUInt_Type.get(), fFloat_Type.get(),
                                                   fDouble_Type.get() }))
-    , fIVec2_Type(new Type(SkString("ivec2"), *fInt_Type, 2))
-    , fIVec3_Type(new Type(SkString("ivec3"), *fInt_Type, 3))
-    , fIVec4_Type(new Type(SkString("ivec4"), *fInt_Type, 4))
-    , fBool_Type(new Type(SkString("bool"), false))
-    , fBVec2_Type(new Type(SkString("bvec2"), *fBool_Type, 2))
-    , fBVec3_Type(new Type(SkString("bvec3"), *fBool_Type, 3))
-    , fBVec4_Type(new Type(SkString("bvec4"), *fBool_Type, 4))
-    , fMat2x2_Type(new Type(SkString("mat2"),   *fFloat_Type, 2, 2))
-    , fMat2x3_Type(new Type(SkString("mat2x3"), *fFloat_Type, 2, 3))
-    , fMat2x4_Type(new Type(SkString("mat2x4"), *fFloat_Type, 2, 4))
-    , fMat3x2_Type(new Type(SkString("mat3x2"), *fFloat_Type, 3, 2))
-    , fMat3x3_Type(new Type(SkString("mat3"),   *fFloat_Type, 3, 3))
-    , fMat3x4_Type(new Type(SkString("mat3x4"), *fFloat_Type, 3, 4))
-    , fMat4x2_Type(new Type(SkString("mat4x2"), *fFloat_Type, 4, 2))
-    , fMat4x3_Type(new Type(SkString("mat4x3"), *fFloat_Type, 4, 3))
-    , fMat4x4_Type(new Type(SkString("mat4"),   *fFloat_Type, 4, 4))
-    , fDMat2x2_Type(new Type(SkString("dmat2"),   *fFloat_Type, 2, 2))
-    , fDMat2x3_Type(new Type(SkString("dmat2x3"), *fFloat_Type, 2, 3))
-    , fDMat2x4_Type(new Type(SkString("dmat2x4"), *fFloat_Type, 2, 4))
-    , fDMat3x2_Type(new Type(SkString("dmat3x2"), *fFloat_Type, 3, 2))
-    , fDMat3x3_Type(new Type(SkString("dmat3"),   *fFloat_Type, 3, 3))
-    , fDMat3x4_Type(new Type(SkString("dmat3x4"), *fFloat_Type, 3, 4))
-    , fDMat4x2_Type(new Type(SkString("dmat4x2"), *fFloat_Type, 4, 2))
-    , fDMat4x3_Type(new Type(SkString("dmat4x3"), *fFloat_Type, 4, 3))
-    , fDMat4x4_Type(new Type(SkString("dmat4"),   *fFloat_Type, 4, 4))
-    , fSampler1D_Type(new Type(SkString("sampler1D"), SpvDim1D, false, false, false, true))
-    , fSampler2D_Type(new Type(SkString("sampler2D"), SpvDim2D, false, false, false, true))
-    , fSampler3D_Type(new Type(SkString("sampler3D"), SpvDim3D, false, false, false, true))
-    , fSamplerExternalOES_Type(new Type(SkString("samplerExternalOES"), SpvDim2D, false, false,
+    , fIVec2_Type(new Type(String("ivec2"), *fInt_Type, 2))
+    , fIVec3_Type(new Type(String("ivec3"), *fInt_Type, 3))
+    , fIVec4_Type(new Type(String("ivec4"), *fInt_Type, 4))
+    , fBool_Type(new Type(String("bool"), false))
+    , fBVec2_Type(new Type(String("bvec2"), *fBool_Type, 2))
+    , fBVec3_Type(new Type(String("bvec3"), *fBool_Type, 3))
+    , fBVec4_Type(new Type(String("bvec4"), *fBool_Type, 4))
+    , fMat2x2_Type(new Type(String("mat2"),   *fFloat_Type, 2, 2))
+    , fMat2x3_Type(new Type(String("mat2x3"), *fFloat_Type, 2, 3))
+    , fMat2x4_Type(new Type(String("mat2x4"), *fFloat_Type, 2, 4))
+    , fMat3x2_Type(new Type(String("mat3x2"), *fFloat_Type, 3, 2))
+    , fMat3x3_Type(new Type(String("mat3"),   *fFloat_Type, 3, 3))
+    , fMat3x4_Type(new Type(String("mat3x4"), *fFloat_Type, 3, 4))
+    , fMat4x2_Type(new Type(String("mat4x2"), *fFloat_Type, 4, 2))
+    , fMat4x3_Type(new Type(String("mat4x3"), *fFloat_Type, 4, 3))
+    , fMat4x4_Type(new Type(String("mat4"),   *fFloat_Type, 4, 4))
+    , fDMat2x2_Type(new Type(String("dmat2"),   *fFloat_Type, 2, 2))
+    , fDMat2x3_Type(new Type(String("dmat2x3"), *fFloat_Type, 2, 3))
+    , fDMat2x4_Type(new Type(String("dmat2x4"), *fFloat_Type, 2, 4))
+    , fDMat3x2_Type(new Type(String("dmat3x2"), *fFloat_Type, 3, 2))
+    , fDMat3x3_Type(new Type(String("dmat3"),   *fFloat_Type, 3, 3))
+    , fDMat3x4_Type(new Type(String("dmat3x4"), *fFloat_Type, 3, 4))
+    , fDMat4x2_Type(new Type(String("dmat4x2"), *fFloat_Type, 4, 2))
+    , fDMat4x3_Type(new Type(String("dmat4x3"), *fFloat_Type, 4, 3))
+    , fDMat4x4_Type(new Type(String("dmat4"),   *fFloat_Type, 4, 4))
+    , fSampler1D_Type(new Type(String("sampler1D"), SpvDim1D, false, false, false, true))
+    , fSampler2D_Type(new Type(String("sampler2D"), SpvDim2D, false, false, false, true))
+    , fSampler3D_Type(new Type(String("sampler3D"), SpvDim3D, false, false, false, true))
+    , fSamplerExternalOES_Type(new Type(String("samplerExternalOES"), SpvDim2D, false, false,
                                         false, true))
-    , fSamplerCube_Type(new Type(SkString("samplerCube"), SpvDimCube, false, false, false, true))
-    , fSampler2DRect_Type(new Type(SkString("sampler2DRect"), SpvDimRect, false, false, false, 
+    , fSamplerCube_Type(new Type(String("samplerCube"), SpvDimCube, false, false, false, true))
+    , fSampler2DRect_Type(new Type(String("sampler2DRect"), SpvDimRect, false, false, false,
                                    true))
-    , fSampler1DArray_Type(new Type(SkString("sampler1DArray")))
-    , fSampler2DArray_Type(new Type(SkString("sampler2DArray")))
-    , fSamplerCubeArray_Type(new Type(SkString("samplerCubeArray")))
-    , fSamplerBuffer_Type(new Type(SkString("samplerBuffer")))
-    , fSampler2DMS_Type(new Type(SkString("sampler2DMS")))
-    , fSampler2DMSArray_Type(new Type(SkString("sampler2DMSArray")))
-    , fSampler1DShadow_Type(new Type(SkString("sampler1DShadow")))
-    , fSampler2DShadow_Type(new Type(SkString("sampler2DShadow")))
-    , fSamplerCubeShadow_Type(new Type(SkString("samplerCubeShadow")))
-    , fSampler2DRectShadow_Type(new Type(SkString("sampler2DRectShadow")))
-    , fSampler1DArrayShadow_Type(new Type(SkString("sampler1DArrayShadow")))
-    , fSampler2DArrayShadow_Type(new Type(SkString("sampler2DArrayShadow")))
-    , fSamplerCubeArrayShadow_Type(new Type(SkString("samplerCubeArrayShadow")))
+    , fSampler1DArray_Type(new Type(String("sampler1DArray")))
+    , fSampler2DArray_Type(new Type(String("sampler2DArray")))
+    , fSamplerCubeArray_Type(new Type(String("samplerCubeArray")))
+    , fSamplerBuffer_Type(new Type(String("samplerBuffer")))
+    , fSampler2DMS_Type(new Type(String("sampler2DMS")))
+    , fSampler2DMSArray_Type(new Type(String("sampler2DMSArray")))
+    , fSampler1DShadow_Type(new Type(String("sampler1DShadow")))
+    , fSampler2DShadow_Type(new Type(String("sampler2DShadow")))
+    , fSamplerCubeShadow_Type(new Type(String("samplerCubeShadow")))
+    , fSampler2DRectShadow_Type(new Type(String("sampler2DRectShadow")))
+    , fSampler1DArrayShadow_Type(new Type(String("sampler1DArrayShadow")))
+    , fSampler2DArrayShadow_Type(new Type(String("sampler2DArrayShadow")))
+    , fSamplerCubeArrayShadow_Type(new Type(String("samplerCubeArrayShadow")))
 
     // Related to below FIXME, gsampler*s don't currently expand to cover integer case.
-    , fISampler2D_Type(new Type(SkString("isampler2D"), SpvDim2D, false, false, false, true))
+    , fISampler2D_Type(new Type(String("isampler2D"), SpvDim2D, false, false, false, true))
 
     // FIXME express these as "gimage2D" that expand to image2D, iimage2D, and uimage2D.
-    , fImage2D_Type(new Type(SkString("image2D"), SpvDim2D, false, false, false, true))
-    , fIImage2D_Type(new Type(SkString("iimage2D"), SpvDim2D, false, false, false, true))
+    , fImage2D_Type(new Type(String("image2D"), SpvDim2D, false, false, false, true))
+    , fIImage2D_Type(new Type(String("iimage2D"), SpvDim2D, false, false, false, true))
 
     // FIXME express these as "gsubpassInput" that expand to subpassInput, isubpassInput,
     // and usubpassInput.
-    , fSubpassInput_Type(new Type(SkString("subpassInput"), SpvDimSubpassData, false, false,
+    , fSubpassInput_Type(new Type(String("subpassInput"), SpvDimSubpassData, false, false,
                                            false, false))
-    , fSubpassInputMS_Type(new Type(SkString("subpassInputMS"), SpvDimSubpassData, false, false,
+    , fSubpassInputMS_Type(new Type(String("subpassInputMS"), SpvDimSubpassData, false, false,
                                              true, false))
 
     // FIXME figure out what we're supposed to do with the gsampler et al. types)
-    , fGSampler1D_Type(new Type(SkString("$gsampler1D"), static_type(*fSampler1D_Type)))
-    , fGSampler2D_Type(new Type(SkString("$gsampler2D"), static_type(*fSampler2D_Type)))
-    , fGSampler3D_Type(new Type(SkString("$gsampler3D"), static_type(*fSampler3D_Type)))
-    , fGSamplerCube_Type(new Type(SkString("$gsamplerCube"), static_type(*fSamplerCube_Type)))
-    , fGSampler2DRect_Type(new Type(SkString("$gsampler2DRect"), static_type(*fSampler2DRect_Type)))
-    , fGSampler1DArray_Type(new Type(SkString("$gsampler1DArray"),
+    , fGSampler1D_Type(new Type(String("$gsampler1D"), static_type(*fSampler1D_Type)))
+    , fGSampler2D_Type(new Type(String("$gsampler2D"), static_type(*fSampler2D_Type)))
+    , fGSampler3D_Type(new Type(String("$gsampler3D"), static_type(*fSampler3D_Type)))
+    , fGSamplerCube_Type(new Type(String("$gsamplerCube"), static_type(*fSamplerCube_Type)))
+    , fGSampler2DRect_Type(new Type(String("$gsampler2DRect"), static_type(*fSampler2DRect_Type)))
+    , fGSampler1DArray_Type(new Type(String("$gsampler1DArray"),
                                      static_type(*fSampler1DArray_Type)))
-    , fGSampler2DArray_Type(new Type(SkString("$gsampler2DArray"),
+    , fGSampler2DArray_Type(new Type(String("$gsampler2DArray"),
                                      static_type(*fSampler2DArray_Type)))
-    , fGSamplerCubeArray_Type(new Type(SkString("$gsamplerCubeArray"),
+    , fGSamplerCubeArray_Type(new Type(String("$gsamplerCubeArray"),
                                        static_type(*fSamplerCubeArray_Type)))
-    , fGSamplerBuffer_Type(new Type(SkString("$gsamplerBuffer"), static_type(*fSamplerBuffer_Type)))
-    , fGSampler2DMS_Type(new Type(SkString("$gsampler2DMS"), static_type(*fSampler2DMS_Type)))
-    , fGSampler2DMSArray_Type(new Type(SkString("$gsampler2DMSArray"),
+    , fGSamplerBuffer_Type(new Type(String("$gsamplerBuffer"), static_type(*fSamplerBuffer_Type)))
+    , fGSampler2DMS_Type(new Type(String("$gsampler2DMS"), static_type(*fSampler2DMS_Type)))
+    , fGSampler2DMSArray_Type(new Type(String("$gsampler2DMSArray"),
                                        static_type(*fSampler2DMSArray_Type)))
-    , fGSampler2DArrayShadow_Type(new Type(SkString("$gsampler2DArrayShadow"),
+    , fGSampler2DArrayShadow_Type(new Type(String("$gsampler2DArrayShadow"),
                                            static_type(*fSampler2DArrayShadow_Type)))
-    , fGSamplerCubeArrayShadow_Type(new Type(SkString("$gsamplerCubeArrayShadow"),
+    , fGSamplerCubeArrayShadow_Type(new Type(String("$gsamplerCubeArrayShadow"),
                                              static_type(*fSamplerCubeArrayShadow_Type)))
-    , fGenType_Type(new Type(SkString("$genType"), { fFloat_Type.get(), fVec2_Type.get(),
+    , fGenType_Type(new Type(String("$genType"), { fFloat_Type.get(), fVec2_Type.get(),
                                                      fVec3_Type.get(), fVec4_Type.get() }))
-    , fGenDType_Type(new Type(SkString("$genDType"), { fDouble_Type.get(), fDVec2_Type.get(),
+    , fGenDType_Type(new Type(String("$genDType"), { fDouble_Type.get(), fDVec2_Type.get(),
                                                        fDVec3_Type.get(), fDVec4_Type.get() }))
-    , fGenIType_Type(new Type(SkString("$genIType"), { fInt_Type.get(), fIVec2_Type.get(),
+    , fGenIType_Type(new Type(String("$genIType"), { fInt_Type.get(), fIVec2_Type.get(),
                                                        fIVec3_Type.get(), fIVec4_Type.get() }))
-    , fGenUType_Type(new Type(SkString("$genUType"), { fUInt_Type.get(), fUVec2_Type.get(),
+    , fGenUType_Type(new Type(String("$genUType"), { fUInt_Type.get(), fUVec2_Type.get(),
                                                        fUVec3_Type.get(), fUVec4_Type.get() }))
-    , fGenBType_Type(new Type(SkString("$genBType"), { fBool_Type.get(), fBVec2_Type.get(),
+    , fGenBType_Type(new Type(String("$genBType"), { fBool_Type.get(), fBVec2_Type.get(),
                                                        fBVec3_Type.get(), fBVec4_Type.get() }))
-    , fMat_Type(new Type(SkString("$mat"), { fMat2x2_Type.get(), fMat2x3_Type.get(),
+    , fMat_Type(new Type(String("$mat"), { fMat2x2_Type.get(), fMat2x3_Type.get(),
                                              fMat2x4_Type.get(), fMat3x2_Type.get(),
                                              fMat3x3_Type.get(), fMat3x4_Type.get(),
                                              fMat4x2_Type.get(), fMat4x3_Type.get(),
@@ -135,21 +135,21 @@
                                              fDMat3x2_Type.get(), fDMat3x3_Type.get(),
                                              fDMat3x4_Type.get(), fDMat4x2_Type.get(),
                                              fDMat4x3_Type.get(), fDMat4x4_Type.get() }))
-    , fVec_Type(new Type(SkString("$vec"), { fInvalid_Type.get(), fVec2_Type.get(),
+    , fVec_Type(new Type(String("$vec"), { fInvalid_Type.get(), fVec2_Type.get(),
                                              fVec3_Type.get(), fVec4_Type.get() }))
-    , fGVec_Type(new Type(SkString("$gvec")))
-    , fGVec2_Type(new Type(SkString("$gvec2")))
-    , fGVec3_Type(new Type(SkString("$gvec3")))
-    , fGVec4_Type(new Type(SkString("$gvec4"), static_type(*fVec4_Type)))
-    , fDVec_Type(new Type(SkString("$dvec"), { fInvalid_Type.get(), fDVec2_Type.get(),
+    , fGVec_Type(new Type(String("$gvec")))
+    , fGVec2_Type(new Type(String("$gvec2")))
+    , fGVec3_Type(new Type(String("$gvec3")))
+    , fGVec4_Type(new Type(String("$gvec4"), static_type(*fVec4_Type)))
+    , fDVec_Type(new Type(String("$dvec"), { fInvalid_Type.get(), fDVec2_Type.get(),
                                               fDVec3_Type.get(), fDVec4_Type.get() }))
-    , fIVec_Type(new Type(SkString("$ivec"), { fInvalid_Type.get(), fIVec2_Type.get(),
+    , fIVec_Type(new Type(String("$ivec"), { fInvalid_Type.get(), fIVec2_Type.get(),
                                                fIVec3_Type.get(), fIVec4_Type.get() }))
-    , fUVec_Type(new Type(SkString("$uvec"), { fInvalid_Type.get(), fUVec2_Type.get(),
+    , fUVec_Type(new Type(String("$uvec"), { fInvalid_Type.get(), fUVec2_Type.get(),
                                                fUVec3_Type.get(), fUVec4_Type.get() }))
-    , fBVec_Type(new Type(SkString("$bvec"), { fInvalid_Type.get(), fBVec2_Type.get(),
+    , fBVec_Type(new Type(String("$bvec"), { fInvalid_Type.get(), fBVec2_Type.get(),
                                                fBVec3_Type.get(), fBVec4_Type.get() }))
-    , fSkCaps_Type(new Type(SkString("$sk_Caps")))
+    , fSkCaps_Type(new Type(String("$sk_Caps")))
     , fDefined_Expression(new Defined(*fInvalid_Type)) {}
 
     static std::vector<const Type*> static_type(const Type& t) {
@@ -269,19 +269,19 @@
 
     const std::unique_ptr<Type> fSkCaps_Type;
 
-    // dummy expression used to mark that a variable has a value during dataflow analysis (when it 
+    // dummy expression used to mark that a variable has a value during dataflow analysis (when it
     // could have several different values, or the analyzer is otherwise unable to assign it a
     // specific expression)
     const std::unique_ptr<Expression> fDefined_Expression;
 
-private:    
+private:
     class Defined : public Expression {
     public:
         Defined(const Type& type)
         : INHERITED(Position(), kDefined_Kind, type) {}
 
-        virtual SkString description() const override {
-            return SkString("<defined>");
+        virtual String description() const override {
+            return String("<defined>");
         }
 
         typedef Expression INHERITED;
diff --git a/src/sksl/SkSLErrorReporter.h b/src/sksl/SkSLErrorReporter.h
index 85d386d..172e488 100644
--- a/src/sksl/SkSLErrorReporter.h
+++ b/src/sksl/SkSLErrorReporter.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ERRORREPORTER
 #define SKSL_ERRORREPORTER
 
@@ -20,10 +20,10 @@
     virtual ~ErrorReporter() {}
 
     void error(Position position, const char* msg) {
-        this->error(position, SkString(msg));
+        this->error(position, String(msg));
     }
 
-    virtual void error(Position position, SkString msg) = 0;
+    virtual void error(Position position, String msg) = 0;
 
     virtual int errorCount() = 0;
 };
diff --git a/src/sksl/SkSLFileOutputStream.h b/src/sksl/SkSLFileOutputStream.h
new file mode 100644
index 0000000..f473930
--- /dev/null
+++ b/src/sksl/SkSLFileOutputStream.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_FILEOUTPUTSTREAM
+#define SKSL_FILEOUTPUTSTREAM
+
+#include "SkSLOutputStream.h"
+#include <stdio.h>
+
+namespace SkSL {
+
+class FileOutputStream : public OutputStream {
+public:
+    FileOutputStream(const char* name) {
+        fFile = fopen(name, "w");
+    }
+
+    ~FileOutputStream() {
+        ASSERT(!fOpen);
+    }
+
+    bool isValid() const override {
+        return nullptr != fFile;
+    }
+
+    void write8(uint8_t b) override {
+        ASSERT(fOpen);
+        if (isValid()) {
+            if (EOF == fputc(b, fFile)) {
+                fFile = nullptr;
+            }
+        }
+    }
+
+    void writeText(const char* s) override {
+        ASSERT(fOpen);
+        if (isValid()) {
+            if (EOF == fputs(s, fFile)) {
+                fFile = nullptr;
+            }
+        }
+    }
+
+    void write(const void* s, size_t size) override {
+        if (isValid()) {
+            size_t written = fwrite(s, 1, size, fFile);
+            if (written != size) {
+                fFile = nullptr;
+            }
+        }
+    }
+
+    bool close() {
+        fOpen = false;
+        if (isValid() && fclose(fFile)) {
+            fFile = nullptr;
+            return false;
+        }
+        return true;
+    }
+
+private:
+    bool fOpen = true;
+    FILE *fFile;
+
+    typedef OutputStream INHERITED;
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index a19de8f..ab64e66 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -7,8 +7,6 @@
 
 #include "SkSLGLSLCodeGenerator.h"
 
-#include "string.h"
-
 #include "GLSL.std.450.h"
 
 #include "SkSLCompiler.h"
@@ -35,15 +33,15 @@
 
 void GLSLCodeGenerator::writeLine(const char* s) {
     this->write(s);
-    fOut->writeText("\n");
+    fOut->write8('\n');
     fAtLineStart = true;
 }
 
-void GLSLCodeGenerator::write(const SkString& s) {
+void GLSLCodeGenerator::write(const String& s) {
     this->write(s.c_str());
 }
 
-void GLSLCodeGenerator::writeLine(const SkString& s) {
+void GLSLCodeGenerator::writeLine(const String& s) {
     this->writeLine(s.c_str());
 }
 
@@ -137,8 +135,8 @@
 // Tegra3 compiler bug.
 void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
     ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
-    SkString tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
-    SkString tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
+    String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
+    String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
     this->fFunctionHeader += "    " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
     this->fFunctionHeader += "    " + otherExpr.fType.name() + " " + tmpVar2 + ";\n";
     this->write("((" + tmpVar1 + " = ");
@@ -411,7 +409,7 @@
     }
 }
 
-void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b, 
+void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
                                               Precedence parentPrecedence) {
     Precedence precedence = get_binary_precedence(b.fOperator);
     if (precedence >= parentPrecedence) {
@@ -425,7 +423,7 @@
     }
 }
 
-void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t, 
+void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
                                                Precedence parentPrecedence) {
     if (kTernary_Precedence >= parentPrecedence) {
         this->write("(");
@@ -440,7 +438,7 @@
     }
 }
 
-void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p, 
+void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
                                               Precedence parentPrecedence) {
     if (kPrefix_Precedence >= parentPrecedence) {
         this->write("(");
@@ -452,7 +450,7 @@
     }
 }
 
-void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p, 
+void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
                                                Precedence parentPrecedence) {
     if (kPostfix_Precedence >= parentPrecedence) {
         this->write("(");
@@ -507,8 +505,8 @@
     this->writeLine(") {");
 
     fFunctionHeader = "";
-    SkWStream* oldOut = fOut;
-    SkDynamicMemoryWStream buffer;
+    OutputStream* oldOut = fOut;
+    StringStream buffer;
     fOut = &buffer;
     fIndentation++;
     for (const auto& s : f.fBody->fStatements) {
@@ -520,8 +518,7 @@
 
     fOut = oldOut;
     this->write(fFunctionHeader);
-    sk_sp<SkData> data(buffer.detachAsData());
-    this->write(SkString((const char*) data->data(), data->size()));
+    this->write(String(buffer.data(), buffer.size()));
 }
 
 void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
@@ -532,7 +529,7 @@
     if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
         this->write("noperspective ");
     }
-    SkString layout = modifiers.fLayout.description();
+    String layout = modifiers.fLayout.description();
     if (layout.size()) {
         this->write(layout + " ");
     }
@@ -625,11 +622,11 @@
     ASSERT(decl.fVars.size() > 0);
     this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
     this->writeType(decl.fBaseType);
-    SkString separator(" ");
+    String separator(" ");
     for (const auto& var : decl.fVars) {
         ASSERT(var.fVar->fModifiers == decl.fVars[0].fVar->fModifiers);
         this->write(separator);
-        separator = SkString(", ");
+        separator = String(", ");
         this->write(var.fVar->fName);
         for (const auto& size : var.fSizes) {
             this->write("[");
@@ -663,7 +660,7 @@
             this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
             this->write(";");
             break;
-        case Statement::kReturn_Kind: 
+        case Statement::kReturn_Kind:
             this->writeReturnStatement((ReturnStatement&) s);
             break;
         case Statement::kVarDeclarations_Kind:
@@ -787,7 +784,7 @@
 }
 
 bool GLSLCodeGenerator::generateCode() {
-    SkWStream* rawOut = fOut;
+    OutputStream* rawOut = fOut;
     fOut = &fHeader;
     fProgramKind = fProgram.fKind;
     this->write(fProgram.fSettings.fCaps->versionDeclString());
@@ -797,7 +794,7 @@
             this->writeExtension((Extension&) *e);
         }
     }
-    SkDynamicMemoryWStream body;
+    StringStream body;
     fOut = &body;
     if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
         this->write("precision ");
@@ -857,8 +854,8 @@
     }
     fOut = nullptr;
 
-    write_data(*fHeader.detachAsData(), *rawOut);
-    write_data(*body.detachAsData(), *rawOut);
+    write_stringstream(fHeader, *rawOut);
+    write_stringstream(body, *rawOut);
     return true;
 }
 
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 907c305..ab88d50 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -12,7 +12,6 @@
 #include <tuple>
 #include <unordered_map>
 
-#include "SkStream.h"
 #include "SkSLCodeGenerator.h"
 #include "ir/SkSLBinaryExpression.h"
 #include "ir/SkSLBoolLiteral.h"
@@ -73,7 +72,7 @@
     };
 
     GLSLCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
-                      SkWStream* out)
+                      OutputStream* out)
     : INHERITED(program, errors, out)
     , fContext(*context) {}
 
@@ -86,9 +85,9 @@
 
     void writeLine(const char* s);
 
-    void write(const SkString& s);
+    void write(const String& s);
 
-    void writeLine(const SkString& s);
+    void writeLine(const String& s);
 
     void writeType(const Type& type);
 
@@ -97,7 +96,7 @@
     void writeInterfaceBlock(const InterfaceBlock& intf);
 
     void writeFunctionStart(const FunctionDeclaration& f);
-    
+
     void writeFunctionDeclaration(const FunctionDeclaration& f);
 
     void writeFunction(const FunctionDefinition& f);
@@ -161,8 +160,8 @@
     void writeReturnStatement(const ReturnStatement& r);
 
     const Context& fContext;
-    SkDynamicMemoryWStream fHeader;
-    SkString fFunctionHeader;
+    StringStream fHeader;
+    String fFunctionHeader;
     Program::Kind fProgramKind;
     int fVarCount = 0;
     int fIndentation = 0;
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 2a4c85d..9910513 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -115,8 +115,8 @@
     fSymbolTable = fSymbolTable->fParent;
 }
 
-static void fill_caps(const GrShaderCaps& caps, std::unordered_map<SkString, CapValue>* capsMap) {
-#define CAP(name) capsMap->insert(std::make_pair(SkString(#name), CapValue(caps.name())));
+static void fill_caps(const SKSL_CAPS_CLASS& caps, std::unordered_map<String, CapValue>* capsMap) {
+#define CAP(name) capsMap->insert(std::make_pair(String(#name), CapValue(caps.name())));
     CAP(fbFetchSupport);
     CAP(fbFetchNeedsCustomOutput);
     CAP(bindlessTextureSupport);
@@ -224,7 +224,7 @@
                 if (!size) {
                     return nullptr;
                 }
-                SkString name = type->fName;
+                String name = type->fName;
                 int64_t count;
                 if (size->fKind == Expression::kIntLiteral_Kind) {
                     count = ((IntLiteral&) *size).fValue;
@@ -255,7 +255,7 @@
             }
             value = this->coerce(std::move(value), *type);
         }
-        if (storage == Variable::kGlobal_Storage && varDecl.fName == SkString("sk_FragColor") &&
+        if (storage == Variable::kGlobal_Storage && varDecl.fName == String("sk_FragColor") &&
             (*fSymbolTable)[varDecl.fName]) {
             // already defined, ignore
         } else if (storage == Variable::kGlobal_Storage && (*fSymbolTable)[varDecl.fName] &&
@@ -501,12 +501,12 @@
         }
         for (int j = (int) param->fSizes.size() - 1; j >= 0; j--) {
             int size = param->fSizes[j];
-            SkString name = type->name() + "[" + to_string(size) + "]";
+            String name = type->name() + "[" + to_string(size) + "]";
             Type* newType = new Type(std::move(name), Type::kArray_Kind, *type, size);
             fSymbolTable->takeOwnership(newType);
             type = newType;
         }
-        SkString name = param->fName;
+        String name = param->fName;
         Position pos = param->fPosition;
         Variable* var = new Variable(pos, param->fModifiers, std::move(name), *type,
                                      Variable::kParameter_Storage);
@@ -632,7 +632,7 @@
             if (!converted) {
                 return nullptr;
             }
-            SkString name = type->fName;
+            String name = type->fName;
             int64_t count;
             if (converted->fKind == Expression::kIntLiteral_Kind) {
                 count = ((IntLiteral&) *converted).fValue;
@@ -677,7 +677,7 @@
     const Symbol* result = (*fSymbolTable)[type.fName];
     if (result && result->fKind == Symbol::kType_Kind) {
         for (int size : type.fSizes) {
-            SkString name = result->fName + "[";
+            String name = result->fName + "[";
             if (size != -1) {
                 name += to_string(size);
             }
@@ -1116,7 +1116,7 @@
                                               const FunctionDeclaration& function,
                                               std::vector<std::unique_ptr<Expression>> arguments) {
     if (function.fParameters.size() != arguments.size()) {
-        SkString msg = "call to '" + function.fName + "' expected " +
+        String msg = "call to '" + function.fName + "' expected " +
                                  to_string((uint64_t) function.fParameters.size()) +
                                  " argument";
         if (function.fParameters.size() != 1) {
@@ -1129,8 +1129,8 @@
     std::vector<const Type*> types;
     const Type* returnType;
     if (!function.determineFinalTypes(arguments, &types, &returnType)) {
-        SkString msg = "no match for " + function.fName + "(";
-        SkString separator;
+        String msg = "no match for " + function.fName + "(";
+        String separator;
         for (size_t i = 0; i < arguments.size(); i++) {
             msg += separator;
             separator = ", ";
@@ -1208,8 +1208,8 @@
         if (best) {
             return this->call(position, *best, std::move(arguments));
         }
-        SkString msg = "no match for " + ref->fFunctions[0]->fName + "(";
-        SkString separator;
+        String msg = "no match for " + ref->fFunctions[0]->fName + "(";
+        String separator;
         for (size_t i = 0; i < arguments.size(); i++) {
             msg += separator;
             separator = ", ";
@@ -1466,7 +1466,7 @@
 }
 
 std::unique_ptr<Expression> IRGenerator::convertField(std::unique_ptr<Expression> base,
-                                                      const SkString& field) {
+                                                      const String& field) {
     auto fields = base->fType.fields();
     for (size_t i = 0; i < fields.size(); i++) {
         if (fields[i].fName == field) {
@@ -1479,7 +1479,7 @@
 }
 
 std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expression> base,
-                                                        const SkString& fields) {
+                                                        const String& fields) {
     if (base->fType.kind() != Type::kVector_Kind) {
         fErrors.error(base->fPosition, "cannot swizzle type '" + base->fType.description() + "'");
         return nullptr;
@@ -1517,7 +1517,7 @@
                 }
                 // fall through
             default:
-                fErrors.error(base->fPosition, SkStringPrintf("invalid swizzle component '%c'",
+                fErrors.error(base->fPosition, String::printf("invalid swizzle component '%c'",
                                                               fields[i]));
                 return nullptr;
         }
@@ -1530,7 +1530,7 @@
     return std::unique_ptr<Expression>(new Swizzle(fContext, std::move(base), swizzleComponents));
 }
 
-std::unique_ptr<Expression> IRGenerator::getCap(Position position, SkString name) {
+std::unique_ptr<Expression> IRGenerator::getCap(Position position, String name) {
     auto found = fCapsMap.find(name);
     if (found == fCapsMap.end()) {
         fErrors.error(position, "unknown capability flag '" + name + "'");
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index fb79cda..b0a449a 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -154,12 +154,12 @@
     Modifiers convertModifiers(const Modifiers& m);
     std::unique_ptr<Expression> convertPrefixExpression(const ASTPrefixExpression& expression);
     std::unique_ptr<Statement> convertReturn(const ASTReturnStatement& r);
-    std::unique_ptr<Expression> getCap(Position position, SkString name);
+    std::unique_ptr<Expression> getCap(Position position, String name);
     std::unique_ptr<Expression> convertSuffixExpression(const ASTSuffixExpression& expression);
     std::unique_ptr<Expression> convertField(std::unique_ptr<Expression> base,
-                                             const SkString& field);
+                                             const String& field);
     std::unique_ptr<Expression> convertSwizzle(std::unique_ptr<Expression> base,
-                                               const SkString& fields);
+                                               const String& fields);
     std::unique_ptr<Expression> convertTernaryExpression(const ASTTernaryExpression& expression);
     std::unique_ptr<Statement> convertVarDeclarationStatement(const ASTVarDeclarationStatement& s);
     std::unique_ptr<Statement> convertWhile(const ASTWhileStatement& w);
@@ -169,7 +169,7 @@
 
     const FunctionDeclaration* fCurrentFunction;
     const Program::Settings* fSettings;
-    std::unordered_map<SkString, CapValue> fCapsMap;
+    std::unordered_map<String, CapValue> fCapsMap;
     std::shared_ptr<SymbolTable> fSymbolTable;
     int fLoopLevel;
     int fSwitchLevel;
diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp
index 46e9c18..1461bf9 100644
--- a/src/sksl/SkSLMain.cpp
+++ b/src/sksl/SkSLMain.cpp
@@ -8,7 +8,7 @@
 #include "stdio.h"
 #include <fstream>
 #include "SkSLCompiler.h"
-#include "GrContextOptions.h"
+#include "SkSLFileOutputStream.h"
 
 /**
  * Very simple standalone executable to facilitate testing.
@@ -34,17 +34,15 @@
     std::ifstream in(argv[1]);
     std::string stdText((std::istreambuf_iterator<char>(in)),
                         std::istreambuf_iterator<char>());
-    SkString text(stdText.c_str());
+    SkSL::String text(stdText.c_str());
     if (in.rdstate()) {
         printf("error reading '%s'\n", argv[1]);
         exit(2);
     }
     SkSL::Program::Settings settings;
-    sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
-    settings.fCaps = caps.get();
-    SkString name(argv[2]);
+    SkSL::String name(argv[2]);
     if (name.endsWith(".spirv")) {
-        SkFILEWStream out(argv[2]);
+        SkSL::FileOutputStream out(argv[2]);
         SkSL::Compiler compiler;
         if (!out.isValid()) {
             printf("error writing '%s'\n", argv[2]);
@@ -55,8 +53,12 @@
             printf("%s", compiler.errorText().c_str());
             exit(3);
         }
+        if (!out.close()) {
+            printf("error writing '%s'\n", argv[2]);
+            exit(4);
+        }
     } else if (name.endsWith(".glsl")) {
-        SkFILEWStream out(argv[2]);
+        SkSL::FileOutputStream out(argv[2]);
         SkSL::Compiler compiler;
         if (!out.isValid()) {
             printf("error writing '%s'\n", argv[2]);
@@ -67,6 +69,10 @@
             printf("%s", compiler.errorText().c_str());
             exit(3);
         }
+        if (!out.close()) {
+            printf("error writing '%s'\n", argv[2]);
+            exit(4);
+        }
     } else {
         printf("expected output filename to end with '.spirv' or '.glsl'");
     }
diff --git a/src/sksl/SkSLMemoryLayout.h b/src/sksl/SkSLMemoryLayout.h
index 95a292f..61712ec 100644
--- a/src/sksl/SkSLMemoryLayout.h
+++ b/src/sksl/SkSLMemoryLayout.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKIASL_MEMORYLAYOUT
 #define SKIASL_MEMORYLAYOUT
 
@@ -19,14 +19,14 @@
         k430_Standard
     };
 
-    MemoryLayout(Standard std) 
+    MemoryLayout(Standard std)
     : fStd(std) {}
 
     static size_t vector_alignment(size_t componentSize, int columns) {
         return componentSize * (columns + columns % 2);
     }
 
-    /** 
+    /**
      * Rounds up to the nearest multiple of 16 if in std140, otherwise returns the parameter
      * unchanged (std140 requires various things to be rounded up to the nearest multiple of 16,
      * std430 does not).
@@ -50,7 +50,7 @@
             case Type::kVector_Kind:
                 return vector_alignment(this->size(type.componentType()), type.columns());
             case Type::kMatrix_Kind:
-                return this->roundUpIfNeeded(vector_alignment(this->size(type.componentType()), 
+                return this->roundUpIfNeeded(vector_alignment(this->size(type.componentType()),
                                                               type.rows()));
             case Type::kArray_Kind:
                 return this->roundUpIfNeeded(this->alignment(type.componentType()));
@@ -65,7 +65,7 @@
                 return this->roundUpIfNeeded(result);
             }
             default:
-                ABORT(("cannot determine size of type " + type.name()).c_str());
+                ABORT("cannot determine size of type %s", type.name().c_str());
         }
     }
 
@@ -111,12 +111,12 @@
                     total += this->size(*f.fType);
                 }
                 size_t alignment = this->alignment(type);
-                ASSERT(!type.fields().size() || 
+                ASSERT(!type.fields().size() ||
                        (0 == alignment % this->alignment(*type.fields()[0].fType)));
                 return (total + alignment - 1) & ~(alignment - 1);
             }
             default:
-                ABORT(("cannot determine size of type " + type.name()).c_str());
+                ABORT("cannot determine size of type %s", type.name().c_str());
         }
     }
 
diff --git a/src/sksl/SkSLOutputStream.h b/src/sksl/SkSLOutputStream.h
new file mode 100644
index 0000000..62be61e
--- /dev/null
+++ b/src/sksl/SkSLOutputStream.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_OUTPUTSTREAM
+#define SKSL_OUTPUTSTREAM
+
+#include "SkSLString.h"
+
+namespace SkSL {
+
+class OutputStream {
+public:
+    virtual bool isValid() const {
+        return true;
+    }
+
+    virtual void write8(uint8_t b) = 0;
+
+    virtual void writeText(const char* s) = 0;
+
+    virtual void write(const void* s, size_t size) = 0;
+
+    void writeString(String s) {
+        this->write(s.c_str(), s.size());
+    }
+
+    virtual ~OutputStream() {}
+};
+
+} // namespace
+
+#endif
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index e24685a..1004de8 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -79,7 +79,7 @@
 
     bool checkValid() {
         if (fParser->fDepth > MAX_PARSE_DEPTH) {
-            fParser->error(fParser->peek().fPosition, SkString("exceeded max parse depth"));
+            fParser->error(fParser->peek().fPosition, String("exceeded max parse depth"));
             return false;
         }
         return true;
@@ -89,8 +89,8 @@
     Parser* fParser;
 };
 
-Parser::Parser(SkString text, SymbolTable& types, ErrorReporter& errors)
-: fPushback(Position(-1, -1), Token::INVALID_TOKEN, SkString())
+Parser::Parser(String text, SymbolTable& types, ErrorReporter& errors)
+: fPushback(Position(-1, -1), Token::INVALID_TOKEN, String())
 , fTypes(types)
 , fErrors(errors) {
     sksllex_init(&fScanner);
@@ -150,17 +150,17 @@
         return result;
     }
     int token = sksllex(fScanner);
-    SkString text;
+    String text;
     switch ((Token::Kind) token) {
         case Token::IDENTIFIER:    // fall through
         case Token::INT_LITERAL:   // fall through
         case Token::FLOAT_LITERAL: // fall through
         case Token::DIRECTIVE:
-            text = SkString(skslget_text(fScanner));
+            text = String(skslget_text(fScanner));
             break;
         default:
 #ifdef SK_DEBUG
-            text = SkString(skslget_text(fScanner));
+            text = String(skslget_text(fScanner));
 #endif
             break;
     }
@@ -179,10 +179,10 @@
 
 
 bool Parser::expect(Token::Kind kind, const char* expected, Token* result) {
-    return this->expect(kind, SkString(expected), result);
+    return this->expect(kind, String(expected), result);
 }
 
-bool Parser::expect(Token::Kind kind, SkString expected, Token* result) {
+bool Parser::expect(Token::Kind kind, String expected, Token* result) {
     Token next = this->nextToken();
     if (next.fKind == kind) {
         if (result) {
@@ -201,14 +201,14 @@
 }
 
 void Parser::error(Position p, const char* msg) {
-    this->error(p, SkString(msg));
+    this->error(p, String(msg));
 }
 
-void Parser::error(Position p, SkString msg) {
+void Parser::error(Position p, String msg) {
     fErrors.error(p, msg);
 }
 
-bool Parser::isType(SkString name) {
+bool Parser::isType(String name) {
     return nullptr != fTypes[name];
 }
 
@@ -380,7 +380,7 @@
                     return nullptr;
                 }
                 uint64_t columns = ((ASTIntLiteral&) *var.fSizes[i]).fValue;
-                SkString name = type->name() + "[" + to_string(columns) + "]";
+                String name = type->name() + "[" + to_string(columns) + "]";
                 type = new Type(name, Type::kArray_Kind, *type, (int) columns);
                 fTypes.takeOwnership((Type*) type);
             }
@@ -427,7 +427,7 @@
    (LBRACKET expression? RBRACKET)* (EQ expression)?)* SEMICOLON */
 std::unique_ptr<ASTVarDeclarations> Parser::varDeclarationEnd(Modifiers mods,
                                                               std::unique_ptr<ASTType> type,
-                                                              SkString name) {
+                                                              String name) {
     std::vector<ASTVarDeclaration> vars;
     std::vector<std::unique_ptr<ASTExpression>> currentVarSizes;
     while (this->peek().fKind == Token::LBRACKET) {
@@ -837,7 +837,7 @@
         decls.push_back(std::move(decl));
     }
     this->nextToken();
-    SkString instanceName;
+    String instanceName;
     std::vector<std::unique_ptr<ASTExpression>> sizes;
     if (this->peek().fKind == Token::IDENTIFIER) {
         instanceName = this->nextToken().fText;
@@ -1008,7 +1008,7 @@
     // parts of the compiler may rely upon this assumption.
     if (this->peek().fKind == Token::DEFAULT) {
         Token defaultStart;
-        SkAssertResult(this->expect(Token::DEFAULT, "'default'", &defaultStart));
+        ASSERT_RESULT(this->expect(Token::DEFAULT, "'default'", &defaultStart));
         if (!this->expect(Token::COLON, "':'")) {
             return nullptr;
         }
@@ -1562,7 +1562,7 @@
         }
         case Token::DOT: {
             Position pos = this->peek().fPosition;
-            SkString text;
+            String text;
             if (this->identifier(&text)) {
                 return std::unique_ptr<ASTSuffix>(new ASTFieldSuffix(pos, std::move(text)));
             }
@@ -1607,7 +1607,7 @@
     Token t = this->peek();
     switch (t.fKind) {
         case Token::IDENTIFIER: {
-            SkString text;
+            String text;
             if (this->identifier(&text)) {
                 result.reset(new ASTIdentifier(t.fPosition, std::move(text)));
             }
@@ -1688,7 +1688,7 @@
 }
 
 /* IDENTIFIER */
-bool Parser::identifier(SkString* dest) {
+bool Parser::identifier(String* dest) {
     Token t;
     if (this->expect(Token::IDENTIFIER, "identifier", &t)) {
         *dest = t.fText;
diff --git a/src/sksl/SkSLParser.h b/src/sksl/SkSLParser.h
index 9be017c..0fa00cb 100644
--- a/src/sksl/SkSLParser.h
+++ b/src/sksl/SkSLParser.h
@@ -51,7 +51,7 @@
  */
 class Parser {
 public:
-    Parser(SkString text, SymbolTable& types, ErrorReporter& errors);
+    Parser(String text, SymbolTable& types, ErrorReporter& errors);
 
     ~Parser();
 
@@ -90,16 +90,16 @@
      * Returns true if the read token was as expected, false otherwise.
      */
     bool expect(Token::Kind kind, const char* expected, Token* result = nullptr);
-    bool expect(Token::Kind kind, SkString expected, Token* result = nullptr);
+    bool expect(Token::Kind kind, String expected, Token* result = nullptr);
 
     void error(Position p, const char* msg);
-    void error(Position p, SkString msg);
-   
+    void error(Position p, String msg);
+
     /**
      * Returns true if the 'name' identifier refers to a type name. For instance, isType("int") will
      * always return true.
      */
-    bool isType(SkString name);
+    bool isType(String name);
 
     // these functions parse individual grammar rules from the current parse position; you probably
     // don't need to call any of these outside of the parser. The function declarations in the .cpp
@@ -119,12 +119,12 @@
 
     std::unique_ptr<ASTVarDeclarations> varDeclarationEnd(Modifiers modifiers,
                                                           std::unique_ptr<ASTType> type,
-                                                          SkString name);
+                                                          String name);
 
     std::unique_ptr<ASTParameter> parameter();
 
     int layoutInt();
-   
+
     Layout layout();
 
     Modifiers modifiers();
@@ -164,7 +164,7 @@
     std::unique_ptr<ASTExpression> expression();
 
     std::unique_ptr<ASTExpression> assignmentExpression();
-   
+
     std::unique_ptr<ASTExpression> ternaryExpression();
 
     std::unique_ptr<ASTExpression> logicalOrExpression();
@@ -203,7 +203,7 @@
 
     bool boolLiteral(bool* dest);
 
-    bool identifier(SkString* dest);
+    bool identifier(String* dest);
 
     void* fScanner;
     void* fLayoutScanner;
diff --git a/src/sksl/SkSLPosition.h b/src/sksl/SkSLPosition.h
index b1841c5..83cfe82 100644
--- a/src/sksl/SkSLPosition.h
+++ b/src/sksl/SkSLPosition.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_POSITION
 #define SKSL_POSITION
 
@@ -17,15 +17,15 @@
  * ignored.
  */
 struct Position {
-    Position() 
+    Position()
     : fLine(-1)
     , fColumn(-1) {}
-    
+
     Position(int line, int column)
     : fLine(line)
     , fColumn(column) {}
 
-    SkString description() const {
+    String description() const {
         return to_string(fLine);
     }
 
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index 2fa4e64..2b8feb9 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -4,10 +4,8 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
-#include "SkSLSPIRVCodeGenerator.h"
 
-#include "string.h"
+#include "SkSLSPIRVCodeGenerator.h"
 
 #include "GLSL.std.450.h"
 
@@ -34,112 +32,111 @@
 #define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
                                    k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
                                    k ## x ## _SpecialIntrinsic)
-    fIntrinsicMap[SkString("round")]         = ALL_GLSL(Round);
-    fIntrinsicMap[SkString("roundEven")]     = ALL_GLSL(RoundEven);
-    fIntrinsicMap[SkString("trunc")]         = ALL_GLSL(Trunc);
-    fIntrinsicMap[SkString("abs")]           = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
-    fIntrinsicMap[SkString("sign")]          = BY_TYPE_GLSL(FSign, SSign, SSign);
-    fIntrinsicMap[SkString("floor")]         = ALL_GLSL(Floor);
-    fIntrinsicMap[SkString("ceil")]          = ALL_GLSL(Ceil);
-    fIntrinsicMap[SkString("fract")]         = ALL_GLSL(Fract);
-    fIntrinsicMap[SkString("radians")]       = ALL_GLSL(Radians);
-    fIntrinsicMap[SkString("degrees")]       = ALL_GLSL(Degrees);
-    fIntrinsicMap[SkString("sin")]           = ALL_GLSL(Sin);
-    fIntrinsicMap[SkString("cos")]           = ALL_GLSL(Cos);
-    fIntrinsicMap[SkString("tan")]           = ALL_GLSL(Tan);
-    fIntrinsicMap[SkString("asin")]          = ALL_GLSL(Asin);
-    fIntrinsicMap[SkString("acos")]          = ALL_GLSL(Acos);
-    fIntrinsicMap[SkString("atan")]          = SPECIAL(Atan);
-    fIntrinsicMap[SkString("sinh")]          = ALL_GLSL(Sinh);
-    fIntrinsicMap[SkString("cosh")]          = ALL_GLSL(Cosh);
-    fIntrinsicMap[SkString("tanh")]          = ALL_GLSL(Tanh);
-    fIntrinsicMap[SkString("asinh")]         = ALL_GLSL(Asinh);
-    fIntrinsicMap[SkString("acosh")]         = ALL_GLSL(Acosh);
-    fIntrinsicMap[SkString("atanh")]         = ALL_GLSL(Atanh);
-    fIntrinsicMap[SkString("pow")]           = ALL_GLSL(Pow);
-    fIntrinsicMap[SkString("exp")]           = ALL_GLSL(Exp);
-    fIntrinsicMap[SkString("log")]           = ALL_GLSL(Log);
-    fIntrinsicMap[SkString("exp2")]          = ALL_GLSL(Exp2);
-    fIntrinsicMap[SkString("log2")]          = ALL_GLSL(Log2);
-    fIntrinsicMap[SkString("sqrt")]          = ALL_GLSL(Sqrt);
-    fIntrinsicMap[SkString("inversesqrt")]   = ALL_GLSL(InverseSqrt);
-    fIntrinsicMap[SkString("determinant")]   = ALL_GLSL(Determinant);
-    fIntrinsicMap[SkString("matrixInverse")] = ALL_GLSL(MatrixInverse);
-    fIntrinsicMap[SkString("mod")]           = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod,
+    fIntrinsicMap[String("round")]         = ALL_GLSL(Round);
+    fIntrinsicMap[String("roundEven")]     = ALL_GLSL(RoundEven);
+    fIntrinsicMap[String("trunc")]         = ALL_GLSL(Trunc);
+    fIntrinsicMap[String("abs")]           = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
+    fIntrinsicMap[String("sign")]          = BY_TYPE_GLSL(FSign, SSign, SSign);
+    fIntrinsicMap[String("floor")]         = ALL_GLSL(Floor);
+    fIntrinsicMap[String("ceil")]          = ALL_GLSL(Ceil);
+    fIntrinsicMap[String("fract")]         = ALL_GLSL(Fract);
+    fIntrinsicMap[String("radians")]       = ALL_GLSL(Radians);
+    fIntrinsicMap[String("degrees")]       = ALL_GLSL(Degrees);
+    fIntrinsicMap[String("sin")]           = ALL_GLSL(Sin);
+    fIntrinsicMap[String("cos")]           = ALL_GLSL(Cos);
+    fIntrinsicMap[String("tan")]           = ALL_GLSL(Tan);
+    fIntrinsicMap[String("asin")]          = ALL_GLSL(Asin);
+    fIntrinsicMap[String("acos")]          = ALL_GLSL(Acos);
+    fIntrinsicMap[String("atan")]          = SPECIAL(Atan);
+    fIntrinsicMap[String("sinh")]          = ALL_GLSL(Sinh);
+    fIntrinsicMap[String("cosh")]          = ALL_GLSL(Cosh);
+    fIntrinsicMap[String("tanh")]          = ALL_GLSL(Tanh);
+    fIntrinsicMap[String("asinh")]         = ALL_GLSL(Asinh);
+    fIntrinsicMap[String("acosh")]         = ALL_GLSL(Acosh);
+    fIntrinsicMap[String("atanh")]         = ALL_GLSL(Atanh);
+    fIntrinsicMap[String("pow")]           = ALL_GLSL(Pow);
+    fIntrinsicMap[String("exp")]           = ALL_GLSL(Exp);
+    fIntrinsicMap[String("log")]           = ALL_GLSL(Log);
+    fIntrinsicMap[String("exp2")]          = ALL_GLSL(Exp2);
+    fIntrinsicMap[String("log2")]          = ALL_GLSL(Log2);
+    fIntrinsicMap[String("sqrt")]          = ALL_GLSL(Sqrt);
+    fIntrinsicMap[String("inversesqrt")]   = ALL_GLSL(InverseSqrt);
+    fIntrinsicMap[String("determinant")]   = ALL_GLSL(Determinant);
+    fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
+    fIntrinsicMap[String("mod")]           = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod,
                                                                SpvOpSMod, SpvOpUMod, SpvOpUndef);
-    fIntrinsicMap[SkString("min")]           = BY_TYPE_GLSL(FMin, SMin, UMin);
-    fIntrinsicMap[SkString("max")]           = BY_TYPE_GLSL(FMax, SMax, UMax);
-    fIntrinsicMap[SkString("clamp")]         = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
-    fIntrinsicMap[SkString("dot")]           = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
+    fIntrinsicMap[String("min")]           = BY_TYPE_GLSL(FMin, SMin, UMin);
+    fIntrinsicMap[String("max")]           = BY_TYPE_GLSL(FMax, SMax, UMax);
+    fIntrinsicMap[String("clamp")]         = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
+    fIntrinsicMap[String("dot")]           = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
                                                                SpvOpUndef, SpvOpUndef, SpvOpUndef);
-    fIntrinsicMap[SkString("mix")]           = ALL_GLSL(FMix);
-    fIntrinsicMap[SkString("step")]          = ALL_GLSL(Step);
-    fIntrinsicMap[SkString("smoothstep")]    = ALL_GLSL(SmoothStep);
-    fIntrinsicMap[SkString("fma")]           = ALL_GLSL(Fma);
-    fIntrinsicMap[SkString("frexp")]         = ALL_GLSL(Frexp);
-    fIntrinsicMap[SkString("ldexp")]         = ALL_GLSL(Ldexp);
+    fIntrinsicMap[String("mix")]           = ALL_GLSL(FMix);
+    fIntrinsicMap[String("step")]          = ALL_GLSL(Step);
+    fIntrinsicMap[String("smoothstep")]    = ALL_GLSL(SmoothStep);
+    fIntrinsicMap[String("fma")]           = ALL_GLSL(Fma);
+    fIntrinsicMap[String("frexp")]         = ALL_GLSL(Frexp);
+    fIntrinsicMap[String("ldexp")]         = ALL_GLSL(Ldexp);
 
-#define PACK(type) fIntrinsicMap[SkString("pack" #type)] = ALL_GLSL(Pack ## type); \
-                   fIntrinsicMap[SkString("unpack" #type)] = ALL_GLSL(Unpack ## type)
+#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
+                   fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
     PACK(Snorm4x8);
     PACK(Unorm4x8);
     PACK(Snorm2x16);
     PACK(Unorm2x16);
     PACK(Half2x16);
     PACK(Double2x32);
-    fIntrinsicMap[SkString("length")]      = ALL_GLSL(Length);
-    fIntrinsicMap[SkString("distance")]    = ALL_GLSL(Distance);
-    fIntrinsicMap[SkString("cross")]       = ALL_GLSL(Cross);
-    fIntrinsicMap[SkString("normalize")]   = ALL_GLSL(Normalize);
-    fIntrinsicMap[SkString("faceForward")] = ALL_GLSL(FaceForward);
-    fIntrinsicMap[SkString("reflect")]     = ALL_GLSL(Reflect);
-    fIntrinsicMap[SkString("refract")]     = ALL_GLSL(Refract);
-    fIntrinsicMap[SkString("findLSB")]     = ALL_GLSL(FindILsb);
-    fIntrinsicMap[SkString("findMSB")]     = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
-    fIntrinsicMap[SkString("dFdx")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
+    fIntrinsicMap[String("length")]      = ALL_GLSL(Length);
+    fIntrinsicMap[String("distance")]    = ALL_GLSL(Distance);
+    fIntrinsicMap[String("cross")]       = ALL_GLSL(Cross);
+    fIntrinsicMap[String("normalize")]   = ALL_GLSL(Normalize);
+    fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
+    fIntrinsicMap[String("reflect")]     = ALL_GLSL(Reflect);
+    fIntrinsicMap[String("refract")]     = ALL_GLSL(Refract);
+    fIntrinsicMap[String("findLSB")]     = ALL_GLSL(FindILsb);
+    fIntrinsicMap[String("findMSB")]     = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
+    fIntrinsicMap[String("dFdx")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
                                                              SpvOpUndef, SpvOpUndef, SpvOpUndef);
-    fIntrinsicMap[SkString("dFdy")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
+    fIntrinsicMap[String("dFdy")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
                                                              SpvOpUndef, SpvOpUndef, SpvOpUndef);
-    fIntrinsicMap[SkString("dFdy")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
+    fIntrinsicMap[String("dFdy")]        = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
                                                              SpvOpUndef, SpvOpUndef, SpvOpUndef);
-    fIntrinsicMap[SkString("texture")]     = SPECIAL(Texture);
+    fIntrinsicMap[String("texture")]     = SPECIAL(Texture);
 
-    fIntrinsicMap[SkString("subpassLoad")] = SPECIAL(SubpassLoad);
+    fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
 
-    fIntrinsicMap[SkString("any")]              = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
+    fIntrinsicMap[String("any")]              = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
                                                                   SpvOpUndef, SpvOpUndef, SpvOpAny);
-    fIntrinsicMap[SkString("all")]              = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
+    fIntrinsicMap[String("all")]              = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
                                                                   SpvOpUndef, SpvOpUndef, SpvOpAll);
-    fIntrinsicMap[SkString("equal")]            = std::make_tuple(kSPIRV_IntrinsicKind,
+    fIntrinsicMap[String("equal")]            = std::make_tuple(kSPIRV_IntrinsicKind,
                                                                   SpvOpFOrdEqual, SpvOpIEqual,
                                                                   SpvOpIEqual, SpvOpLogicalEqual);
-    fIntrinsicMap[SkString("notEqual")]         = std::make_tuple(kSPIRV_IntrinsicKind,
+    fIntrinsicMap[String("notEqual")]         = std::make_tuple(kSPIRV_IntrinsicKind,
                                                                   SpvOpFOrdNotEqual, SpvOpINotEqual,
                                                                   SpvOpINotEqual,
                                                                   SpvOpLogicalNotEqual);
-    fIntrinsicMap[SkString("lessThan")]         = std::make_tuple(kSPIRV_IntrinsicKind,
+    fIntrinsicMap[String("lessThan")]         = std::make_tuple(kSPIRV_IntrinsicKind,
                                                                   SpvOpSLessThan, SpvOpULessThan,
                                                                   SpvOpFOrdLessThan, SpvOpUndef);
-    fIntrinsicMap[SkString("lessThanEqual")]    = std::make_tuple(kSPIRV_IntrinsicKind,
+    fIntrinsicMap[String("lessThanEqual")]    = std::make_tuple(kSPIRV_IntrinsicKind,
                                                                   SpvOpSLessThanEqual,
                                                                   SpvOpULessThanEqual,
                                                                   SpvOpFOrdLessThanEqual,
                                                                   SpvOpUndef);
-    fIntrinsicMap[SkString("greaterThan")]      = std::make_tuple(kSPIRV_IntrinsicKind,
+    fIntrinsicMap[String("greaterThan")]      = std::make_tuple(kSPIRV_IntrinsicKind,
                                                                   SpvOpSGreaterThan,
                                                                   SpvOpUGreaterThan,
                                                                   SpvOpFOrdGreaterThan,
                                                                   SpvOpUndef);
-    fIntrinsicMap[SkString("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
+    fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
                                                                   SpvOpSGreaterThanEqual,
                                                                   SpvOpUGreaterThanEqual,
                                                                   SpvOpFOrdGreaterThanEqual,
                                                                   SpvOpUndef);
-
 // interpolateAt* not yet supported...
 }
 
-void SPIRVCodeGenerator::writeWord(int32_t word, SkWStream& out) {
+void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
 #if SPIRV_DEBUG
     out << "(" << word << ") ";
 #else
@@ -180,603 +177,603 @@
 }
 
 #if SPIRV_DEBUG
-static SkString opcode_text(SpvOp_ opCode) {
+static String opcode_text(SpvOp_ opCode) {
     switch (opCode) {
         case SpvOpNop:
-            return SkString("Nop");
+            return String("Nop");
         case SpvOpUndef:
-            return SkString("Undef");
+            return String("Undef");
         case SpvOpSourceContinued:
-            return SkString("SourceContinued");
+            return String("SourceContinued");
         case SpvOpSource:
-            return SkString("Source");
+            return String("Source");
         case SpvOpSourceExtension:
-            return SkString("SourceExtension");
+            return String("SourceExtension");
         case SpvOpName:
-            return SkString("Name");
+            return String("Name");
         case SpvOpMemberName:
-            return SkString("MemberName");
+            return String("MemberName");
         case SpvOpString:
-            return SkString("String");
+            return String("String");
         case SpvOpLine:
-            return SkString("Line");
+            return String("Line");
         case SpvOpExtension:
-            return SkString("Extension");
+            return String("Extension");
         case SpvOpExtInstImport:
-            return SkString("ExtInstImport");
+            return String("ExtInstImport");
         case SpvOpExtInst:
-            return SkString("ExtInst");
+            return String("ExtInst");
         case SpvOpMemoryModel:
-            return SkString("MemoryModel");
+            return String("MemoryModel");
         case SpvOpEntryPoint:
-            return SkString("EntryPoint");
+            return String("EntryPoint");
         case SpvOpExecutionMode:
-            return SkString("ExecutionMode");
+            return String("ExecutionMode");
         case SpvOpCapability:
-            return SkString("Capability");
+            return String("Capability");
         case SpvOpTypeVoid:
-            return SkString("TypeVoid");
+            return String("TypeVoid");
         case SpvOpTypeBool:
-            return SkString("TypeBool");
+            return String("TypeBool");
         case SpvOpTypeInt:
-            return SkString("TypeInt");
+            return String("TypeInt");
         case SpvOpTypeFloat:
-            return SkString("TypeFloat");
+            return String("TypeFloat");
         case SpvOpTypeVector:
-            return SkString("TypeVector");
+            return String("TypeVector");
         case SpvOpTypeMatrix:
-            return SkString("TypeMatrix");
+            return String("TypeMatrix");
         case SpvOpTypeImage:
-            return SkString("TypeImage");
+            return String("TypeImage");
         case SpvOpTypeSampler:
-            return SkString("TypeSampler");
+            return String("TypeSampler");
         case SpvOpTypeSampledImage:
-            return SkString("TypeSampledImage");
+            return String("TypeSampledImage");
         case SpvOpTypeArray:
-            return SkString("TypeArray");
+            return String("TypeArray");
         case SpvOpTypeRuntimeArray:
-            return SkString("TypeRuntimeArray");
+            return String("TypeRuntimeArray");
         case SpvOpTypeStruct:
-            return SkString("TypeStruct");
+            return String("TypeStruct");
         case SpvOpTypeOpaque:
-            return SkString("TypeOpaque");
+            return String("TypeOpaque");
         case SpvOpTypePointer:
-            return SkString("TypePointer");
+            return String("TypePointer");
         case SpvOpTypeFunction:
-            return SkString("TypeFunction");
+            return String("TypeFunction");
         case SpvOpTypeEvent:
-            return SkString("TypeEvent");
+            return String("TypeEvent");
         case SpvOpTypeDeviceEvent:
-            return SkString("TypeDeviceEvent");
+            return String("TypeDeviceEvent");
         case SpvOpTypeReserveId:
-            return SkString("TypeReserveId");
+            return String("TypeReserveId");
         case SpvOpTypeQueue:
-            return SkString("TypeQueue");
+            return String("TypeQueue");
         case SpvOpTypePipe:
-            return SkString("TypePipe");
+            return String("TypePipe");
         case SpvOpTypeForwardPointer:
-            return SkString("TypeForwardPointer");
+            return String("TypeForwardPointer");
         case SpvOpConstantTrue:
-            return SkString("ConstantTrue");
+            return String("ConstantTrue");
         case SpvOpConstantFalse:
-            return SkString("ConstantFalse");
+            return String("ConstantFalse");
         case SpvOpConstant:
-            return SkString("Constant");
+            return String("Constant");
         case SpvOpConstantComposite:
-            return SkString("ConstantComposite");
+            return String("ConstantComposite");
         case SpvOpConstantSampler:
-            return SkString("ConstantSampler");
+            return String("ConstantSampler");
         case SpvOpConstantNull:
-            return SkString("ConstantNull");
+            return String("ConstantNull");
         case SpvOpSpecConstantTrue:
-            return SkString("SpecConstantTrue");
+            return String("SpecConstantTrue");
         case SpvOpSpecConstantFalse:
-            return SkString("SpecConstantFalse");
+            return String("SpecConstantFalse");
         case SpvOpSpecConstant:
-            return SkString("SpecConstant");
+            return String("SpecConstant");
         case SpvOpSpecConstantComposite:
-            return SkString("SpecConstantComposite");
+            return String("SpecConstantComposite");
         case SpvOpSpecConstantOp:
-            return SkString("SpecConstantOp");
+            return String("SpecConstantOp");
         case SpvOpFunction:
-            return SkString("Function");
+            return String("Function");
         case SpvOpFunctionParameter:
-            return SkString("FunctionParameter");
+            return String("FunctionParameter");
         case SpvOpFunctionEnd:
-            return SkString("FunctionEnd");
+            return String("FunctionEnd");
         case SpvOpFunctionCall:
-            return SkString("FunctionCall");
+            return String("FunctionCall");
         case SpvOpVariable:
-            return SkString("Variable");
+            return String("Variable");
         case SpvOpImageTexelPointer:
-            return SkString("ImageTexelPointer");
+            return String("ImageTexelPointer");
         case SpvOpLoad:
-            return SkString("Load");
+            return String("Load");
         case SpvOpStore:
-            return SkString("Store");
+            return String("Store");
         case SpvOpCopyMemory:
-            return SkString("CopyMemory");
+            return String("CopyMemory");
         case SpvOpCopyMemorySized:
-            return SkString("CopyMemorySized");
+            return String("CopyMemorySized");
         case SpvOpAccessChain:
-            return SkString("AccessChain");
+            return String("AccessChain");
         case SpvOpInBoundsAccessChain:
-            return SkString("InBoundsAccessChain");
+            return String("InBoundsAccessChain");
         case SpvOpPtrAccessChain:
-            return SkString("PtrAccessChain");
+            return String("PtrAccessChain");
         case SpvOpArrayLength:
-            return SkString("ArrayLength");
+            return String("ArrayLength");
         case SpvOpGenericPtrMemSemantics:
-            return SkString("GenericPtrMemSemantics");
+            return String("GenericPtrMemSemantics");
         case SpvOpInBoundsPtrAccessChain:
-            return SkString("InBoundsPtrAccessChain");
+            return String("InBoundsPtrAccessChain");
         case SpvOpDecorate:
-            return SkString("Decorate");
+            return String("Decorate");
         case SpvOpMemberDecorate:
-            return SkString("MemberDecorate");
+            return String("MemberDecorate");
         case SpvOpDecorationGroup:
-            return SkString("DecorationGroup");
+            return String("DecorationGroup");
         case SpvOpGroupDecorate:
-            return SkString("GroupDecorate");
+            return String("GroupDecorate");
         case SpvOpGroupMemberDecorate:
-            return SkString("GroupMemberDecorate");
+            return String("GroupMemberDecorate");
         case SpvOpVectorExtractDynamic:
-            return SkString("VectorExtractDynamic");
+            return String("VectorExtractDynamic");
         case SpvOpVectorInsertDynamic:
-            return SkString("VectorInsertDynamic");
+            return String("VectorInsertDynamic");
         case SpvOpVectorShuffle:
-            return SkString("VectorShuffle");
+            return String("VectorShuffle");
         case SpvOpCompositeConstruct:
-            return SkString("CompositeConstruct");
+            return String("CompositeConstruct");
         case SpvOpCompositeExtract:
-            return SkString("CompositeExtract");
+            return String("CompositeExtract");
         case SpvOpCompositeInsert:
-            return SkString("CompositeInsert");
+            return String("CompositeInsert");
         case SpvOpCopyObject:
-            return SkString("CopyObject");
+            return String("CopyObject");
         case SpvOpTranspose:
-            return SkString("Transpose");
+            return String("Transpose");
         case SpvOpSampledImage:
-            return SkString("SampledImage");
+            return String("SampledImage");
         case SpvOpImageSampleImplicitLod:
-            return SkString("ImageSampleImplicitLod");
+            return String("ImageSampleImplicitLod");
         case SpvOpImageSampleExplicitLod:
-            return SkString("ImageSampleExplicitLod");
+            return String("ImageSampleExplicitLod");
         case SpvOpImageSampleDrefImplicitLod:
-            return SkString("ImageSampleDrefImplicitLod");
+            return String("ImageSampleDrefImplicitLod");
         case SpvOpImageSampleDrefExplicitLod:
-            return SkString("ImageSampleDrefExplicitLod");
+            return String("ImageSampleDrefExplicitLod");
         case SpvOpImageSampleProjImplicitLod:
-            return SkString("ImageSampleProjImplicitLod");
+            return String("ImageSampleProjImplicitLod");
         case SpvOpImageSampleProjExplicitLod:
-            return SkString("ImageSampleProjExplicitLod");
+            return String("ImageSampleProjExplicitLod");
         case SpvOpImageSampleProjDrefImplicitLod:
-            return SkString("ImageSampleProjDrefImplicitLod");
+            return String("ImageSampleProjDrefImplicitLod");
         case SpvOpImageSampleProjDrefExplicitLod:
-            return SkString("ImageSampleProjDrefExplicitLod");
+            return String("ImageSampleProjDrefExplicitLod");
         case SpvOpImageFetch:
-            return SkString("ImageFetch");
+            return String("ImageFetch");
         case SpvOpImageGather:
-            return SkString("ImageGather");
+            return String("ImageGather");
         case SpvOpImageDrefGather:
-            return SkString("ImageDrefGather");
+            return String("ImageDrefGather");
         case SpvOpImageRead:
-            return SkString("ImageRead");
+            return String("ImageRead");
         case SpvOpImageWrite:
-            return SkString("ImageWrite");
+            return String("ImageWrite");
         case SpvOpImage:
-            return SkString("Image");
+            return String("Image");
         case SpvOpImageQueryFormat:
-            return SkString("ImageQueryFormat");
+            return String("ImageQueryFormat");
         case SpvOpImageQueryOrder:
-            return SkString("ImageQueryOrder");
+            return String("ImageQueryOrder");
         case SpvOpImageQuerySizeLod:
-            return SkString("ImageQuerySizeLod");
+            return String("ImageQuerySizeLod");
         case SpvOpImageQuerySize:
-            return SkString("ImageQuerySize");
+            return String("ImageQuerySize");
         case SpvOpImageQueryLod:
-            return SkString("ImageQueryLod");
+            return String("ImageQueryLod");
         case SpvOpImageQueryLevels:
-            return SkString("ImageQueryLevels");
+            return String("ImageQueryLevels");
         case SpvOpImageQuerySamples:
-            return SkString("ImageQuerySamples");
+            return String("ImageQuerySamples");
         case SpvOpConvertFToU:
-            return SkString("ConvertFToU");
+            return String("ConvertFToU");
         case SpvOpConvertFToS:
-            return SkString("ConvertFToS");
+            return String("ConvertFToS");
         case SpvOpConvertSToF:
-            return SkString("ConvertSToF");
+            return String("ConvertSToF");
         case SpvOpConvertUToF:
-            return SkString("ConvertUToF");
+            return String("ConvertUToF");
         case SpvOpUConvert:
-            return SkString("UConvert");
+            return String("UConvert");
         case SpvOpSConvert:
-            return SkString("SConvert");
+            return String("SConvert");
         case SpvOpFConvert:
-            return SkString("FConvert");
+            return String("FConvert");
         case SpvOpQuantizeToF16:
-            return SkString("QuantizeToF16");
+            return String("QuantizeToF16");
         case SpvOpConvertPtrToU:
-            return SkString("ConvertPtrToU");
+            return String("ConvertPtrToU");
         case SpvOpSatConvertSToU:
-            return SkString("SatConvertSToU");
+            return String("SatConvertSToU");
         case SpvOpSatConvertUToS:
-            return SkString("SatConvertUToS");
+            return String("SatConvertUToS");
         case SpvOpConvertUToPtr:
-            return SkString("ConvertUToPtr");
+            return String("ConvertUToPtr");
         case SpvOpPtrCastToGeneric:
-            return SkString("PtrCastToGeneric");
+            return String("PtrCastToGeneric");
         case SpvOpGenericCastToPtr:
-            return SkString("GenericCastToPtr");
+            return String("GenericCastToPtr");
         case SpvOpGenericCastToPtrExplicit:
-            return SkString("GenericCastToPtrExplicit");
+            return String("GenericCastToPtrExplicit");
         case SpvOpBitcast:
-            return SkString("Bitcast");
+            return String("Bitcast");
         case SpvOpSNegate:
-            return SkString("SNegate");
+            return String("SNegate");
         case SpvOpFNegate:
-            return SkString("FNegate");
+            return String("FNegate");
         case SpvOpIAdd:
-            return SkString("IAdd");
+            return String("IAdd");
         case SpvOpFAdd:
-            return SkString("FAdd");
+            return String("FAdd");
         case SpvOpISub:
-            return SkString("ISub");
+            return String("ISub");
         case SpvOpFSub:
-            return SkString("FSub");
+            return String("FSub");
         case SpvOpIMul:
-            return SkString("IMul");
+            return String("IMul");
         case SpvOpFMul:
-            return SkString("FMul");
+            return String("FMul");
         case SpvOpUDiv:
-            return SkString("UDiv");
+            return String("UDiv");
         case SpvOpSDiv:
-            return SkString("SDiv");
+            return String("SDiv");
         case SpvOpFDiv:
-            return SkString("FDiv");
+            return String("FDiv");
         case SpvOpUMod:
-            return SkString("UMod");
+            return String("UMod");
         case SpvOpSRem:
-            return SkString("SRem");
+            return String("SRem");
         case SpvOpSMod:
-            return SkString("SMod");
+            return String("SMod");
         case SpvOpFRem:
-            return SkString("FRem");
+            return String("FRem");
         case SpvOpFMod:
-            return SkString("FMod");
+            return String("FMod");
         case SpvOpVectorTimesScalar:
-            return SkString("VectorTimesScalar");
+            return String("VectorTimesScalar");
         case SpvOpMatrixTimesScalar:
-            return SkString("MatrixTimesScalar");
+            return String("MatrixTimesScalar");
         case SpvOpVectorTimesMatrix:
-            return SkString("VectorTimesMatrix");
+            return String("VectorTimesMatrix");
         case SpvOpMatrixTimesVector:
-            return SkString("MatrixTimesVector");
+            return String("MatrixTimesVector");
         case SpvOpMatrixTimesMatrix:
-            return SkString("MatrixTimesMatrix");
+            return String("MatrixTimesMatrix");
         case SpvOpOuterProduct:
-            return SkString("OuterProduct");
+            return String("OuterProduct");
         case SpvOpDot:
-            return SkString("Dot");
+            return String("Dot");
         case SpvOpIAddCarry:
-            return SkString("IAddCarry");
+            return String("IAddCarry");
         case SpvOpISubBorrow:
-            return SkString("ISubBorrow");
+            return String("ISubBorrow");
         case SpvOpUMulExtended:
-            return SkString("UMulExtended");
+            return String("UMulExtended");
         case SpvOpSMulExtended:
-            return SkString("SMulExtended");
+            return String("SMulExtended");
         case SpvOpAny:
-            return SkString("Any");
+            return String("Any");
         case SpvOpAll:
-            return SkString("All");
+            return String("All");
         case SpvOpIsNan:
-            return SkString("IsNan");
+            return String("IsNan");
         case SpvOpIsInf:
-            return SkString("IsInf");
+            return String("IsInf");
         case SpvOpIsFinite:
-            return SkString("IsFinite");
+            return String("IsFinite");
         case SpvOpIsNormal:
-            return SkString("IsNormal");
+            return String("IsNormal");
         case SpvOpSignBitSet:
-            return SkString("SignBitSet");
+            return String("SignBitSet");
         case SpvOpLessOrGreater:
-            return SkString("LessOrGreater");
+            return String("LessOrGreater");
         case SpvOpOrdered:
-            return SkString("Ordered");
+            return String("Ordered");
         case SpvOpUnordered:
-            return SkString("Unordered");
+            return String("Unordered");
         case SpvOpLogicalEqual:
-            return SkString("LogicalEqual");
+            return String("LogicalEqual");
         case SpvOpLogicalNotEqual:
-            return SkString("LogicalNotEqual");
+            return String("LogicalNotEqual");
         case SpvOpLogicalOr:
-            return SkString("LogicalOr");
+            return String("LogicalOr");
         case SpvOpLogicalAnd:
-            return SkString("LogicalAnd");
+            return String("LogicalAnd");
         case SpvOpLogicalNot:
-            return SkString("LogicalNot");
+            return String("LogicalNot");
         case SpvOpSelect:
-            return SkString("Select");
+            return String("Select");
         case SpvOpIEqual:
-            return SkString("IEqual");
+            return String("IEqual");
         case SpvOpINotEqual:
-            return SkString("INotEqual");
+            return String("INotEqual");
         case SpvOpUGreaterThan:
-            return SkString("UGreaterThan");
+            return String("UGreaterThan");
         case SpvOpSGreaterThan:
-            return SkString("SGreaterThan");
+            return String("SGreaterThan");
         case SpvOpUGreaterThanEqual:
-            return SkString("UGreaterThanEqual");
+            return String("UGreaterThanEqual");
         case SpvOpSGreaterThanEqual:
-            return SkString("SGreaterThanEqual");
+            return String("SGreaterThanEqual");
         case SpvOpULessThan:
-            return SkString("ULessThan");
+            return String("ULessThan");
         case SpvOpSLessThan:
-            return SkString("SLessThan");
+            return String("SLessThan");
         case SpvOpULessThanEqual:
-            return SkString("ULessThanEqual");
+            return String("ULessThanEqual");
         case SpvOpSLessThanEqual:
-            return SkString("SLessThanEqual");
+            return String("SLessThanEqual");
         case SpvOpFOrdEqual:
-            return SkString("FOrdEqual");
+            return String("FOrdEqual");
         case SpvOpFUnordEqual:
-            return SkString("FUnordEqual");
+            return String("FUnordEqual");
         case SpvOpFOrdNotEqual:
-            return SkString("FOrdNotEqual");
+            return String("FOrdNotEqual");
         case SpvOpFUnordNotEqual:
-            return SkString("FUnordNotEqual");
+            return String("FUnordNotEqual");
         case SpvOpFOrdLessThan:
-            return SkString("FOrdLessThan");
+            return String("FOrdLessThan");
         case SpvOpFUnordLessThan:
-            return SkString("FUnordLessThan");
+            return String("FUnordLessThan");
         case SpvOpFOrdGreaterThan:
-            return SkString("FOrdGreaterThan");
+            return String("FOrdGreaterThan");
         case SpvOpFUnordGreaterThan:
-            return SkString("FUnordGreaterThan");
+            return String("FUnordGreaterThan");
         case SpvOpFOrdLessThanEqual:
-            return SkString("FOrdLessThanEqual");
+            return String("FOrdLessThanEqual");
         case SpvOpFUnordLessThanEqual:
-            return SkString("FUnordLessThanEqual");
+            return String("FUnordLessThanEqual");
         case SpvOpFOrdGreaterThanEqual:
-            return SkString("FOrdGreaterThanEqual");
+            return String("FOrdGreaterThanEqual");
         case SpvOpFUnordGreaterThanEqual:
-            return SkString("FUnordGreaterThanEqual");
+            return String("FUnordGreaterThanEqual");
         case SpvOpShiftRightLogical:
-            return SkString("ShiftRightLogical");
+            return String("ShiftRightLogical");
         case SpvOpShiftRightArithmetic:
-            return SkString("ShiftRightArithmetic");
+            return String("ShiftRightArithmetic");
         case SpvOpShiftLeftLogical:
-            return SkString("ShiftLeftLogical");
+            return String("ShiftLeftLogical");
         case SpvOpBitwiseOr:
-            return SkString("BitwiseOr");
+            return String("BitwiseOr");
         case SpvOpBitwiseXor:
-            return SkString("BitwiseXor");
+            return String("BitwiseXor");
         case SpvOpBitwiseAnd:
-            return SkString("BitwiseAnd");
+            return String("BitwiseAnd");
         case SpvOpNot:
-            return SkString("Not");
+            return String("Not");
         case SpvOpBitFieldInsert:
-            return SkString("BitFieldInsert");
+            return String("BitFieldInsert");
         case SpvOpBitFieldSExtract:
-            return SkString("BitFieldSExtract");
+            return String("BitFieldSExtract");
         case SpvOpBitFieldUExtract:
-            return SkString("BitFieldUExtract");
+            return String("BitFieldUExtract");
         case SpvOpBitReverse:
-            return SkString("BitReverse");
+            return String("BitReverse");
         case SpvOpBitCount:
-            return SkString("BitCount");
+            return String("BitCount");
         case SpvOpDPdx:
-            return SkString("DPdx");
+            return String("DPdx");
         case SpvOpDPdy:
-            return SkString("DPdy");
+            return String("DPdy");
         case SpvOpFwidth:
-            return SkString("Fwidth");
+            return String("Fwidth");
         case SpvOpDPdxFine:
-            return SkString("DPdxFine");
+            return String("DPdxFine");
         case SpvOpDPdyFine:
-            return SkString("DPdyFine");
+            return String("DPdyFine");
         case SpvOpFwidthFine:
-            return SkString("FwidthFine");
+            return String("FwidthFine");
         case SpvOpDPdxCoarse:
-            return SkString("DPdxCoarse");
+            return String("DPdxCoarse");
         case SpvOpDPdyCoarse:
-            return SkString("DPdyCoarse");
+            return String("DPdyCoarse");
         case SpvOpFwidthCoarse:
-            return SkString("FwidthCoarse");
+            return String("FwidthCoarse");
         case SpvOpEmitVertex:
-            return SkString("EmitVertex");
+            return String("EmitVertex");
         case SpvOpEndPrimitive:
-            return SkString("EndPrimitive");
+            return String("EndPrimitive");
         case SpvOpEmitStreamVertex:
-            return SkString("EmitStreamVertex");
+            return String("EmitStreamVertex");
         case SpvOpEndStreamPrimitive:
-            return SkString("EndStreamPrimitive");
+            return String("EndStreamPrimitive");
         case SpvOpControlBarrier:
-            return SkString("ControlBarrier");
+            return String("ControlBarrier");
         case SpvOpMemoryBarrier:
-            return SkString("MemoryBarrier");
+            return String("MemoryBarrier");
         case SpvOpAtomicLoad:
-            return SkString("AtomicLoad");
+            return String("AtomicLoad");
         case SpvOpAtomicStore:
-            return SkString("AtomicStore");
+            return String("AtomicStore");
         case SpvOpAtomicExchange:
-            return SkString("AtomicExchange");
+            return String("AtomicExchange");
         case SpvOpAtomicCompareExchange:
-            return SkString("AtomicCompareExchange");
+            return String("AtomicCompareExchange");
         case SpvOpAtomicCompareExchangeWeak:
-            return SkString("AtomicCompareExchangeWeak");
+            return String("AtomicCompareExchangeWeak");
         case SpvOpAtomicIIncrement:
-            return SkString("AtomicIIncrement");
+            return String("AtomicIIncrement");
         case SpvOpAtomicIDecrement:
-            return SkString("AtomicIDecrement");
+            return String("AtomicIDecrement");
         case SpvOpAtomicIAdd:
-            return SkString("AtomicIAdd");
+            return String("AtomicIAdd");
         case SpvOpAtomicISub:
-            return SkString("AtomicISub");
+            return String("AtomicISub");
         case SpvOpAtomicSMin:
-            return SkString("AtomicSMin");
+            return String("AtomicSMin");
         case SpvOpAtomicUMin:
-            return SkString("AtomicUMin");
+            return String("AtomicUMin");
         case SpvOpAtomicSMax:
-            return SkString("AtomicSMax");
+            return String("AtomicSMax");
         case SpvOpAtomicUMax:
-            return SkString("AtomicUMax");
+            return String("AtomicUMax");
         case SpvOpAtomicAnd:
-            return SkString("AtomicAnd");
+            return String("AtomicAnd");
         case SpvOpAtomicOr:
-            return SkString("AtomicOr");
+            return String("AtomicOr");
         case SpvOpAtomicXor:
-            return SkString("AtomicXor");
+            return String("AtomicXor");
         case SpvOpPhi:
-            return SkString("Phi");
+            return String("Phi");
         case SpvOpLoopMerge:
-            return SkString("LoopMerge");
+            return String("LoopMerge");
         case SpvOpSelectionMerge:
-            return SkString("SelectionMerge");
+            return String("SelectionMerge");
         case SpvOpLabel:
-            return SkString("Label");
+            return String("Label");
         case SpvOpBranch:
-            return SkString("Branch");
+            return String("Branch");
         case SpvOpBranchConditional:
-            return SkString("BranchConditional");
+            return String("BranchConditional");
         case SpvOpSwitch:
-            return SkString("Switch");
+            return String("Switch");
         case SpvOpKill:
-            return SkString("Kill");
+            return String("Kill");
         case SpvOpReturn:
-            return SkString("Return");
+            return String("Return");
         case SpvOpReturnValue:
-            return SkString("ReturnValue");
+            return String("ReturnValue");
         case SpvOpUnreachable:
-            return SkString("Unreachable");
+            return String("Unreachable");
         case SpvOpLifetimeStart:
-            return SkString("LifetimeStart");
+            return String("LifetimeStart");
         case SpvOpLifetimeStop:
-            return SkString("LifetimeStop");
+            return String("LifetimeStop");
         case SpvOpGroupAsyncCopy:
-            return SkString("GroupAsyncCopy");
+            return String("GroupAsyncCopy");
         case SpvOpGroupWaitEvents:
-            return SkString("GroupWaitEvents");
+            return String("GroupWaitEvents");
         case SpvOpGroupAll:
-            return SkString("GroupAll");
+            return String("GroupAll");
         case SpvOpGroupAny:
-            return SkString("GroupAny");
+            return String("GroupAny");
         case SpvOpGroupBroadcast:
-            return SkString("GroupBroadcast");
+            return String("GroupBroadcast");
         case SpvOpGroupIAdd:
-            return SkString("GroupIAdd");
+            return String("GroupIAdd");
         case SpvOpGroupFAdd:
-            return SkString("GroupFAdd");
+            return String("GroupFAdd");
         case SpvOpGroupFMin:
-            return SkString("GroupFMin");
+            return String("GroupFMin");
         case SpvOpGroupUMin:
-            return SkString("GroupUMin");
+            return String("GroupUMin");
         case SpvOpGroupSMin:
-            return SkString("GroupSMin");
+            return String("GroupSMin");
         case SpvOpGroupFMax:
-            return SkString("GroupFMax");
+            return String("GroupFMax");
         case SpvOpGroupUMax:
-            return SkString("GroupUMax");
+            return String("GroupUMax");
         case SpvOpGroupSMax:
-            return SkString("GroupSMax");
+            return String("GroupSMax");
         case SpvOpReadPipe:
-            return SkString("ReadPipe");
+            return String("ReadPipe");
         case SpvOpWritePipe:
-            return SkString("WritePipe");
+            return String("WritePipe");
         case SpvOpReservedReadPipe:
-            return SkString("ReservedReadPipe");
+            return String("ReservedReadPipe");
         case SpvOpReservedWritePipe:
-            return SkString("ReservedWritePipe");
+            return String("ReservedWritePipe");
         case SpvOpReserveReadPipePackets:
-            return SkString("ReserveReadPipePackets");
+            return String("ReserveReadPipePackets");
         case SpvOpReserveWritePipePackets:
-            return SkString("ReserveWritePipePackets");
+            return String("ReserveWritePipePackets");
         case SpvOpCommitReadPipe:
-            return SkString("CommitReadPipe");
+            return String("CommitReadPipe");
         case SpvOpCommitWritePipe:
-            return SkString("CommitWritePipe");
+            return String("CommitWritePipe");
         case SpvOpIsValidReserveId:
-            return SkString("IsValidReserveId");
+            return String("IsValidReserveId");
         case SpvOpGetNumPipePackets:
-            return SkString("GetNumPipePackets");
+            return String("GetNumPipePackets");
         case SpvOpGetMaxPipePackets:
-            return SkString("GetMaxPipePackets");
+            return String("GetMaxPipePackets");
         case SpvOpGroupReserveReadPipePackets:
-            return SkString("GroupReserveReadPipePackets");
+            return String("GroupReserveReadPipePackets");
         case SpvOpGroupReserveWritePipePackets:
-            return SkString("GroupReserveWritePipePackets");
+            return String("GroupReserveWritePipePackets");
         case SpvOpGroupCommitReadPipe:
-            return SkString("GroupCommitReadPipe");
+            return String("GroupCommitReadPipe");
         case SpvOpGroupCommitWritePipe:
-            return SkString("GroupCommitWritePipe");
+            return String("GroupCommitWritePipe");
         case SpvOpEnqueueMarker:
-            return SkString("EnqueueMarker");
+            return String("EnqueueMarker");
         case SpvOpEnqueueKernel:
-            return SkString("EnqueueKernel");
+            return String("EnqueueKernel");
         case SpvOpGetKernelNDrangeSubGroupCount:
-            return SkString("GetKernelNDrangeSubGroupCount");
+            return String("GetKernelNDrangeSubGroupCount");
         case SpvOpGetKernelNDrangeMaxSubGroupSize:
-            return SkString("GetKernelNDrangeMaxSubGroupSize");
+            return String("GetKernelNDrangeMaxSubGroupSize");
         case SpvOpGetKernelWorkGroupSize:
-            return SkString("GetKernelWorkGroupSize");
+            return String("GetKernelWorkGroupSize");
         case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
-            return SkString("GetKernelPreferredWorkGroupSizeMultiple");
+            return String("GetKernelPreferredWorkGroupSizeMultiple");
         case SpvOpRetainEvent:
-            return SkString("RetainEvent");
+            return String("RetainEvent");
         case SpvOpReleaseEvent:
-            return SkString("ReleaseEvent");
+            return String("ReleaseEvent");
         case SpvOpCreateUserEvent:
-            return SkString("CreateUserEvent");
+            return String("CreateUserEvent");
         case SpvOpIsValidEvent:
-            return SkString("IsValidEvent");
+            return String("IsValidEvent");
         case SpvOpSetUserEventStatus:
-            return SkString("SetUserEventStatus");
+            return String("SetUserEventStatus");
         case SpvOpCaptureEventProfilingInfo:
-            return SkString("CaptureEventProfilingInfo");
+            return String("CaptureEventProfilingInfo");
         case SpvOpGetDefaultQueue:
-            return SkString("GetDefaultQueue");
+            return String("GetDefaultQueue");
         case SpvOpBuildNDRange:
-            return SkString("BuildNDRange");
+            return String("BuildNDRange");
         case SpvOpImageSparseSampleImplicitLod:
-            return SkString("ImageSparseSampleImplicitLod");
+            return String("ImageSparseSampleImplicitLod");
         case SpvOpImageSparseSampleExplicitLod:
-            return SkString("ImageSparseSampleExplicitLod");
+            return String("ImageSparseSampleExplicitLod");
         case SpvOpImageSparseSampleDrefImplicitLod:
-            return SkString("ImageSparseSampleDrefImplicitLod");
+            return String("ImageSparseSampleDrefImplicitLod");
         case SpvOpImageSparseSampleDrefExplicitLod:
-            return SkString("ImageSparseSampleDrefExplicitLod");
+            return String("ImageSparseSampleDrefExplicitLod");
         case SpvOpImageSparseSampleProjImplicitLod:
-            return SkString("ImageSparseSampleProjImplicitLod");
+            return String("ImageSparseSampleProjImplicitLod");
         case SpvOpImageSparseSampleProjExplicitLod:
-            return SkString("ImageSparseSampleProjExplicitLod");
+            return String("ImageSparseSampleProjExplicitLod");
         case SpvOpImageSparseSampleProjDrefImplicitLod:
-            return SkString("ImageSparseSampleProjDrefImplicitLod");
+            return String("ImageSparseSampleProjDrefImplicitLod");
         case SpvOpImageSparseSampleProjDrefExplicitLod:
-            return SkString("ImageSparseSampleProjDrefExplicitLod");
+            return String("ImageSparseSampleProjDrefExplicitLod");
         case SpvOpImageSparseFetch:
-            return SkString("ImageSparseFetch");
+            return String("ImageSparseFetch");
         case SpvOpImageSparseGather:
-            return SkString("ImageSparseGather");
+            return String("ImageSparseGather");
         case SpvOpImageSparseDrefGather:
-            return SkString("ImageSparseDrefGather");
+            return String("ImageSparseDrefGather");
         case SpvOpImageSparseTexelsResident:
-            return SkString("ImageSparseTexelsResident");
+            return String("ImageSparseTexelsResident");
         case SpvOpNoLine:
-            return SkString("NoLine");
+            return String("NoLine");
         case SpvOpAtomicFlagTestAndSet:
-            return SkString("AtomicFlagTestAndSet");
+            return String("AtomicFlagTestAndSet");
         case SpvOpAtomicFlagClear:
-            return SkString("AtomicFlagClear");
+            return String("AtomicFlagClear");
         case SpvOpImageSparseRead:
-            return SkString("ImageSparseRead");
+            return String("ImageSparseRead");
         default:
-            ABORT("unsupported SPIR-V op");    
+            ABORT("unsupported SPIR-V op");
     }
 }
 #endif
 
-void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, SkWStream& out) {
+void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
     ASSERT(opCode != SpvOpUndef);
     switch (opCode) {
         case SpvOpReturn:      // fall through
@@ -830,23 +827,23 @@
 #endif
 }
 
-void SPIRVCodeGenerator::writeLabel(SpvId label, SkWStream& out) {
+void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
     fCurrentBlock = label;
     this->writeInstruction(SpvOpLabel, label, out);
 }
 
-void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, SkWStream& out) {
+void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
     this->writeOpCode(opCode, 1, out);
 }
 
-void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, SkWStream& out) {
+void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
     this->writeOpCode(opCode, 2, out);
     this->writeWord(word1, out);
 }
 
-void SPIRVCodeGenerator::writeString(const char* string, SkWStream& out) {
+void SPIRVCodeGenerator::writeString(const char* string, OutputStream& out) {
     size_t length = strlen(string);
-    out.writeText(string);
+    out.write(string, length);
     switch (length % 4) {
         case 1:
             out.write8(0);
@@ -862,7 +859,7 @@
     }
 }
 
-void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, SkWStream& out) {
+void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, OutputStream& out) {
     int32_t length = (int32_t) strlen(string);
     this->writeOpCode(opCode, 1 + (length + 4) / 4, out);
     this->writeString(string, out);
@@ -870,7 +867,7 @@
 
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string,
-                                          SkWStream& out) {
+                                          OutputStream& out) {
     int32_t length = (int32_t) strlen(string);
     this->writeOpCode(opCode, 2 + (length + 4) / 4, out);
     this->writeWord(word1, out);
@@ -878,7 +875,7 @@
 }
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
-                                          const char* string, SkWStream& out) {
+                                          const char* string, OutputStream& out) {
     int32_t length = (int32_t) strlen(string);
     this->writeOpCode(opCode, 3 + (length + 4) / 4, out);
     this->writeWord(word1, out);
@@ -887,14 +884,14 @@
 }
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
-                                          SkWStream& out) {
+                                          OutputStream& out) {
     this->writeOpCode(opCode, 3, out);
     this->writeWord(word1, out);
     this->writeWord(word2, out);
 }
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
-                                          int32_t word3, SkWStream& out) {
+                                          int32_t word3, OutputStream& out) {
     this->writeOpCode(opCode, 4, out);
     this->writeWord(word1, out);
     this->writeWord(word2, out);
@@ -902,7 +899,7 @@
 }
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
-                                          int32_t word3, int32_t word4, SkWStream& out) {
+                                          int32_t word3, int32_t word4, OutputStream& out) {
     this->writeOpCode(opCode, 5, out);
     this->writeWord(word1, out);
     this->writeWord(word2, out);
@@ -912,7 +909,7 @@
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
                                           int32_t word3, int32_t word4, int32_t word5,
-                                          SkWStream& out) {
+                                          OutputStream& out) {
     this->writeOpCode(opCode, 6, out);
     this->writeWord(word1, out);
     this->writeWord(word2, out);
@@ -923,7 +920,7 @@
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
                                           int32_t word3, int32_t word4, int32_t word5,
-                                          int32_t word6, SkWStream& out) {
+                                          int32_t word6, OutputStream& out) {
     this->writeOpCode(opCode, 7, out);
     this->writeWord(word1, out);
     this->writeWord(word2, out);
@@ -935,7 +932,7 @@
 
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
                                           int32_t word3, int32_t word4, int32_t word5,
-                                          int32_t word6, int32_t word7, SkWStream& out) {
+                                          int32_t word6, int32_t word7, OutputStream& out) {
     this->writeOpCode(opCode, 8, out);
     this->writeWord(word1, out);
     this->writeWord(word2, out);
@@ -949,7 +946,7 @@
 void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
                                           int32_t word3, int32_t word4, int32_t word5,
                                           int32_t word6, int32_t word7, int32_t word8,
-                                          SkWStream& out) {
+                                          OutputStream& out) {
     this->writeOpCode(opCode, 9, out);
     this->writeWord(word1, out);
     this->writeWord(word2, out);
@@ -961,7 +958,7 @@
     this->writeWord(word8, out);
 }
 
-void SPIRVCodeGenerator::writeCapabilities(SkWStream& out) {
+void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
     for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
         if (fCapabilities & bit) {
             this->writeInstruction(SpvOpCapability, (SpvId) i, out);
@@ -1037,7 +1034,7 @@
 }
 
 SpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) {
-    SkString key = type.name() + to_string((int) layout.fStd);
+    String key = type.name() + to_string((int) layout.fStd);
     auto entry = fTypeMap.find(key);
     if (entry == fTypeMap.end()) {
         SpvId result = this->nextId();
@@ -1077,7 +1074,7 @@
                                            this->getType(type.componentType(), layout),
                                            this->writeIntLiteral(count), fConstantBuffer);
                     this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
-                                           (int32_t) layout.stride(type), 
+                                           (int32_t) layout.stride(type),
                                            fDecorationBuffer);
                 } else {
                     ABORT("runtime-sized arrays are not yet supported");
@@ -1116,8 +1113,8 @@
 }
 
 SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
-    SkString key = function.fReturnType.description() + "(";
-    SkString separator;
+    String key = function.fReturnType.description() + "(";
+    String separator;
     for (size_t i = 0; i < function.fParameters.size(); i++) {
         key += separator;
         separator = ", ";
@@ -1178,7 +1175,7 @@
 
 SpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout,
                                          SpvStorageClass_ storageClass) {
-    SkString key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
+    String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
     auto entry = fTypeMap.find(key);
     if (entry == fTypeMap.end()) {
         SpvId result = this->nextId();
@@ -1190,7 +1187,7 @@
     return entry->second;
 }
 
-SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
     switch (expr.fKind) {
         case Expression::kBinary_Kind:
             return this->writeBinaryExpression((BinaryExpression&) expr, out);
@@ -1224,7 +1221,7 @@
     return -1;
 }
 
-SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
     auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
     ASSERT(intrinsic != fIntrinsicMap.end());
     const Type& type = c.fArguments[0]->fType;
@@ -1280,7 +1277,7 @@
 }
 
 SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
-                                                SkWStream& out) {
+                                                OutputStream& out) {
     SpvId result = this->nextId();
     switch (kind) {
         case kAtan_SpecialIntrinsic: {
@@ -1358,7 +1355,7 @@
                                        coords,
                                        out);
             } else {
-                SkASSERT(2 == c.fArguments.size());
+                ASSERT(2 == c.fArguments.size());
                 SpvId sample = this->writeExpression(*c.fArguments[1], out);
                 this->writeInstruction(SpvOpImageRead,
                                        this->getType(c.fType),
@@ -1375,7 +1372,7 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
     const auto& entry = fFunctionMap.find(&c.fFunction);
     if (entry == fFunctionMap.end()) {
         return this->writeIntrinsicCall(c, out);
@@ -1464,7 +1461,7 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
     ASSERT(c.fType == *fContext.fFloat_Type);
     ASSERT(c.fArguments.size() == 1);
     ASSERT(c.fArguments[0]->fType.isNumber());
@@ -1482,7 +1479,7 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
     ASSERT(c.fType == *fContext.fInt_Type);
     ASSERT(c.fArguments.size() == 1);
     ASSERT(c.fArguments[0]->fType.isNumber());
@@ -1501,7 +1498,7 @@
 }
 
 void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
-                                                 SkWStream& out) {
+                                                 OutputStream& out) {
     FloatLiteral zero(fContext, Position(), 0);
     SpvId zeroId = this->writeFloatLiteral(zero);
     std::vector<SpvId> columnIds;
@@ -1527,11 +1524,11 @@
 }
 
 void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
-                                         const Type& dstType, SkWStream& out) {
+                                         const Type& dstType, OutputStream& out) {
     ABORT("unimplemented");
 }
 
-SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
     ASSERT(c.fType.kind() == Type::kMatrix_Kind);
     // go ahead and write the arguments so we don't try to write new instructions in the middle of
     // an instruction
@@ -1580,7 +1577,7 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
     ASSERT(c.fType.kind() == Type::kVector_Kind);
     if (c.isConstant()) {
         return this->writeConstantVector(c);
@@ -1610,7 +1607,7 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
     if (c.fType == *fContext.fFloat_Type) {
         return this->writeFloatConstructor(c, out);
     } else if (c.fType == *fContext.fInt_Type) {
@@ -1656,7 +1653,7 @@
     }
 }
 
-std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, SkWStream& out) {
+std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
     std::vector<SpvId> chain;
     switch (expr.fKind) {
         case Expression::kIndex_Kind: {
@@ -1689,13 +1686,13 @@
         return fPointer;
     }
 
-    virtual SpvId load(SkWStream& out) override {
+    virtual SpvId load(OutputStream& out) override {
         SpvId result = fGen.nextId();
         fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
         return result;
     }
 
-    virtual void store(SpvId value, SkWStream& out) override {
+    virtual void store(SpvId value, OutputStream& out) override {
         fGen.writeInstruction(SpvOpStore, fPointer, value, out);
     }
 
@@ -1719,7 +1716,7 @@
         return 0;
     }
 
-    virtual SpvId load(SkWStream& out) override {
+    virtual SpvId load(OutputStream& out) override {
         SpvId base = fGen.nextId();
         fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
         SpvId result = fGen.nextId();
@@ -1734,7 +1731,7 @@
         return result;
     }
 
-    virtual void store(SpvId value, SkWStream& out) override {
+    virtual void store(SpvId value, OutputStream& out) override {
         // use OpVectorShuffle to mix and match the vector components. We effectively create
         // a virtual vector out of the concatenation of the left and right vectors, and then
         // select components from this virtual vector to make the result vector. For
@@ -1781,7 +1778,7 @@
 };
 
 std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
-                                                                          SkWStream& out) {
+                                                                          OutputStream& out) {
     switch (expr.fKind) {
         case Expression::kVariableReference_Kind: {
             const Variable& var = ((VariableReference&) expr).fVariable;
@@ -1854,7 +1851,7 @@
     }
 }
 
-SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
     SpvId result = this->nextId();
     auto entry = fVariableMap.find(&ref.fVariable);
     ASSERT(entry != fVariableMap.end());
@@ -1868,19 +1865,20 @@
             std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
             ASSERT(fRTHeightFieldIndex == (SpvId) -1);
             std::vector<Type::Field> fields;
-            fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME),
+            fields.emplace_back(Modifiers(), String(SKSL_RTHEIGHT_NAME),
                                 fContext.fFloat_Type.get());
-            SkString name("sksl_synthetic_uniforms");
+            String name("sksl_synthetic_uniforms");
             Type intfStruct(Position(), name, fields);
-            Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false, Layout::Format::kUnspecified,
-                          false, Layout::kUnspecified_Primitive, -1, -1);
+            Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false,
+                          Layout::Format::kUnspecified, false, Layout::kUnspecified_Primitive, -1,
+                          -1);
             Variable* intfVar = new Variable(Position(),
                                              Modifiers(layout, Modifiers::kUniform_Flag),
                                              name,
                                              intfStruct,
                                              Variable::kGlobal_Storage);
             fSynthetics.takeOwnership(intfVar);
-            InterfaceBlock intf(Position(), intfVar, name, SkString(""),
+            InterfaceBlock intf(Position(), intfVar, name, String(""),
                                 std::vector<std::unique_ptr<Expression>>(), st);
             fRTHeightStructId = this->writeInterfaceBlock(intf);
             fRTHeightFieldIndex = 0;
@@ -1924,15 +1922,15 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
     return getLValue(expr, out)->load(out);
 }
 
-SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
     return getLValue(f, out)->load(out);
 }
 
-SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
     SpvId base = this->writeExpression(*swizzle.fBase, out);
     SpvId result = this->nextId();
     size_t count = swizzle.fComponents.size();
@@ -1955,7 +1953,7 @@
 SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
                                                const Type& operandType, SpvId lhs,
                                                SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
-                                               SpvOp_ ifUInt, SpvOp_ ifBool, SkWStream& out) {
+                                               SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
     SpvId result = this->nextId();
     if (is_float(fContext, operandType)) {
         this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
@@ -1993,7 +1991,7 @@
     }
 }
 
-SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SkWStream& out) {
+SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, OutputStream& out) {
     if (operandType.kind() == Type::kVector_Kind) {
         SpvId result = this->nextId();
         this->writeInstruction(SpvOpAll, this->getType(*fContext.fBool_Type), result, id, out);
@@ -2002,7 +2000,7 @@
     return id;
 }
 
-SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
     // handle cases where we don't necessarily evaluate both LHS and RHS
     switch (b.fOperator) {
         case Token::EQ: {
@@ -2199,7 +2197,7 @@
     }
 }
 
-SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
     ASSERT(a.fOperator == Token::LOGICALAND);
     BoolLiteral falseLiteral(fContext, Position(), false);
     SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
@@ -2220,7 +2218,7 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
     ASSERT(o.fOperator == Token::LOGICALOR);
     BoolLiteral trueLiteral(fContext, Position(), true);
     SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
@@ -2241,7 +2239,7 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
     SpvId test = this->writeExpression(*t.fTest, out);
     if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
         // both true and false are constants, can just use OpSelect
@@ -2281,11 +2279,11 @@
     else if (type == *context.fFloat_Type) {
         return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
     } else {
-        ABORT("math is unsupported on type '%s'")
+        ABORT("math is unsupported on type '%s'", type.name().c_str());
     }
 }
 
-SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
     if (p.fOperator == Token::MINUS) {
         SpvId result = this->nextId();
         SpvId typeId = this->getType(p.fType);
@@ -2338,7 +2336,7 @@
     }
 }
 
-SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
     std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
     SpvId result = lv->load(out);
     SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
@@ -2435,7 +2433,7 @@
     }
 }
 
-SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
     SpvId result = fFunctionMap[&f];
     this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
                            SpvFunctionControlMaskNone, this->getFunctionType(f), out);
@@ -2450,16 +2448,17 @@
     return result;
 }
 
-SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, SkWStream& out) {
+SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
+    fVariableBuffer.reset();
     SpvId result = this->writeFunctionStart(f.fDeclaration, out);
     this->writeLabel(this->nextId(), out);
     if (f.fDeclaration.fName == "main") {
-        write_data(*fGlobalInitializersBuffer.detachAsData(), out);
+        write_stringstream(fGlobalInitializersBuffer, out);
     }
-    SkDynamicMemoryWStream bodyBuffer;
+    StringStream bodyBuffer;
     this->writeBlock(*f.fBody, bodyBuffer);
-    write_data(*fVariableBuffer.detachAsData(), out);
-    write_data(*bodyBuffer.detachAsData(), out);
+    write_stringstream(fVariableBuffer, out);
+    write_stringstream(bodyBuffer, out);
     if (fCurrentBlock) {
         this->writeInstruction(SpvOpReturn, out);
     }
@@ -2533,7 +2532,7 @@
         std::vector<Type::Field> fields = type->fields();
         fRTHeightStructId = result;
         fRTHeightFieldIndex = fields.size();
-        fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
+        fields.emplace_back(Modifiers(), String(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
         type = new Type(type->fPosition, type->name(), fields);
     }
     SpvId typeId = this->getType(*type, layout);
@@ -2552,7 +2551,7 @@
 
 #define BUILTIN_IGNORE 9999
 void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
-                                         SkWStream& out) {
+                                         OutputStream& out) {
     for (size_t i = 0; i < decl.fVars.size(); i++) {
         const VarDeclaration& varDecl = decl.fVars[i];
         const Variable* var = varDecl.fVar;
@@ -2614,7 +2613,7 @@
     }
 }
 
-void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, SkWStream& out) {
+void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
     for (const auto& varDecl : decl.fVars) {
         const Variable* var = varDecl.fVar;
         // These haven't been implemented in our SPIR-V generator yet and we only currently use them
@@ -2636,7 +2635,7 @@
     }
 }
 
-void SPIRVCodeGenerator::writeStatement(const Statement& s, SkWStream& out) {
+void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
     switch (s.fKind) {
         case Statement::kBlock_Kind:
             this->writeBlock((Block&) s, out);
@@ -2676,13 +2675,13 @@
     }
 }
 
-void SPIRVCodeGenerator::writeBlock(const Block& b, SkWStream& out) {
+void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
     for (size_t i = 0; i < b.fStatements.size(); i++) {
         this->writeStatement(*b.fStatements[i], out);
     }
 }
 
-void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, SkWStream& out) {
+void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
     SpvId test = this->writeExpression(*stmt.fTest, out);
     SpvId ifTrue = this->nextId();
     SpvId ifFalse = this->nextId();
@@ -2713,7 +2712,7 @@
     }
 }
 
-void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, SkWStream& out) {
+void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
     if (f.fInitializer) {
         this->writeStatement(*f.fInitializer, out);
     }
@@ -2748,7 +2747,7 @@
     fContinueTarget.pop();
 }
 
-void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, SkWStream& out) {
+void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
     // We believe the while loop code below will work, but Skia doesn't actually use them and
     // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
     // the time being, we just fail with an error due to the lack of testing. If you encounter this
@@ -2780,7 +2779,7 @@
     fContinueTarget.pop();
 }
 
-void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, SkWStream& out) {
+void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
     // We believe the do loop code below will work, but Skia doesn't actually use them and
     // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
     // the time being, we just fail with an error due to the lack of testing. If you encounter this
@@ -2812,7 +2811,7 @@
     fContinueTarget.pop();
 }
 
-void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, SkWStream& out) {
+void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
     if (r.fExpression) {
         this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
                                out);
@@ -2821,9 +2820,9 @@
     }
 }
 
-void SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& out) {
+void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
     fGLSLExtendedInstructions = this->nextId();
-    SkDynamicMemoryWStream body;
+    StringStream body;
     std::set<SpvId> interfaceVars;
     // assign IDs to functions
     for (size_t i = 0; i < program.fElements.size(); i++) {
@@ -2903,12 +2902,12 @@
         }
     }
 
-    write_data(*fExtraGlobalsBuffer.detachAsData(), out);
-    write_data(*fNameBuffer.detachAsData(), out);
-    write_data(*fDecorationBuffer.detachAsData(), out);
-    write_data(*fConstantBuffer.detachAsData(), out);
-    write_data(*fExternalFunctionsBuffer.detachAsData(), out);
-    write_data(*body.detachAsData(), out);
+    write_stringstream(fExtraGlobalsBuffer, out);
+    write_stringstream(fNameBuffer, out);
+    write_stringstream(fDecorationBuffer, out);
+    write_stringstream(fConstantBuffer, out);
+    write_stringstream(fExternalFunctionsBuffer, out);
+    write_stringstream(body, out);
 }
 
 bool SPIRVCodeGenerator::generateCode() {
@@ -2916,11 +2915,11 @@
     this->writeWord(SpvMagicNumber, *fOut);
     this->writeWord(SpvVersion, *fOut);
     this->writeWord(SKSL_MAGIC, *fOut);
-    SkDynamicMemoryWStream buffer;
+    StringStream buffer;
     this->writeInstructions(fProgram, buffer);
     this->writeWord(fIdCount, *fOut);
     this->writeWord(0, *fOut); // reserved, always zero
-    write_data(*buffer.detachAsData(), *fOut);
+    write_stringstream(buffer, *fOut);
     return 0 == fErrors.errorCount();
 }
 
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.h b/src/sksl/SkSLSPIRVCodeGenerator.h
index ea160b1..84a4c1f 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.h
+++ b/src/sksl/SkSLSPIRVCodeGenerator.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_SPIRVCODEGENERATOR
 #define SKSL_SPIRVCODEGENERATOR
 
@@ -12,7 +12,6 @@
 #include <tuple>
 #include <unordered_map>
 
-#include "SkStream.h"
 #include "SkSLCodeGenerator.h"
 #include "SkSLMemoryLayout.h"
 #include "ir/SkSLBinaryExpression.h"
@@ -59,13 +58,13 @@
         // by a pointer (e.g. vector swizzles), returns 0.
         virtual SpvId getPointer() = 0;
 
-        virtual SpvId load(SkWStream& out) = 0;
+        virtual SpvId load(OutputStream& out) = 0;
 
-        virtual void store(SpvId value, SkWStream& out) = 0;
+        virtual void store(SpvId value, OutputStream& out) = 0;
     };
 
     SPIRVCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
-                       SkWStream* out)
+                       OutputStream* out)
     : INHERITED(program, errors, out)
     , fContext(*context)
     , fDefaultLayout(MemoryLayout::k140_Standard)
@@ -109,7 +108,7 @@
     SpvId getPointerType(const Type& type, const MemoryLayout& layout,
                          SpvStorageClass_ storageClass);
 
-    std::vector<SpvId> getAccessChain(const Expression& expr, SkWStream& out);
+    std::vector<SpvId> getAccessChain(const Expression& expr, OutputStream& out);
 
     void writeLayout(const Layout& layout, SpvId target);
 
@@ -117,43 +116,43 @@
 
     void writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId);
 
-    void writeProgramElement(const ProgramElement& pe, SkWStream& out);
+    void writeProgramElement(const ProgramElement& pe, OutputStream& out);
 
     SpvId writeInterfaceBlock(const InterfaceBlock& intf);
 
-    SpvId writeFunctionStart(const FunctionDeclaration& f, SkWStream& out);
-    
-    SpvId writeFunctionDeclaration(const FunctionDeclaration& f, SkWStream& out);
+    SpvId writeFunctionStart(const FunctionDeclaration& f, OutputStream& out);
 
-    SpvId writeFunction(const FunctionDefinition& f, SkWStream& out);
+    SpvId writeFunctionDeclaration(const FunctionDeclaration& f, OutputStream& out);
 
-    void writeGlobalVars(Program::Kind kind, const VarDeclarations& v, SkWStream& out);
+    SpvId writeFunction(const FunctionDefinition& f, OutputStream& out);
 
-    void writeVarDeclarations(const VarDeclarations& decl, SkWStream& out);
+    void writeGlobalVars(Program::Kind kind, const VarDeclarations& v, OutputStream& out);
 
-    SpvId writeVariableReference(const VariableReference& ref, SkWStream& out);
+    void writeVarDeclarations(const VarDeclarations& decl, OutputStream& out);
 
-    std::unique_ptr<LValue> getLValue(const Expression& value, SkWStream& out);
+    SpvId writeVariableReference(const VariableReference& ref, OutputStream& out);
 
-    SpvId writeExpression(const Expression& expr, SkWStream& out);
-    
-    SpvId writeIntrinsicCall(const FunctionCall& c, SkWStream& out);
+    std::unique_ptr<LValue> getLValue(const Expression& value, OutputStream& out);
 
-    SpvId writeFunctionCall(const FunctionCall& c, SkWStream& out);
+    SpvId writeExpression(const Expression& expr, OutputStream& out);
 
-    SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, SkWStream& out);
+    SpvId writeIntrinsicCall(const FunctionCall& c, OutputStream& out);
+
+    SpvId writeFunctionCall(const FunctionCall& c, OutputStream& out);
+
+    SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, OutputStream& out);
 
     SpvId writeConstantVector(const Constructor& c);
 
-    SpvId writeFloatConstructor(const Constructor& c, SkWStream& out);
+    SpvId writeFloatConstructor(const Constructor& c, OutputStream& out);
 
-    SpvId writeIntConstructor(const Constructor& c, SkWStream& out);
+    SpvId writeIntConstructor(const Constructor& c, OutputStream& out);
 
     /**
      * Writes a matrix with the diagonal entries all equal to the provided expression, and all other
      * entries equal to zero.
      */
-    void writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type, SkWStream& out);
+    void writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type, OutputStream& out);
 
     /**
      * Writes a potentially-different-sized copy of a matrix. Entries which do not exist in the
@@ -161,17 +160,17 @@
      * ignored.
      */
     void writeMatrixCopy(SpvId id, SpvId src, const Type& srcType, const Type& dstType,
-                         SkWStream& out);
+                         OutputStream& out);
 
-    SpvId writeMatrixConstructor(const Constructor& c, SkWStream& out);
+    SpvId writeMatrixConstructor(const Constructor& c, OutputStream& out);
 
-    SpvId writeVectorConstructor(const Constructor& c, SkWStream& out);
+    SpvId writeVectorConstructor(const Constructor& c, OutputStream& out);
 
-    SpvId writeConstructor(const Constructor& c, SkWStream& out);
+    SpvId writeConstructor(const Constructor& c, OutputStream& out);
 
-    SpvId writeFieldAccess(const FieldAccess& f, SkWStream& out);
+    SpvId writeFieldAccess(const FieldAccess& f, OutputStream& out);
 
-    SpvId writeSwizzle(const Swizzle& swizzle, SkWStream& out);
+    SpvId writeSwizzle(const Swizzle& swizzle, OutputStream& out);
 
     /**
      * Folds the potentially-vector result of a logical operation down to a single bool. If
@@ -179,28 +178,28 @@
      * same dimensions, and applys all() to it to fold it down to a single bool value. Otherwise,
      * returns the original id value.
      */
-    SpvId foldToBool(SpvId id, const Type& operandType, SkWStream& out);
+    SpvId foldToBool(SpvId id, const Type& operandType, OutputStream& out);
 
     SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
                                SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
-                               SpvOp_ ifBool, SkWStream& out);
+                               SpvOp_ ifBool, OutputStream& out);
 
     SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
-                               SpvOp_ ifUInt, SkWStream& out);
+                               SpvOp_ ifUInt, OutputStream& out);
 
-    SpvId writeBinaryExpression(const BinaryExpression& b, SkWStream& out);
+    SpvId writeBinaryExpression(const BinaryExpression& b, OutputStream& out);
 
-    SpvId writeTernaryExpression(const TernaryExpression& t, SkWStream& out);
+    SpvId writeTernaryExpression(const TernaryExpression& t, OutputStream& out);
 
-    SpvId writeIndexExpression(const IndexExpression& expr, SkWStream& out);
+    SpvId writeIndexExpression(const IndexExpression& expr, OutputStream& out);
 
-    SpvId writeLogicalAnd(const BinaryExpression& b, SkWStream& out);
+    SpvId writeLogicalAnd(const BinaryExpression& b, OutputStream& out);
 
-    SpvId writeLogicalOr(const BinaryExpression& o, SkWStream& out);
+    SpvId writeLogicalOr(const BinaryExpression& o, OutputStream& out);
 
-    SpvId writePrefixExpression(const PrefixExpression& p, SkWStream& out);
+    SpvId writePrefixExpression(const PrefixExpression& p, OutputStream& out);
 
-    SpvId writePostfixExpression(const PostfixExpression& p, SkWStream& out);
+    SpvId writePostfixExpression(const PostfixExpression& p, OutputStream& out);
 
     SpvId writeBoolLiteral(const BoolLiteral& b);
 
@@ -208,63 +207,63 @@
 
     SpvId writeFloatLiteral(const FloatLiteral& f);
 
-    void writeStatement(const Statement& s, SkWStream& out);
+    void writeStatement(const Statement& s, OutputStream& out);
 
-    void writeBlock(const Block& b, SkWStream& out);
+    void writeBlock(const Block& b, OutputStream& out);
 
-    void writeIfStatement(const IfStatement& stmt, SkWStream& out);
+    void writeIfStatement(const IfStatement& stmt, OutputStream& out);
 
-    void writeForStatement(const ForStatement& f, SkWStream& out);
+    void writeForStatement(const ForStatement& f, OutputStream& out);
 
-    void writeWhileStatement(const WhileStatement& w, SkWStream& out);
+    void writeWhileStatement(const WhileStatement& w, OutputStream& out);
 
-    void writeDoStatement(const DoStatement& d, SkWStream& out);
+    void writeDoStatement(const DoStatement& d, OutputStream& out);
 
-    void writeReturnStatement(const ReturnStatement& r, SkWStream& out);
+    void writeReturnStatement(const ReturnStatement& r, OutputStream& out);
 
-    void writeCapabilities(SkWStream& out);
+    void writeCapabilities(OutputStream& out);
 
-    void writeInstructions(const Program& program, SkWStream& out);
+    void writeInstructions(const Program& program, OutputStream& out);
 
-    void writeOpCode(SpvOp_ opCode, int length, SkWStream& out);
+    void writeOpCode(SpvOp_ opCode, int length, OutputStream& out);
 
-    void writeWord(int32_t word, SkWStream& out);
+    void writeWord(int32_t word, OutputStream& out);
 
-    void writeString(const char* string, SkWStream& out);
+    void writeString(const char* string, OutputStream& out);
 
-    void writeLabel(SpvId id, SkWStream& out);
+    void writeLabel(SpvId id, OutputStream& out);
 
-    void writeInstruction(SpvOp_ opCode, SkWStream& out);
+    void writeInstruction(SpvOp_ opCode, OutputStream& out);
 
-    void writeInstruction(SpvOp_ opCode, const char* string, SkWStream& out);
+    void writeInstruction(SpvOp_ opCode, const char* string, OutputStream& out);
 
-    void writeInstruction(SpvOp_ opCode, int32_t word1, SkWStream& out);
+    void writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out);
 
-    void writeInstruction(SpvOp_ opCode, int32_t word1, const char* string, SkWStream& out);
+    void writeInstruction(SpvOp_ opCode, int32_t word1, const char* string, OutputStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, const char* string,
-                          SkWStream& out);
+                          OutputStream& out);
 
-    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, SkWStream& out);
+    void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, OutputStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
-                          SkWStream& out);
+                          OutputStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
-                          SkWStream& out);
+                          OutputStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
-                          int32_t word5, SkWStream& out);
+                          int32_t word5, OutputStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
-                          int32_t word5, int32_t word6, SkWStream& out);
+                          int32_t word5, int32_t word6, OutputStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
-                          int32_t word5, int32_t word6, int32_t word7, SkWStream& out);
+                          int32_t word5, int32_t word6, int32_t word7, OutputStream& out);
 
     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
                           int32_t word5, int32_t word6, int32_t word7, int32_t word8,
-                          SkWStream& out);
+                          OutputStream& out);
 
     const Context& fContext;
     const MemoryLayout fDefaultLayout;
@@ -273,19 +272,19 @@
     SpvId fIdCount;
     SpvId fGLSLExtendedInstructions;
     typedef std::tuple<IntrinsicKind, int32_t, int32_t, int32_t, int32_t> Intrinsic;
-    std::unordered_map<SkString, Intrinsic> fIntrinsicMap;
+    std::unordered_map<String, Intrinsic> fIntrinsicMap;
     std::unordered_map<const FunctionDeclaration*, SpvId> fFunctionMap;
     std::unordered_map<const Variable*, SpvId> fVariableMap;
     std::unordered_map<const Variable*, int32_t> fInterfaceBlockMap;
-    std::unordered_map<SkString, SpvId> fTypeMap;
-    SkDynamicMemoryWStream fCapabilitiesBuffer;
-    SkDynamicMemoryWStream fGlobalInitializersBuffer;
-    SkDynamicMemoryWStream fConstantBuffer;
-    SkDynamicMemoryWStream fExtraGlobalsBuffer;
-    SkDynamicMemoryWStream fExternalFunctionsBuffer;
-    SkDynamicMemoryWStream fVariableBuffer;
-    SkDynamicMemoryWStream fNameBuffer;
-    SkDynamicMemoryWStream fDecorationBuffer;
+    std::unordered_map<String, SpvId> fTypeMap;
+    StringStream fCapabilitiesBuffer;
+    StringStream fGlobalInitializersBuffer;
+    StringStream fConstantBuffer;
+    StringStream fExtraGlobalsBuffer;
+    StringStream fExternalFunctionsBuffer;
+    StringStream fVariableBuffer;
+    StringStream fNameBuffer;
+    StringStream fDecorationBuffer;
 
     SpvId fBoolTrue;
     SpvId fBoolFalse;
diff --git a/src/sksl/SkSLString.cpp b/src/sksl/SkSLString.cpp
new file mode 100644
index 0000000..e98062e
--- /dev/null
+++ b/src/sksl/SkSLString.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLString.h"
+
+#include "SkSLUtil.h"
+#include <cinttypes>
+#include <errno.h>
+#include <limits.h>
+#include <locale>
+#include <sstream>
+#include <string>
+
+namespace SkSL {
+
+String String::printf(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    String result;
+    result.vappendf(fmt, args);
+    return result;
+}
+
+#ifdef SKSL_STANDALONE
+void String::appendf(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    this->vappendf(fmt, args);
+}
+#endif
+
+void String::vappendf(const char* fmt, va_list args) {
+#ifdef SKSL_BUILD_FOR_WIN
+    #define VSNPRINTF    _vsnprintf
+#else
+    #define VSNPRINTF    vsnprintf
+#endif
+    #define BUFFER_SIZE 256
+    char buffer[BUFFER_SIZE];
+    size_t size = VSNPRINTF(buffer, BUFFER_SIZE, fmt, args);
+    if (BUFFER_SIZE >= size) {
+        this->append(buffer, size);
+    } else {
+        auto newBuffer = std::unique_ptr<char[]>(new char[size]);
+        VSNPRINTF(newBuffer.get(), size, fmt, args);
+        this->append(newBuffer.get(), size);
+    }
+    va_end(args);
+}
+
+
+bool String::startsWith(const char* s) const {
+    return strncmp(c_str(), s, strlen(s));
+}
+
+bool String::endsWith(const char* s) const {
+    size_t len = strlen(s);
+    if (size() < len) {
+        return false;
+    }
+    return strncmp(c_str() + size() - len, s, len);
+}
+
+String String::operator+(const char* s) const {
+    String result(*this);
+    result.append(s);
+    return result;
+}
+
+String String::operator+(const String& s) const {
+    String result(*this);
+    result.append(s);
+    return result;
+}
+
+bool String::operator==(const String& s) const {
+    return this->size() == s.size() && !memcmp(c_str(), s.c_str(), this->size());
+}
+
+bool String::operator!=(const String& s) const {
+    return !(*this == s);
+}
+
+bool String::operator==(const char* s) const {
+    return this->size() == strlen(s) && !memcmp(c_str(), s, this->size());
+}
+
+bool String::operator!=(const char* s) const {
+    return !(*this == s);
+}
+
+String operator+(const char* s1, const String& s2) {
+    String result(s1);
+    result.append(s2);
+    return result;
+}
+
+bool operator==(const char* s1, const String& s2) {
+    return s2 == s1;
+}
+
+bool operator!=(const char* s1, const String& s2) {
+    return s2 != s1;
+}
+
+String to_string(int32_t value) {
+    return SkSL::String::printf("%d", value);
+}
+
+String to_string(uint32_t value) {
+    return SkSL::String::printf("%u", value);
+}
+
+String to_string(int64_t value) {
+    return SkSL::String::printf("%" PRId64, value);
+}
+
+String to_string(uint64_t value) {
+    return SkSL::String::printf("%" PRIu64, value);
+}
+
+String to_string(double value) {
+#ifdef SKSL_BUILD_FOR_WIN
+    #define SNPRINTF    _snprintf
+#else
+    #define SNPRINTF    snprintf
+#endif
+#define MAX_DOUBLE_CHARS 25
+    char buffer[MAX_DOUBLE_CHARS];
+    SKSL_DEBUGCODE(int len = )SNPRINTF(buffer, sizeof(buffer), "%.17g", value);
+    ASSERT(len < MAX_DOUBLE_CHARS);
+    String result(buffer);
+    if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
+        result += ".0";
+    }
+    return result;
+#undef SNPRINTF
+#undef MAX_DOUBLE_CHARS
+}
+
+int stoi(String s) {
+    char* p;
+    SKSL_DEBUGCODE(errno = 0;)
+    long result = strtol(s.c_str(), &p, 0);
+    ASSERT(*p == 0);
+    ASSERT(!errno && INT_MAX >= result && INT_MIN <= result);
+    return (int) result;
+}
+
+double stod(String s) {
+    double result;
+    std::string str(s.c_str(), s.size());
+    std::stringstream buffer(str);
+    buffer.imbue(std::locale::classic());
+    buffer >> result;
+    ASSERT(!buffer.fail());
+    return result;
+}
+
+long stol(String s) {
+    char* p;
+    SKSL_DEBUGCODE(errno = 0;)
+    long result = strtol(s.c_str(), &p, 0);
+    ASSERT(*p == 0);
+    ASSERT(!errno);
+    return result;
+}
+
+} // namespace
diff --git a/src/sksl/SkSLString.h b/src/sksl/SkSLString.h
new file mode 100644
index 0000000..73ba746
--- /dev/null
+++ b/src/sksl/SkSLString.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_STRING
+#define SKSL_STRING
+
+
+#ifdef SKSL_STANDALONE
+    #define SKSL_STRING_BASE std::string
+    #include <string>
+#else
+    #define SKSL_STRING_BASE SkString
+    #include "SkString.h"
+#endif
+
+namespace SkSL {
+
+class String : public SKSL_STRING_BASE {
+public:
+    String() = default;
+    String(const String&) = default;
+    String(String&&) = default;
+    String& operator=(const String&) = default;
+    String& operator=(String&&) = default;
+
+#ifndef SKSL_STANDALONE
+    String(const SkString& s)
+    : INHERITED(s) {}
+#endif
+
+    String(const char* s)
+    : INHERITED(s) {}
+
+    String(const char* s, size_t size)
+    : INHERITED(s, size) {}
+
+    static String printf(const char* fmt, ...);
+
+#ifdef SKSL_STANDALONE
+    void appendf(const char* fmt, ...);
+#endif
+    void vappendf(const char* fmt, va_list va);
+
+    bool startsWith(const char* s) const;
+    bool endsWith(const char* s) const;
+
+    String operator+(const char* s) const;
+    String operator+(const String& s) const;
+    bool operator==(const char* s) const;
+    bool operator!=(const char* s) const;
+    bool operator==(const String& s) const;
+    bool operator!=(const String& s) const;
+    friend String operator+(const char* s1, const String& s2);
+    friend bool operator==(const char* s1, const String& s2);
+    friend bool operator!=(const char* s1, const String& s2);
+
+private:
+    typedef SKSL_STRING_BASE INHERITED;
+};
+
+String operator+(const char* s1, const String& s2);
+bool operator!=(const char* s1, const String& s2);
+
+String to_string(double value);
+
+String to_string(int32_t value);
+
+String to_string(uint32_t value);
+
+String to_string(int64_t value);
+
+String to_string(uint64_t value);
+
+int stoi(String s);
+
+double stod(String s);
+
+long stol(String s);
+
+} // namespace
+
+#ifdef SKSL_STANDALONE
+namespace std {
+    template<> struct hash<SkSL::String> {
+        size_t operator()(const SkSL::String& s) const {
+            return hash<std::string>{}(s);
+        }
+    };
+} // namespace
+#else
+#include "SkOpts.h"
+namespace std {
+    template<> struct hash<SkSL::String> {
+        size_t operator()(const SkSL::String& s) const {
+            return SkOpts::hash_fn(s.c_str(), s.size(), 0);
+        }
+    };
+} // namespace
+#endif // SKIA_STANDALONE
+
+#endif
diff --git a/src/sksl/SkSLStringStream.h b/src/sksl/SkSLStringStream.h
new file mode 100644
index 0000000..9061432
--- /dev/null
+++ b/src/sksl/SkSLStringStream.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKSL_STRINGSTREAM
+#define SKSL_STRINGSTREAM
+
+#include "SkSLOutputStream.h"
+
+#ifdef SKSL_STANDALONE
+
+namespace SkSL {
+
+class StringStream : public OutputStream {
+public:
+    void write8(uint8_t b) override {
+        fBuffer += (char) b;
+    }
+
+    void writeText(const char* s) override {
+        fBuffer += s;
+    }
+
+    void write(const void* s, size_t size) override {
+        fBuffer.append((const char*) s, size);
+    }
+
+    const char* data() const {
+        return fBuffer.c_str();
+    }
+
+    size_t size() const {
+        return fBuffer.size();
+    }
+
+    void reset() {
+        fBuffer = "";
+    }
+
+private:
+    String fBuffer;
+};
+
+#else
+
+#include "SkData.h"
+#include "SkStream.h"
+
+namespace SkSL {
+
+class StringStream : public OutputStream {
+public:
+    void write8(uint8_t b) override {
+        SkASSERT(!fData);
+        fStream.write8(b);
+    }
+
+    void writeText(const char* s) override {
+        SkASSERT(!fData);
+        fStream.writeText(s);
+    }
+
+    void write(const void* s, size_t size) override {
+        SkASSERT(!fData);
+        fStream.write(s, size);
+    }
+
+    const char* data() const {
+        if (!fData) {
+            fData = fStream.detachAsData();
+        }
+        return (const char*) fData->data();
+    }
+
+    size_t size() const {
+        if (!fData) {
+            fData = fStream.detachAsData();
+        }
+        return fData->size();
+    }
+
+    void reset() {
+        fStream.reset();
+        fData = nullptr;
+    }
+
+private:
+    mutable SkDynamicMemoryWStream fStream;
+    mutable sk_sp<SkData> fData;
+};
+
+#endif // SKSL_STANDALONE
+
+} // namespace
+
+#endif
diff --git a/src/sksl/SkSLToken.h b/src/sksl/SkSLToken.h
index 6bacb90..8732e80 100644
--- a/src/sksl/SkSLToken.h
+++ b/src/sksl/SkSLToken.h
@@ -4,13 +4,13 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_TOKEN
 #define SKSL_TOKEN
 
 #include "SkSLPosition.h"
 #include "SkSLUtil.h"
- 
+
 namespace SkSL {
 
 #undef IN
@@ -131,54 +131,54 @@
         INVALID_TOKEN
     };
 
-    static SkString OperatorName(Kind kind) {
+    static String OperatorName(Kind kind) {
         switch (kind) {
-            case Token::PLUS:         return SkString("+");
-            case Token::MINUS:        return SkString("-");
-            case Token::STAR:         return SkString("*");
-            case Token::SLASH:        return SkString("/");
-            case Token::PERCENT:      return SkString("%");
-            case Token::SHL:          return SkString("<<");
-            case Token::SHR:          return SkString(">>");
-            case Token::LOGICALNOT:   return SkString("!");
-            case Token::LOGICALAND:   return SkString("&&");
-            case Token::LOGICALOR:    return SkString("||");
-            case Token::LOGICALXOR:   return SkString("^^");
-            case Token::BITWISENOT:   return SkString("~");
-            case Token::BITWISEAND:   return SkString("&");
-            case Token::BITWISEOR:    return SkString("|");
-            case Token::BITWISEXOR:   return SkString("^");
-            case Token::EQ:           return SkString("=");
-            case Token::EQEQ:         return SkString("==");
-            case Token::NEQ:          return SkString("!=");
-            case Token::LT:           return SkString("<");
-            case Token::GT:           return SkString(">");
-            case Token::LTEQ:         return SkString("<=");
-            case Token::GTEQ:         return SkString(">=");
-            case Token::PLUSEQ:       return SkString("+=");
-            case Token::MINUSEQ:      return SkString("-=");
-            case Token::STAREQ:       return SkString("*=");
-            case Token::SLASHEQ:      return SkString("/=");
-            case Token::PERCENTEQ:    return SkString("%=");
-            case Token::SHLEQ:        return SkString("<<=");
-            case Token::SHREQ:        return SkString(">>=");
-            case Token::LOGICALANDEQ: return SkString("&&=");
-            case Token::LOGICALOREQ:  return SkString("||=");
-            case Token::LOGICALXOREQ: return SkString("^^=");
-            case Token::BITWISEANDEQ: return SkString("&=");
-            case Token::BITWISEOREQ:  return SkString("|=");
-            case Token::BITWISEXOREQ: return SkString("^=");
-            case Token::PLUSPLUS:     return SkString("++");
-            case Token::MINUSMINUS:   return SkString("--");
+            case Token::PLUS:         return String("+");
+            case Token::MINUS:        return String("-");
+            case Token::STAR:         return String("*");
+            case Token::SLASH:        return String("/");
+            case Token::PERCENT:      return String("%");
+            case Token::SHL:          return String("<<");
+            case Token::SHR:          return String(">>");
+            case Token::LOGICALNOT:   return String("!");
+            case Token::LOGICALAND:   return String("&&");
+            case Token::LOGICALOR:    return String("||");
+            case Token::LOGICALXOR:   return String("^^");
+            case Token::BITWISENOT:   return String("~");
+            case Token::BITWISEAND:   return String("&");
+            case Token::BITWISEOR:    return String("|");
+            case Token::BITWISEXOR:   return String("^");
+            case Token::EQ:           return String("=");
+            case Token::EQEQ:         return String("==");
+            case Token::NEQ:          return String("!=");
+            case Token::LT:           return String("<");
+            case Token::GT:           return String(">");
+            case Token::LTEQ:         return String("<=");
+            case Token::GTEQ:         return String(">=");
+            case Token::PLUSEQ:       return String("+=");
+            case Token::MINUSEQ:      return String("-=");
+            case Token::STAREQ:       return String("*=");
+            case Token::SLASHEQ:      return String("/=");
+            case Token::PERCENTEQ:    return String("%=");
+            case Token::SHLEQ:        return String("<<=");
+            case Token::SHREQ:        return String(">>=");
+            case Token::LOGICALANDEQ: return String("&&=");
+            case Token::LOGICALOREQ:  return String("||=");
+            case Token::LOGICALXOREQ: return String("^^=");
+            case Token::BITWISEANDEQ: return String("&=");
+            case Token::BITWISEOREQ:  return String("|=");
+            case Token::BITWISEXOREQ: return String("^=");
+            case Token::PLUSPLUS:     return String("++");
+            case Token::MINUSMINUS:   return String("--");
             default:
-                ABORT("unsupported operator: %d\n", kind); 
-        }        
+                ABORT("unsupported operator: %d\n", kind);
+        }
     }
 
     Token() {
     }
 
-    Token(Position position, Kind kind, SkString text)
+    Token(Position position, Kind kind, String text)
     : fPosition(position)
     , fKind(kind)
     , fText(std::move(text)) {}
@@ -209,7 +209,7 @@
     Kind fKind;
     // will be the empty string unless the token has variable text content (identifiers, numeric
     // literals, and directives)
-    SkString fText;
+    String fText;
 };
 
 } // namespace
diff --git a/src/sksl/SkSLUtil.cpp b/src/sksl/SkSLUtil.cpp
index e93a953..c715cf1 100644
--- a/src/sksl/SkSLUtil.cpp
+++ b/src/sksl/SkSLUtil.cpp
@@ -10,117 +10,24 @@
 #ifndef __STDC_FORMAT_MACROS
 #define __STDC_FORMAT_MACROS
 #endif
-#include <cinttypes>
-#include <locale>
-#include <sstream>
-#include <string>
 
 namespace SkSL {
 
-SkString to_string(double value) {
-#ifdef SK_BUILD_FOR_WIN
-    #define SNPRINTF    _snprintf
-#else
-    #define SNPRINTF    snprintf
+#ifdef SKSL_STANDALONE
+StandaloneShaderCaps standaloneCaps;
 #endif
-#define MAX_DOUBLE_CHARS 25
-    char buffer[MAX_DOUBLE_CHARS];
-    SkDEBUGCODE(int len = )SNPRINTF(buffer, sizeof(buffer), "%.17g", value);
-    ASSERT(len < MAX_DOUBLE_CHARS);
-    SkString result(buffer);
-    if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
-        result += ".0";
-    }
-    return result;
-#undef SNPRINTF
-#undef MAX_DOUBLE_CHARS
-}
-
-SkString to_string(int32_t value) {
-    return SkStringPrintf("%d", value);
-}
-
-SkString to_string(uint32_t value) {
-    return SkStringPrintf("%u", value);
-}
-
-SkString to_string(int64_t value) {
-    return SkStringPrintf("%" PRId64, value);
-}
-
-SkString to_string(uint64_t value) {
-    return SkStringPrintf("%" PRIu64, value);
-}
-
-int stoi(SkString s) {
-    if (s.size() > 2 && s[0] == '0' && s[1] == 'x') {
-        char* p;
-        int result = strtoul(s.c_str() + 2, &p, 16);
-        ASSERT(*p == 0);
-        return result;
-    }
-    return atoi(s.c_str());
-}
-
-double stod(SkString s) {
-    double result;
-    std::string str(s.c_str(), s.size());
-    std::stringstream buffer(str);
-    buffer.imbue(std::locale::classic());
-    buffer >> result;
-    return result;
-}
-
-long stol(SkString s) {
-    if (s.size() > 2 && s[0] == '0' && s[1] == 'x') {
-        char* p;
-        long result = strtoul(s.c_str() + 2, &p, 16);
-        ASSERT(*p == 0);
-        return result;
-    }
-    return atol(s.c_str());
-}
 
 void sksl_abort() {
-#ifdef SKIA
+#ifdef SKSL_STANDALONE
+    abort();
+#else
     sk_abort_no_print();
     exit(1);
-#else
-    abort();
 #endif
 }
 
-void write_data(const SkData& data, SkWStream& out) {
-    out.write(data.data(), data.size());
+void write_stringstream(const StringStream& s, OutputStream& out) {
+    out.write(s.data(), s.size());
 }
 
-SkString operator+(const SkString& s, const char* c) {
-    SkString result(s);
-    result += c;
-    return result;
-}
-
-SkString operator+(const char* c, const SkString& s) {
-    SkString result(c);
-    result += s;
-    return result;
-}
-
-SkString operator+(const SkString& s1, const SkString& s2) {
-    SkString result(s1);
-    result += s2;
-    return result;
-}
-
-bool operator==(const SkString& s1, const char* s2) {
-    return !strcmp(s1.c_str(), s2);
-}
-
-bool operator!=(const SkString& s1, const char* s2) {
-    return strcmp(s1.c_str(), s2);
-}
-
-bool operator!=(const char* s1, const SkString& s2) {
-    return strcmp(s1, s2.c_str());
-}
 } // namespace
diff --git a/src/sksl/SkSLUtil.h b/src/sksl/SkSLUtil.h
index 678241d..d1af9bb 100644
--- a/src/sksl/SkSLUtil.h
+++ b/src/sksl/SkSLUtil.h
@@ -4,22 +4,159 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_UTIL
 #define SKSL_UTIL
 
+#include <cstdarg>
+#include <memory>
 #include "stdlib.h"
+#include "string.h"
 #include "assert.h"
-#include "SkOpts.h"
-#include "SkRefCnt.h"
-#include "SkStream.h"
-#include "SkString.h"
-#include "SkTypes.h"
+#include "SkSLString.h"
+#include "SkSLStringStream.h"
+
+#ifndef SKSL_STANDALONE
 #include "GrContextOptions.h"
 #include "GrShaderCaps.h"
+#endif
+
+#ifdef SKSL_STANDALONE
+#if defined(_WIN32) || defined(__SYMBIAN32__)
+#define SKSL_BUILD_FOR_WIN
+#endif
+#else
+#ifdef SK_BUILD_FOR_WIN
+#define SKSL_BUILD_FOR_WIN
+#endif // SK_BUILD_FOR_WIN
+#endif // SKSL_STANDALONE
 
 namespace SkSL {
 
+#ifdef SKSL_STANDALONE
+
+// we're being compiled standalone, so we don't have access to caps...
+enum GrGLSLGeneration {
+    k110_GrGLSLGeneration,
+    k130_GrGLSLGeneration,
+    k140_GrGLSLGeneration,
+    k150_GrGLSLGeneration,
+    k330_GrGLSLGeneration,
+    k400_GrGLSLGeneration,
+    k420_GrGLSLGeneration,
+    k310es_GrGLSLGeneration,
+    k320es_GrGLSLGeneration,
+};
+
+#define SKSL_CAPS_CLASS StandaloneShaderCaps
+class StandaloneShaderCaps {
+public:
+    GrGLSLGeneration generation() const {
+        return k400_GrGLSLGeneration;
+    }
+
+    bool canUseMinAndAbsTogether() const {
+        return true;
+    }
+
+    bool mustForceNegatedAtanParamToFloat() const {
+        return false;
+    }
+
+    bool shaderDerivativeSupport() const {
+        return true;
+    }
+
+    bool usesPrecisionModifiers() const {
+        return true;
+    }
+
+    bool mustDeclareFragmentShaderOutput() const {
+        return true;
+    }
+
+    bool fbFetchSupport() const {
+        return true;
+    }
+
+    bool fbFetchNeedsCustomOutput() const {
+        return false;
+    }
+
+    bool bindlessTextureSupport() const {
+        return false;
+    }
+
+    bool dropsTileOnZeroDivide() const {
+        return false;
+    }
+
+    bool flatInterpolationSupport() const {
+        return true;
+    }
+
+    bool noperspectiveInterpolationSupport() const {
+        return true;
+    }
+
+    bool multisampleInterpolationSupport() const {
+        return true;
+    }
+
+    bool sampleVariablesSupport() const {
+        return true;
+    }
+
+    bool sampleMaskOverrideCoverageSupport() const {
+        return true;
+    }
+
+    bool externalTextureSupport() const {
+        return true;
+    }
+
+    bool texelFetchSupport() const {
+        return true;
+    }
+
+    bool imageLoadStoreSupport() const {
+        return true;
+    }
+
+    bool mustEnableAdvBlendEqs() const {
+        return false;
+    }
+
+    bool mustEnableSpecificAdvBlendEqs() const {
+        return false;
+    }
+
+    bool canUseAnyFunctionInShader() const {
+        return false;
+    }
+
+    const char* shaderDerivativeExtensionString() const {
+        return nullptr;
+    }
+
+    const char* fragCoordConventionsExtensionString() const {
+        return nullptr;
+    }
+
+    const char* imageLoadStoreExtensionString() const {
+        return nullptr;
+    }
+
+    const char* versionDeclString() const {
+        return "";
+    }
+};
+
+extern StandaloneShaderCaps standaloneCaps;
+
+#else
+
+#define SKSL_CAPS_CLASS GrShaderCaps
 // Various sets of caps for use in tests
 class ShaderCapsFactory {
 public:
@@ -98,60 +235,38 @@
         return result;
     }
 };
+#endif
 
-void write_data(const SkData& d, SkWStream& out);
-
-SkString operator+(const SkString& s, const char* c);
-
-SkString operator+(const char* c, const SkString& s);
-
-SkString operator+(const SkString& s1, const SkString& s2);
-
-bool operator==(const SkString& s1, const char* s2);
-
-bool operator!=(const SkString& s1, const char* s2);
-
-bool operator!=(const char* s1, const SkString& s2);
-
-SkString to_string(double value);
-
-SkString to_string(int32_t value);
-
-SkString to_string(uint32_t value);
-
-SkString to_string(int64_t value);
-
-SkString to_string(uint64_t value);
+void write_stringstream(const StringStream& d, OutputStream& out);
 
 #if _MSC_VER
 #define NORETURN __declspec(noreturn)
 #else
 #define NORETURN __attribute__((__noreturn__))
 #endif
-int stoi(SkString s);
-
-double stod(SkString s);
-
-long stol(SkString s);
 
 NORETURN void sksl_abort();
 
 } // namespace
 
-#define ASSERT(x) SkASSERT(x)
-#define ASSERT_RESULT(x) SkAssertResult(x);
-
-#ifdef SKIA
-#define ABORT(...) { SkDebugf(__VA_ARGS__); sksl_abort(); }
+#ifdef SKSL_STANDALONE
+#define ASSERT(x) (void)((x) || (ABORT("failed assert(%s): %s:%d\n", #x, __FILE__, __LINE__), 0))
+#define ASSERT_RESULT(x) ASSERT(x)
+#define SKSL_DEBUGCODE(x) x
 #else
-#define ABORT(...) { sksl_abort(); }
+#define ASSERT SkASSERT
+#define ASSERT_RESULT(x) SkAssertResult(x)
+#define SKSL_DEBUGCODE(x) SkDEBUGCODE(x)
 #endif
 
-namespace std {
-    template<> struct hash<SkString> {
-        size_t operator()(const SkString& s) const {
-            return SkOpts::hash_fn(s.c_str(), s.size(), 0);
-        }
-    };
-}
+#define SKSL_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+
+#if defined(__clang__) || defined(__GNUC__)
+#define SKSL_PRINTF_LIKE(A, B) __attribute__((format(printf, (A), (B))))
+#else
+#define SKSL_PRINTF_LIKE(A, B)
+#endif
+
+#define ABORT(...) (printf(__VA_ARGS__), sksl_abort())
+
 #endif
diff --git a/src/sksl/ast/SkSLASTBinaryExpression.h b/src/sksl/ast/SkSLASTBinaryExpression.h
index c4b6e3a..9a24970 100644
--- a/src/sksl/ast/SkSLASTBinaryExpression.h
+++ b/src/sksl/ast/SkSLASTBinaryExpression.h
@@ -14,7 +14,7 @@
 namespace SkSL {
 
 /**
- * Represents a binary operation, with the operator represented by the token's type. 
+ * Represents a binary operation, with the operator represented by the token's type.
  */
 struct ASTBinaryExpression : public ASTExpression {
     ASTBinaryExpression(std::unique_ptr<ASTExpression> left, Token op,
@@ -24,7 +24,7 @@
     , fOperator(op.fKind)
     , fRight(std::move(right)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "(" + fLeft->description() + " " + Token::OperatorName(fOperator) + " " +
                fRight->description() + ")";
     }
diff --git a/src/sksl/ast/SkSLASTBlock.h b/src/sksl/ast/SkSLASTBlock.h
index 6b1e9c5..37c0e81 100644
--- a/src/sksl/ast/SkSLASTBlock.h
+++ b/src/sksl/ast/SkSLASTBlock.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTBLOCK
 #define SKSL_ASTBLOCK
 
@@ -13,21 +13,21 @@
 namespace SkSL {
 
 /**
- * Represents a curly-braced block of statements. 
+ * Represents a curly-braced block of statements.
  */
 struct ASTBlock : public ASTStatement {
     ASTBlock(Position position, std::vector<std::unique_ptr<ASTStatement>> statements)
     : INHERITED(position, kBlock_Kind)
     , fStatements(std::move(statements)) {}
 
-    SkString description() const override {
-        SkString result("{");
+    String description() const override {
+        String result("{");
         for (size_t i = 0; i < fStatements.size(); i++) {
             result += "\n";
             result += fStatements[i]->description();
         }
         result += "\n}\n";
-        return result;        
+        return result;
     }
 
     const std::vector<std::unique_ptr<ASTStatement>> fStatements;
diff --git a/src/sksl/ast/SkSLASTBoolLiteral.h b/src/sksl/ast/SkSLASTBoolLiteral.h
index 02f4bac..48e916e 100644
--- a/src/sksl/ast/SkSLASTBoolLiteral.h
+++ b/src/sksl/ast/SkSLASTBoolLiteral.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTBOOLLITERAL
 #define SKSL_ASTBOOLLITERAL
 
@@ -13,15 +13,15 @@
 namespace SkSL {
 
 /**
- * Represents "true" or "false". 
+ * Represents "true" or "false".
  */
 struct ASTBoolLiteral : public ASTExpression {
     ASTBoolLiteral(Position position, bool value)
     : INHERITED(position, kBool_Kind)
     , fValue(value) {}
 
-    SkString description() const override {
-        return SkString(fValue ? "true" : "false");
+    String description() const override {
+        return String(fValue ? "true" : "false");
     }
 
     const bool fValue;
diff --git a/src/sksl/ast/SkSLASTBreakStatement.h b/src/sksl/ast/SkSLASTBreakStatement.h
index dad2a85..079ee76 100644
--- a/src/sksl/ast/SkSLASTBreakStatement.h
+++ b/src/sksl/ast/SkSLASTBreakStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTBREAKSTATEMENT
 #define SKSL_ASTBREAKSTATEMENT
 
@@ -13,14 +13,14 @@
 namespace SkSL {
 
 /**
- * A 'break' statement. 
+ * A 'break' statement.
  */
 struct ASTBreakStatement : public ASTStatement {
     ASTBreakStatement(Position position)
     : INHERITED(position, kBreak_Kind) {}
 
-    SkString description() const override {
-        return SkString("break;");
+    String description() const override {
+        return String("break;");
     }
 
     typedef ASTStatement INHERITED;
diff --git a/src/sksl/ast/SkSLASTCallSuffix.h b/src/sksl/ast/SkSLASTCallSuffix.h
index 356ac85..3ba3f0e 100644
--- a/src/sksl/ast/SkSLASTCallSuffix.h
+++ b/src/sksl/ast/SkSLASTCallSuffix.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTCALLSUFFIX
 #define SKSL_ASTCALLSUFFIX
 
@@ -14,16 +14,16 @@
 namespace SkSL {
 
 /**
- * A parenthesized list of arguments following an expression, indicating a function call. 
+ * A parenthesized list of arguments following an expression, indicating a function call.
  */
 struct ASTCallSuffix : public ASTSuffix {
-    ASTCallSuffix(Position position, std::vector<std::unique_ptr<ASTExpression>> arguments) 
+    ASTCallSuffix(Position position, std::vector<std::unique_ptr<ASTExpression>> arguments)
     : INHERITED(position, ASTSuffix::kCall_Kind)
     , fArguments(std::move(arguments)) {}
 
-    SkString description() const override {
-        SkString result("(");
-        SkString separator;
+    String description() const override {
+        String result("(");
+        String separator;
         for (size_t i = 0; i < fArguments.size(); ++i) {
             result += separator;
             separator = ", ";
diff --git a/src/sksl/ast/SkSLASTContinueStatement.h b/src/sksl/ast/SkSLASTContinueStatement.h
index 4cded3b..fdfce85 100644
--- a/src/sksl/ast/SkSLASTContinueStatement.h
+++ b/src/sksl/ast/SkSLASTContinueStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTCONTINUESTATEMENT
 #define SKSL_ASTCONTINUESTATEMENT
 
@@ -13,14 +13,14 @@
 namespace SkSL {
 
 /**
- * A 'continue' statement. 
+ * A 'continue' statement.
  */
 struct ASTContinueStatement : public ASTStatement {
     ASTContinueStatement(Position position)
     : INHERITED(position, kContinue_Kind) {}
 
-    SkString description() const override {
-        return SkString("continue;");
+    String description() const override {
+        return String("continue;");
     }
 
     typedef ASTStatement INHERITED;
diff --git a/src/sksl/ast/SkSLASTDeclaration.h b/src/sksl/ast/SkSLASTDeclaration.h
index 70f0ebc..0395ef9 100644
--- a/src/sksl/ast/SkSLASTDeclaration.h
+++ b/src/sksl/ast/SkSLASTDeclaration.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTDECLARATION
 #define SKSL_ASTDECLARATION
 
@@ -13,7 +13,7 @@
 namespace SkSL {
 
 /**
- * Abstract supertype of declarations such as variables and functions. 
+ * Abstract supertype of declarations such as variables and functions.
  */
 struct ASTDeclaration : public ASTPositionNode {
     enum Kind {
diff --git a/src/sksl/ast/SkSLASTDiscardStatement.h b/src/sksl/ast/SkSLASTDiscardStatement.h
index 754bf95..dcf6b15 100644
--- a/src/sksl/ast/SkSLASTDiscardStatement.h
+++ b/src/sksl/ast/SkSLASTDiscardStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTDISCARDSTATEMENT
 #define SKSL_ASTDISCARDSTATEMENT
 
@@ -13,14 +13,14 @@
 namespace SkSL {
 
 /**
- * A 'discard' statement. 
+ * A 'discard' statement.
  */
 struct ASTDiscardStatement : public ASTStatement {
     ASTDiscardStatement(Position position)
     : INHERITED(position, kDiscard_Kind) {}
 
-    SkString description() const override {
-        return SkString("discard;");
+    String description() const override {
+        return String("discard;");
     }
 
     typedef ASTStatement INHERITED;
diff --git a/src/sksl/ast/SkSLASTDoStatement.h b/src/sksl/ast/SkSLASTDoStatement.h
index 9a0cace..fc97d9e 100644
--- a/src/sksl/ast/SkSLASTDoStatement.h
+++ b/src/sksl/ast/SkSLASTDoStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTDOSTATEMENT
 #define SKSL_ASTDOSTATEMENT
 
@@ -13,7 +13,7 @@
 namespace SkSL {
 
 /**
- * A 'do' loop. 
+ * A 'do' loop.
  */
 struct ASTDoStatement : public ASTStatement {
     ASTDoStatement(Position position, std::unique_ptr<ASTStatement> statement,
@@ -22,7 +22,7 @@
     , fStatement(std::move(statement))
     , fTest(std::move(test)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "do " + fStatement->description() + " while (" + fTest->description() + ");";
     }
 
diff --git a/src/sksl/ast/SkSLASTExpression.h b/src/sksl/ast/SkSLASTExpression.h
index 8a48271..11815ae 100644
--- a/src/sksl/ast/SkSLASTExpression.h
+++ b/src/sksl/ast/SkSLASTExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTEXPRESSION
 #define SKSL_ASTEXPRESSION
 
@@ -13,7 +13,7 @@
 namespace SkSL {
 
 /**
- * Abstract supertype of all expressions. 
+ * Abstract supertype of all expressions.
  */
 struct ASTExpression : public ASTPositionNode {
     enum Kind {
diff --git a/src/sksl/ast/SkSLASTExpressionStatement.h b/src/sksl/ast/SkSLASTExpressionStatement.h
index 2dbd209..398a16a 100644
--- a/src/sksl/ast/SkSLASTExpressionStatement.h
+++ b/src/sksl/ast/SkSLASTExpressionStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTEXPRESSIONSTATEMENT
 #define SKSL_ASTEXPRESSIONSTATEMENT
 
@@ -13,14 +13,14 @@
 namespace SkSL {
 
 /**
- * A lone expression being used as a statement. 
+ * A lone expression being used as a statement.
  */
 struct ASTExpressionStatement : public ASTStatement {
     ASTExpressionStatement(std::unique_ptr<ASTExpression> expression)
     : INHERITED(expression->fPosition, kExpression_Kind)
     , fExpression(std::move(expression)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fExpression->description() + ";";
     }
 
diff --git a/src/sksl/ast/SkSLASTExtension.h b/src/sksl/ast/SkSLASTExtension.h
index b9df3c5..a6fde06 100644
--- a/src/sksl/ast/SkSLASTExtension.h
+++ b/src/sksl/ast/SkSLASTExtension.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTEXTENSION
 #define SKSL_ASTEXTENSION
 
@@ -12,19 +12,19 @@
 
 namespace SkSL {
 
-/** 
- * An extension declaration. 
+/**
+ * An extension declaration.
  */
 struct ASTExtension : public ASTDeclaration {
-    ASTExtension(Position position, SkString name)
+    ASTExtension(Position position, String name)
     : INHERITED(position, kExtension_Kind)
     , fName(std::move(name)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "#extension " + fName + " : enable";
     }
 
-    const SkString fName;
+    const String fName;
 
     typedef ASTDeclaration INHERITED;
 };
diff --git a/src/sksl/ast/SkSLASTFieldSuffix.h b/src/sksl/ast/SkSLASTFieldSuffix.h
index 9ee8531..bde1e4a 100644
--- a/src/sksl/ast/SkSLASTFieldSuffix.h
+++ b/src/sksl/ast/SkSLASTFieldSuffix.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTFIELDSUFFIX
 #define SKSL_ASTFIELDSUFFIX
 
@@ -17,15 +17,15 @@
  * actually vector swizzle (which looks the same to the parser).
  */
 struct ASTFieldSuffix : public ASTSuffix {
-    ASTFieldSuffix(Position position, SkString field) 
+    ASTFieldSuffix(Position position, String field)
     : INHERITED(position, ASTSuffix::kField_Kind)
     , fField(std::move(field)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "." + fField;
     }
 
-    SkString fField;
+    String fField;
 
     typedef ASTSuffix INHERITED;
 };
diff --git a/src/sksl/ast/SkSLASTFloatLiteral.h b/src/sksl/ast/SkSLASTFloatLiteral.h
index ea0f595..15fe836 100644
--- a/src/sksl/ast/SkSLASTFloatLiteral.h
+++ b/src/sksl/ast/SkSLASTFloatLiteral.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTFLOATLITERAL
 #define SKSL_ASTFLOATLITERAL
 
@@ -13,14 +13,14 @@
 namespace SkSL {
 
 /**
- * A literal floating point number. 
+ * A literal floating point number.
  */
 struct ASTFloatLiteral : public ASTExpression {
     ASTFloatLiteral(Position position, double value)
     : INHERITED(position, kFloat_Kind)
     , fValue(value) {}
 
-    SkString description() const override {
+    String description() const override {
         return to_string(fValue);
     }
 
diff --git a/src/sksl/ast/SkSLASTForStatement.h b/src/sksl/ast/SkSLASTForStatement.h
index 2706a39..326713e 100644
--- a/src/sksl/ast/SkSLASTForStatement.h
+++ b/src/sksl/ast/SkSLASTForStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTFORSTATEMENT
 #define SKSL_ASTFORSTATEMENT
 
@@ -13,10 +13,10 @@
 namespace SkSL {
 
 /**
- * A 'for' loop. 
+ * A 'for' loop.
  */
 struct ASTForStatement : public ASTStatement {
-    ASTForStatement(Position position, std::unique_ptr<ASTStatement> initializer, 
+    ASTForStatement(Position position, std::unique_ptr<ASTStatement> initializer,
                    std::unique_ptr<ASTExpression> test, std::unique_ptr<ASTExpression> next,
                    std::unique_ptr<ASTStatement> statement)
     : INHERITED(position, kFor_Kind)
@@ -25,8 +25,8 @@
     , fNext(std::move(next))
     , fStatement(std::move(statement)) {}
 
-    SkString description() const override {
-        SkString result("for (");
+    String description() const override {
+        String result("for (");
         if (fInitializer) {
             result.append(fInitializer->description());
         }
diff --git a/src/sksl/ast/SkSLASTFunction.h b/src/sksl/ast/SkSLASTFunction.h
index 32f4da7..d9f3067 100644
--- a/src/sksl/ast/SkSLASTFunction.h
+++ b/src/sksl/ast/SkSLASTFunction.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTFUNCTION
 #define SKSL_ASTFUNCTION
 
@@ -16,11 +16,11 @@
 namespace SkSL {
 
 /**
- * A function declaration or definition. The fBody field will be null for declarations. 
+ * A function declaration or definition. The fBody field will be null for declarations.
  */
 struct ASTFunction : public ASTDeclaration {
-    ASTFunction(Position position, std::unique_ptr<ASTType> returnType, SkString name,
-                std::vector<std::unique_ptr<ASTParameter>> parameters, 
+    ASTFunction(Position position, std::unique_ptr<ASTType> returnType, String name,
+                std::vector<std::unique_ptr<ASTParameter>> parameters,
                 std::unique_ptr<ASTBlock> body)
     : INHERITED(position, kFunction_Kind)
     , fReturnType(std::move(returnType))
@@ -28,8 +28,8 @@
     , fParameters(std::move(parameters))
     , fBody(std::move(body)) {}
 
-    SkString description() const override {
-        SkString result = fReturnType->description() + " " + fName + "(";
+    String description() const override {
+        String result = fReturnType->description() + " " + fName + "(";
         for (size_t i = 0; i < fParameters.size(); i++) {
             if (i > 0) {
                 result += ", ";
@@ -41,11 +41,11 @@
         } else {
             result += ");";
         }
-        return result;        
+        return result;
     }
 
     const std::unique_ptr<ASTType> fReturnType;
-    const SkString fName;
+    const String fName;
     const std::vector<std::unique_ptr<ASTParameter>> fParameters;
     const std::unique_ptr<ASTBlock> fBody;
 
diff --git a/src/sksl/ast/SkSLASTIdentifier.h b/src/sksl/ast/SkSLASTIdentifier.h
index aa0179a..016123c 100644
--- a/src/sksl/ast/SkSLASTIdentifier.h
+++ b/src/sksl/ast/SkSLASTIdentifier.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTIDENTIFIER
 #define SKSL_ASTIDENTIFIER
 
@@ -13,18 +13,18 @@
 namespace SkSL {
 
 /**
- * An identifier in an expression context. 
+ * An identifier in an expression context.
  */
 struct ASTIdentifier : public ASTExpression {
-    ASTIdentifier(Position position, SkString text)
+    ASTIdentifier(Position position, String text)
     : INHERITED(position, kIdentifier_Kind)
     , fText(std::move(text)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fText;
     }
 
-    const SkString fText;
+    const String fText;
 
     typedef ASTExpression INHERITED;
 };
diff --git a/src/sksl/ast/SkSLASTIfStatement.h b/src/sksl/ast/SkSLASTIfStatement.h
index d169702..684bea0 100644
--- a/src/sksl/ast/SkSLASTIfStatement.h
+++ b/src/sksl/ast/SkSLASTIfStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTIFSTATEMENT
 #define SKSL_ASTIFSTATEMENT
 
@@ -13,18 +13,18 @@
 namespace SkSL {
 
 /**
- * An 'if' statement. 
+ * An 'if' statement.
  */
 struct ASTIfStatement : public ASTStatement {
-    ASTIfStatement(Position position, std::unique_ptr<ASTExpression> test, 
+    ASTIfStatement(Position position, std::unique_ptr<ASTExpression> test,
                    std::unique_ptr<ASTStatement> ifTrue, std::unique_ptr<ASTStatement> ifFalse)
     : INHERITED(position, kIf_Kind)
     , fTest(std::move(test))
     , fIfTrue(std::move(ifTrue))
     , fIfFalse(std::move(ifFalse)) {}
 
-    SkString description() const override {
-        SkString result("if (");
+    String description() const override {
+        String result("if (");
         result += fTest->description();
         result += ") ";
         result += fIfTrue->description();
@@ -32,7 +32,7 @@
             result += " else ";
             result += fIfFalse->description();
         }
-        return result;        
+        return result;
     }
 
     const std::unique_ptr<ASTExpression> fTest;
diff --git a/src/sksl/ast/SkSLASTIndexSuffix.h b/src/sksl/ast/SkSLASTIndexSuffix.h
index 2b7cd48..31142e3 100644
--- a/src/sksl/ast/SkSLASTIndexSuffix.h
+++ b/src/sksl/ast/SkSLASTIndexSuffix.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTINDEXSUFFIX
 #define SKSL_ASTINDEXSUFFIX
 
@@ -18,19 +18,19 @@
  * 'float[](5, 6)' are represented with a null fExpression.
  */
 struct ASTIndexSuffix : public ASTSuffix {
-    ASTIndexSuffix(Position position) 
+    ASTIndexSuffix(Position position)
     : INHERITED(position, ASTSuffix::kIndex_Kind)
     , fExpression(nullptr) {}
 
-    ASTIndexSuffix(std::unique_ptr<ASTExpression> expression) 
+    ASTIndexSuffix(std::unique_ptr<ASTExpression> expression)
     : INHERITED(expression ? expression->fPosition : Position(), ASTSuffix::kIndex_Kind)
     , fExpression(std::move(expression)) {}
 
-    SkString description() const override {
+    String description() const override {
         if (fExpression) {
             return "[" + fExpression->description() + "]";
         } else {
-            return SkString("[]");
+            return String("[]");
         }
     }
 
diff --git a/src/sksl/ast/SkSLASTIntLiteral.h b/src/sksl/ast/SkSLASTIntLiteral.h
index f524bc0..fe04347 100644
--- a/src/sksl/ast/SkSLASTIntLiteral.h
+++ b/src/sksl/ast/SkSLASTIntLiteral.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTINTLITERAL
 #define SKSL_ASTINTLITERAL
 
@@ -21,7 +21,7 @@
     : INHERITED(position, kInt_Kind)
     , fValue(value) {}
 
-    SkString description() const override {
+    String description() const override {
         return to_string(fValue);
     }
 
diff --git a/src/sksl/ast/SkSLASTInterfaceBlock.h b/src/sksl/ast/SkSLASTInterfaceBlock.h
index 7647fb5..e727ae9 100644
--- a/src/sksl/ast/SkSLASTInterfaceBlock.h
+++ b/src/sksl/ast/SkSLASTInterfaceBlock.h
@@ -25,9 +25,9 @@
     // valueName is empty when it was not present in the source
     ASTInterfaceBlock(Position position,
                       Modifiers modifiers,
-                      SkString typeName,
+                      String typeName,
                       std::vector<std::unique_ptr<ASTVarDeclarations>> declarations,
-                      SkString instanceName,
+                      String instanceName,
                       std::vector<std::unique_ptr<ASTExpression>> sizes)
     : INHERITED(position, kInterfaceBlock_Kind)
     , fModifiers(modifiers)
@@ -36,8 +36,8 @@
     , fInstanceName(std::move(instanceName))
     , fSizes(std::move(sizes)) {}
 
-    SkString description() const override {
-        SkString result = fModifiers.description() + fTypeName + " {\n";
+    String description() const override {
+        String result = fModifiers.description() + fTypeName + " {\n";
         for (size_t i = 0; i < fDeclarations.size(); i++) {
             result += fDeclarations[i]->description() + "\n";
         }
@@ -56,9 +56,9 @@
     }
 
     const Modifiers fModifiers;
-    const SkString fTypeName;
+    const String fTypeName;
     const std::vector<std::unique_ptr<ASTVarDeclarations>> fDeclarations;
-    const SkString fInstanceName;
+    const String fInstanceName;
     const std::vector<std::unique_ptr<ASTExpression>> fSizes;
 
     typedef ASTDeclaration INHERITED;
diff --git a/src/sksl/ast/SkSLASTModifiersDeclaration.h b/src/sksl/ast/SkSLASTModifiersDeclaration.h
index 7950f6d..ba07f16 100644
--- a/src/sksl/ast/SkSLASTModifiersDeclaration.h
+++ b/src/sksl/ast/SkSLASTModifiersDeclaration.h
@@ -23,7 +23,7 @@
     : INHERITED(Position(), kModifiers_Kind)
     , fModifiers(modifiers) {}
 
-    SkString description() const {
+    String description() const {
         return fModifiers.description() + ";";
     }
 
diff --git a/src/sksl/ast/SkSLASTNode.h b/src/sksl/ast/SkSLASTNode.h
index af06595..b08bc2a 100644
--- a/src/sksl/ast/SkSLASTNode.h
+++ b/src/sksl/ast/SkSLASTNode.h
@@ -4,11 +4,11 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTNODE
 #define SKSL_ASTNODE
 
-#include "SkString.h"
+#include "SkSLString.h"
 
 namespace SkSL {
 
@@ -18,8 +18,8 @@
  */
 struct ASTNode {
     virtual ~ASTNode() {}
-     
-    virtual SkString description() const = 0;
+
+    virtual String description() const = 0;
 };
 
 } // namespace
diff --git a/src/sksl/ast/SkSLASTParameter.h b/src/sksl/ast/SkSLASTParameter.h
index 6bb13ac..01227c6 100644
--- a/src/sksl/ast/SkSLASTParameter.h
+++ b/src/sksl/ast/SkSLASTParameter.h
@@ -21,15 +21,15 @@
     // 'sizes' is a list of the array sizes appearing on a parameter, in source order.
     // e.g. int x[3][1] would have sizes [3, 1].
     ASTParameter(Position position, Modifiers modifiers, std::unique_ptr<ASTType> type,
-                 SkString name, std::vector<int> sizes)
+                 String name, std::vector<int> sizes)
     : INHERITED(position)
     , fModifiers(modifiers)
     , fType(std::move(type))
     , fName(std::move(name))
     , fSizes(std::move(sizes)) {}
 
-    SkString description() const override {
-        SkString result = fModifiers.description() + fType->description() + " " + fName;
+    String description() const override {
+        String result = fModifiers.description() + fType->description() + " " + fName;
         for (int size : fSizes) {
             result += "[" + to_string(size) + "]";
         }
@@ -38,7 +38,7 @@
 
     const Modifiers fModifiers;
     const std::unique_ptr<ASTType> fType;
-    const SkString fName;
+    const String fName;
     const std::vector<int> fSizes;
 
     typedef ASTPositionNode INHERITED;
diff --git a/src/sksl/ast/SkSLASTPositionNode.h b/src/sksl/ast/SkSLASTPositionNode.h
index 226b4ae..cc435c4 100644
--- a/src/sksl/ast/SkSLASTPositionNode.h
+++ b/src/sksl/ast/SkSLASTPositionNode.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTPOSITIONNODE
 #define SKSL_ASTPOSITIONNODE
 
diff --git a/src/sksl/ast/SkSLASTPrecision.h b/src/sksl/ast/SkSLASTPrecision.h
index a2f427c..4b50ed3 100644
--- a/src/sksl/ast/SkSLASTPrecision.h
+++ b/src/sksl/ast/SkSLASTPrecision.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTPRECISION
 #define SKSL_ASTPRECISION
 
@@ -22,17 +22,17 @@
     : INHERITED(position, kPrecision_Kind)
     , fPrecision(precision) {}
 
-    SkString description() const {
+    String description() const {
         switch (fPrecision) {
-            case Modifiers::kLowp_Flag: return SkString("precision lowp float;");
-            case Modifiers::kMediump_Flag: return SkString("precision mediump float;");
-            case Modifiers::kHighp_Flag: return SkString("precision highp float;");
-            default: 
-                ASSERT(false); 
-                return SkString("<error>");
+            case Modifiers::kLowp_Flag: return String("precision lowp float;");
+            case Modifiers::kMediump_Flag: return String("precision mediump float;");
+            case Modifiers::kHighp_Flag: return String("precision highp float;");
+            default:
+                ASSERT(false);
+                return String("<error>");
         }
         ASSERT(false);
-        return SkString("<error>");
+        return String("<error>");
     }
 
     const Modifiers::Flag fPrecision;
diff --git a/src/sksl/ast/SkSLASTPrefixExpression.h b/src/sksl/ast/SkSLASTPrefixExpression.h
index e06ec41..08e50f7 100644
--- a/src/sksl/ast/SkSLASTPrefixExpression.h
+++ b/src/sksl/ast/SkSLASTPrefixExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTPREFIXEXPRESSION
 #define SKSL_ASTPREFIXEXPRESSION
 
@@ -22,7 +22,7 @@
     , fOperator(op.fKind)
     , fOperand(std::move(operand)) {}
 
-    SkString description() const override {
+    String description() const override {
         return Token::OperatorName(fOperator) + fOperand->description();
     }
 
diff --git a/src/sksl/ast/SkSLASTReturnStatement.h b/src/sksl/ast/SkSLASTReturnStatement.h
index ed24d4a..6762eb3 100644
--- a/src/sksl/ast/SkSLASTReturnStatement.h
+++ b/src/sksl/ast/SkSLASTReturnStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTRETURNSTATEMENT
 #define SKSL_ASTRETURNSTATEMENT
 
@@ -21,12 +21,12 @@
     : INHERITED(position, kReturn_Kind)
     , fExpression(std::move(expression)) {}
 
-    SkString description() const override {
-        SkString result("return");
+    String description() const override {
+        String result("return");
         if (fExpression) {
             result += " " + fExpression->description();
         }
-        return result + ";";        
+        return result + ";";
     }
 
     const std::unique_ptr<ASTExpression> fExpression;
diff --git a/src/sksl/ast/SkSLASTStatement.h b/src/sksl/ast/SkSLASTStatement.h
index 6ce320e..1989a1f 100644
--- a/src/sksl/ast/SkSLASTStatement.h
+++ b/src/sksl/ast/SkSLASTStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTSTATEMENT
 #define SKSL_ASTSTATEMENT
 
diff --git a/src/sksl/ast/SkSLASTSuffix.h b/src/sksl/ast/SkSLASTSuffix.h
index 64178c7..f06c6fd 100644
--- a/src/sksl/ast/SkSLASTSuffix.h
+++ b/src/sksl/ast/SkSLASTSuffix.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTSUFFIX
 #define SKSL_ASTSUFFIX
 
@@ -30,15 +30,15 @@
     : INHERITED(position)
     , fKind(kind) {}
 
-    SkString description() const override {
+    String description() const override {
         switch (fKind) {
             case kPostIncrement_Kind:
-                return SkString("++");
+                return String("++");
             case kPostDecrement_Kind:
-                return SkString("--");
+                return String("--");
             default:
                 ABORT("unsupported suffix operator");
-        }        
+        }
     }
 
     Kind fKind;
diff --git a/src/sksl/ast/SkSLASTSuffixExpression.h b/src/sksl/ast/SkSLASTSuffixExpression.h
index 7ee200f..2cff9a8 100644
--- a/src/sksl/ast/SkSLASTSuffixExpression.h
+++ b/src/sksl/ast/SkSLASTSuffixExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTSUFFIXEXPRESSION
 #define SKSL_ASTSUFFIXEXPRESSION
 
@@ -22,7 +22,7 @@
     , fBase(std::move(base))
     , fSuffix(std::move(suffix)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fBase->description() + fSuffix->description();
     }
 
diff --git a/src/sksl/ast/SkSLASTSwitchCase.h b/src/sksl/ast/SkSLASTSwitchCase.h
index 2c0a01c..405013a 100644
--- a/src/sksl/ast/SkSLASTSwitchCase.h
+++ b/src/sksl/ast/SkSLASTSwitchCase.h
@@ -23,8 +23,8 @@
     , fValue(std::move(value))
     , fStatements(std::move(statements)) {}
 
-    SkString description() const override {
-        SkString result;
+    String description() const override {
+        String result;
         if (fValue) {
             result.appendf("case %s:\n", fValue->description().c_str());
         } else {
diff --git a/src/sksl/ast/SkSLASTSwitchStatement.h b/src/sksl/ast/SkSLASTSwitchStatement.h
index 3031a7d..4a963eb 100644
--- a/src/sksl/ast/SkSLASTSwitchStatement.h
+++ b/src/sksl/ast/SkSLASTSwitchStatement.h
@@ -23,8 +23,8 @@
     , fValue(std::move(value))
     , fCases(std::move(cases)) {}
 
-    SkString description() const override {
-        SkString result = SkStringPrintf("switch (%s) {\n", + fValue->description().c_str());
+    String description() const override {
+        String result = String::printf("switch (%s) {\n", + fValue->description().c_str());
         for (const auto& c : fCases) {
             result += c->description();
         }
diff --git a/src/sksl/ast/SkSLASTTernaryExpression.h b/src/sksl/ast/SkSLASTTernaryExpression.h
index ddf8e3d..07c9297 100644
--- a/src/sksl/ast/SkSLASTTernaryExpression.h
+++ b/src/sksl/ast/SkSLASTTernaryExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTTERNARYEXPRESSION
 #define SKSL_ASTTERNARYEXPRESSION
 
@@ -24,9 +24,9 @@
     , fIfTrue(std::move(ifTrue))
     , fIfFalse(std::move(ifFalse)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "(" + fTest->description() + " ? " + fIfTrue->description() + " : " +
-               fIfFalse->description() + ")";        
+               fIfFalse->description() + ")";
     }
 
     const std::unique_ptr<ASTExpression> fTest;
diff --git a/src/sksl/ast/SkSLASTType.h b/src/sksl/ast/SkSLASTType.h
index b95c3d7..57a8025 100644
--- a/src/sksl/ast/SkSLASTType.h
+++ b/src/sksl/ast/SkSLASTType.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTTYPE
 #define SKSL_ASTTYPE
 
@@ -21,17 +21,17 @@
         kStruct_Kind
     };
 
-    ASTType(Position position, SkString name, Kind kind, std::vector<int> sizes)
+    ASTType(Position position, String name, Kind kind, std::vector<int> sizes)
     : INHERITED(position)
     , fName(std::move(name))
     , fKind(kind)
     , fSizes(std::move(sizes)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fName;
     }
 
-    const SkString fName;
+    const String fName;
 
     const Kind fKind;
 
diff --git a/src/sksl/ast/SkSLASTVarDeclaration.h b/src/sksl/ast/SkSLASTVarDeclaration.h
index 7d50a06..2dcb978 100644
--- a/src/sksl/ast/SkSLASTVarDeclaration.h
+++ b/src/sksl/ast/SkSLASTVarDeclaration.h
@@ -22,15 +22,15 @@
  * instances.
  */
 struct ASTVarDeclaration {
-    ASTVarDeclaration(const SkString name,
+    ASTVarDeclaration(const String name,
                       std::vector<std::unique_ptr<ASTExpression>> sizes,
                       std::unique_ptr<ASTExpression> value)
     : fName(name)
     , fSizes(std::move(sizes))
     , fValue(std::move(value)) {}
 
-    SkString description() const {
-        SkString result = fName;
+    String description() const {
+        String result = fName;
         for (const auto& size : fSizes) {
             if (size) {
                 result += "[" + size->description() + "]";
@@ -44,7 +44,7 @@
         return result;
     }
 
-    SkString fName;
+    String fName;
 
     // array sizes, if any. e.g. 'foo[3][]' has sizes [3, null]
     std::vector<std::unique_ptr<ASTExpression>> fSizes;
@@ -65,9 +65,9 @@
     , fType(std::move(type))
     , fVars(std::move(vars)) {}
 
-    SkString description() const override {
-        SkString result = fModifiers.description() + fType->description() + " ";
-        SkString separator;
+    String description() const override {
+        String result = fModifiers.description() + fType->description() + " ";
+        String separator;
         for (const auto& var : fVars) {
             result += separator;
             separator = ", ";
diff --git a/src/sksl/ast/SkSLASTVarDeclarationStatement.h b/src/sksl/ast/SkSLASTVarDeclarationStatement.h
index d71639d..c3a4069 100644
--- a/src/sksl/ast/SkSLASTVarDeclarationStatement.h
+++ b/src/sksl/ast/SkSLASTVarDeclarationStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTVARDECLARATIONSTATEMENT
 #define SKSL_ASTVARDECLARATIONSTATEMENT
 
@@ -21,7 +21,7 @@
     : INHERITED(decl->fPosition, kVarDeclaration_Kind)
     , fDeclarations(std::move(decl)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fDeclarations->description() + ";";
     }
 
diff --git a/src/sksl/ast/SkSLASTWhileStatement.h b/src/sksl/ast/SkSLASTWhileStatement.h
index 853ac80..e63c502 100644
--- a/src/sksl/ast/SkSLASTWhileStatement.h
+++ b/src/sksl/ast/SkSLASTWhileStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_ASTWHILESTATEMENT
 #define SKSL_ASTWHILESTATEMENT
 
@@ -16,13 +16,13 @@
  * A 'while' statement.
  */
 struct ASTWhileStatement : public ASTStatement {
-    ASTWhileStatement(Position position, std::unique_ptr<ASTExpression> test, 
+    ASTWhileStatement(Position position, std::unique_ptr<ASTExpression> test,
                       std::unique_ptr<ASTStatement> statement)
     : INHERITED(position, kWhile_Kind)
     , fTest(std::move(test))
     , fStatement(std::move(statement)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "while (" + fTest->description() + ") " + fStatement->description();
     }
 
diff --git a/src/sksl/ir/SkSLBinaryExpression.h b/src/sksl/ir/SkSLBinaryExpression.h
index de85e48..73b1829 100644
--- a/src/sksl/ir/SkSLBinaryExpression.h
+++ b/src/sksl/ir/SkSLBinaryExpression.h
@@ -34,7 +34,7 @@
                                         *fRight);
     }
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return "(" + fLeft->description() + " " + Token::OperatorName(fOperator) + " " +
                fRight->description() + ")";
     }
diff --git a/src/sksl/ir/SkSLBlock.h b/src/sksl/ir/SkSLBlock.h
index 17970fd..fe58d44 100644
--- a/src/sksl/ir/SkSLBlock.h
+++ b/src/sksl/ir/SkSLBlock.h
@@ -23,8 +23,8 @@
     , fSymbols(std::move(symbols))
     , fStatements(std::move(statements)) {}
 
-    SkString description() const override {
-        SkString result("{");
+    String description() const override {
+        String result("{");
         for (size_t i = 0; i < fStatements.size(); i++) {
             result += "\n";
             result += fStatements[i]->description();
diff --git a/src/sksl/ir/SkSLBoolLiteral.h b/src/sksl/ir/SkSLBoolLiteral.h
index b372f2f..4e1e050 100644
--- a/src/sksl/ir/SkSLBoolLiteral.h
+++ b/src/sksl/ir/SkSLBoolLiteral.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_BOOLLITERAL
 #define SKSL_BOOLLITERAL
 
@@ -21,8 +21,8 @@
     : INHERITED(position, kBoolLiteral_Kind, *context.fBool_Type)
     , fValue(value) {}
 
-    SkString description() const override {
-        return SkString(fValue ? "true" : "false");
+    String description() const override {
+        return String(fValue ? "true" : "false");
     }
 
     bool isConstant() const override {
diff --git a/src/sksl/ir/SkSLBreakStatement.h b/src/sksl/ir/SkSLBreakStatement.h
index cd633c7..f6edc55 100644
--- a/src/sksl/ir/SkSLBreakStatement.h
+++ b/src/sksl/ir/SkSLBreakStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_BREAKSTATEMENT
 #define SKSL_BREAKSTATEMENT
 
@@ -14,14 +14,14 @@
 namespace SkSL {
 
 /**
- * A 'break' statement. 
+ * A 'break' statement.
  */
 struct BreakStatement : public Statement {
     BreakStatement(Position position)
     : INHERITED(position, kBreak_Kind) {}
 
-    SkString description() const override {
-        return SkString("break;");
+    String description() const override {
+        return String("break;");
     }
 
     typedef Statement INHERITED;
diff --git a/src/sksl/ir/SkSLConstructor.h b/src/sksl/ir/SkSLConstructor.h
index 3360ace..5c647c7 100644
--- a/src/sksl/ir/SkSLConstructor.h
+++ b/src/sksl/ir/SkSLConstructor.h
@@ -44,9 +44,9 @@
         return nullptr;
     }
 
-    SkString description() const override {
-        SkString result = fType.description() + "(";
-        SkString separator;
+    String description() const override {
+        String result = fType.description() + "(";
+        String separator;
         for (size_t i = 0; i < fArguments.size(); i++) {
             result += separator;
             result += fArguments[i]->description();
diff --git a/src/sksl/ir/SkSLContinueStatement.h b/src/sksl/ir/SkSLContinueStatement.h
index b444694..3f5bc1d 100644
--- a/src/sksl/ir/SkSLContinueStatement.h
+++ b/src/sksl/ir/SkSLContinueStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_CONTINUESTATEMENT
 #define SKSL_CONTINUESTATEMENT
 
@@ -14,14 +14,14 @@
 namespace SkSL {
 
 /**
- * A 'continue' statement. 
+ * A 'continue' statement.
  */
 struct ContinueStatement : public Statement {
     ContinueStatement(Position position)
     : INHERITED(position, kContinue_Kind) {}
 
-    SkString description() const override {
-        return SkString("continue;");
+    String description() const override {
+        return String("continue;");
     }
 
     typedef Statement INHERITED;
diff --git a/src/sksl/ir/SkSLDiscardStatement.h b/src/sksl/ir/SkSLDiscardStatement.h
index 3ab6b27..6212466 100644
--- a/src/sksl/ir/SkSLDiscardStatement.h
+++ b/src/sksl/ir/SkSLDiscardStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_DISCARDSTATEMENT
 #define SKSL_DISCARDSTATEMENT
 
@@ -14,14 +14,14 @@
 namespace SkSL {
 
 /**
- * A 'discard' statement. 
+ * A 'discard' statement.
  */
 struct DiscardStatement : public Statement {
     DiscardStatement(Position position)
     : INHERITED(position, kDiscard_Kind) {}
 
-    SkString description() const override {
-        return SkString("discard;");
+    String description() const override {
+        return String("discard;");
     }
 
     typedef Statement INHERITED;
diff --git a/src/sksl/ir/SkSLDoStatement.h b/src/sksl/ir/SkSLDoStatement.h
index e26d3dc..4d3d348 100644
--- a/src/sksl/ir/SkSLDoStatement.h
+++ b/src/sksl/ir/SkSLDoStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_DOSTATEMENT
 #define SKSL_DOSTATEMENT
 
@@ -23,7 +23,7 @@
     , fStatement(std::move(statement))
     , fTest(std::move(test)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "do " + fStatement->description() + " while (" + fTest->description() + ");";
     }
 
diff --git a/src/sksl/ir/SkSLExpressionStatement.h b/src/sksl/ir/SkSLExpressionStatement.h
index 088b1c9..d1ab8e9 100644
--- a/src/sksl/ir/SkSLExpressionStatement.h
+++ b/src/sksl/ir/SkSLExpressionStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_EXPRESSIONSTATEMENT
 #define SKSL_EXPRESSIONSTATEMENT
 
@@ -14,14 +14,14 @@
 namespace SkSL {
 
 /**
- * A lone expression being used as a statement. 
+ * A lone expression being used as a statement.
  */
 struct ExpressionStatement : public Statement {
     ExpressionStatement(std::unique_ptr<Expression> expression)
     : INHERITED(expression->fPosition, kExpression_Kind)
     , fExpression(std::move(expression)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fExpression->description() + ";";
     }
 
diff --git a/src/sksl/ir/SkSLExtension.h b/src/sksl/ir/SkSLExtension.h
index ea5e044..70dc6b3 100644
--- a/src/sksl/ir/SkSLExtension.h
+++ b/src/sksl/ir/SkSLExtension.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_EXTENSION
 #define SKSL_EXTENSION
 
@@ -12,19 +12,19 @@
 
 namespace SkSL {
 
-/** 
- * An extension declaration. 
+/**
+ * An extension declaration.
  */
 struct Extension : public ProgramElement {
-    Extension(Position position, SkString name)
-    : INHERITED(position, kExtension_Kind) 
+    Extension(Position position, String name)
+    : INHERITED(position, kExtension_Kind)
     , fName(std::move(name)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "#extension " + fName + " : enable";
     }
 
-    const SkString fName;
+    const String fName;
 
     typedef ProgramElement INHERITED;
 };
diff --git a/src/sksl/ir/SkSLField.h b/src/sksl/ir/SkSLField.h
index 53d85e0..abea730 100644
--- a/src/sksl/ir/SkSLField.h
+++ b/src/sksl/ir/SkSLField.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FIELD
 #define SKSL_FIELD
 
@@ -16,9 +16,9 @@
 
 namespace SkSL {
 
-/** 
- * A symbol which should be interpreted as a field access. Fields are added to the symboltable 
- * whenever a bare reference to an identifier should refer to a struct field; in GLSL, this is the 
+/**
+ * A symbol which should be interpreted as a field access. Fields are added to the symboltable
+ * whenever a bare reference to an identifier should refer to a struct field; in GLSL, this is the
  * result of declaring anonymous interface blocks.
  */
 struct Field : public Symbol {
@@ -27,7 +27,7 @@
     , fOwner(owner)
     , fFieldIndex(fieldIndex) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return fOwner.description() + "." + fOwner.fType.fields()[fFieldIndex].fName;
     }
 
diff --git a/src/sksl/ir/SkSLFieldAccess.h b/src/sksl/ir/SkSLFieldAccess.h
index de26a3f..eead41c 100644
--- a/src/sksl/ir/SkSLFieldAccess.h
+++ b/src/sksl/ir/SkSLFieldAccess.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FIELDACCESS
 #define SKSL_FIELDACCESS
 
@@ -24,14 +24,14 @@
         kAnonymousInterfaceBlock_OwnerKind
     };
 
-    FieldAccess(std::unique_ptr<Expression> base, int fieldIndex, 
+    FieldAccess(std::unique_ptr<Expression> base, int fieldIndex,
                 OwnerKind ownerKind = kDefault_OwnerKind)
     : INHERITED(base->fPosition, kFieldAccess_Kind, *base->fType.fields()[fieldIndex].fType)
     , fBase(std::move(base))
     , fFieldIndex(fieldIndex)
     , fOwnerKind(ownerKind) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return fBase->description() + "." + fBase->fType.fields()[fFieldIndex].fName;
     }
 
diff --git a/src/sksl/ir/SkSLFloatLiteral.h b/src/sksl/ir/SkSLFloatLiteral.h
index 8a1a5ad..5ed1235 100644
--- a/src/sksl/ir/SkSLFloatLiteral.h
+++ b/src/sksl/ir/SkSLFloatLiteral.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FLOATLITERAL
 #define SKSL_FLOATLITERAL
 
@@ -21,7 +21,7 @@
     : INHERITED(position, kFloatLiteral_Kind, *context.fFloat_Type)
     , fValue(value) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return to_string(fValue);
     }
 
diff --git a/src/sksl/ir/SkSLForStatement.h b/src/sksl/ir/SkSLForStatement.h
index f2bf880..b72c26b 100644
--- a/src/sksl/ir/SkSLForStatement.h
+++ b/src/sksl/ir/SkSLForStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FORSTATEMENT
 #define SKSL_FORSTATEMENT
 
@@ -18,8 +18,8 @@
  * A 'for' statement.
  */
 struct ForStatement : public Statement {
-    ForStatement(Position position, std::unique_ptr<Statement> initializer, 
-                 std::unique_ptr<Expression> test, std::unique_ptr<Expression> next, 
+    ForStatement(Position position, std::unique_ptr<Statement> initializer,
+                 std::unique_ptr<Expression> test, std::unique_ptr<Expression> next,
                  std::unique_ptr<Statement> statement, std::shared_ptr<SymbolTable> symbols)
     : INHERITED(position, kFor_Kind)
     , fSymbols(symbols)
@@ -28,15 +28,15 @@
     , fNext(std::move(next))
     , fStatement(std::move(statement)) {}
 
-    SkString description() const override {
-        SkString result("for (");
+    String description() const override {
+        String result("for (");
         if (fInitializer) {
             result += fInitializer->description();
-        } 
+        }
         result += " ";
         if (fTest) {
             result += fTest->description();
-        } 
+        }
         result += "; ";
         if (fNext) {
             result += fNext->description();
diff --git a/src/sksl/ir/SkSLFunctionCall.h b/src/sksl/ir/SkSLFunctionCall.h
index 1838076..1a5c6fd 100644
--- a/src/sksl/ir/SkSLFunctionCall.h
+++ b/src/sksl/ir/SkSLFunctionCall.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FUNCTIONCALL
 #define SKSL_FUNCTIONCALL
 
@@ -23,9 +23,9 @@
     , fFunction(std::move(function))
     , fArguments(std::move(arguments)) {}
 
-    SkString description() const override {
-        SkString result = fFunction.fName + "(";
-        SkString separator;
+    String description() const override {
+        String result = fFunction.fName + "(";
+        String separator;
         for (size_t i = 0; i < fArguments.size(); i++) {
             result += separator;
             result += fArguments[i]->description();
diff --git a/src/sksl/ir/SkSLFunctionDeclaration.h b/src/sksl/ir/SkSLFunctionDeclaration.h
index c15d2b9..05ba03a 100644
--- a/src/sksl/ir/SkSLFunctionDeclaration.h
+++ b/src/sksl/ir/SkSLFunctionDeclaration.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FUNCTIONDECLARATION
 #define SKSL_FUNCTIONDECLARATION
 
@@ -21,7 +21,7 @@
  * A function declaration (not a definition -- does not contain a body).
  */
 struct FunctionDeclaration : public Symbol {
-    FunctionDeclaration(Position position, SkString name, 
+    FunctionDeclaration(Position position, String name,
                         std::vector<const Variable*> parameters, const Type& returnType)
     : INHERITED(position, kFunctionDeclaration_Kind, std::move(name))
     , fDefined(false)
@@ -29,9 +29,9 @@
     , fParameters(std::move(parameters))
     , fReturnType(returnType) {}
 
-    SkString description() const override {
-        SkString result = fReturnType.description() + " " + fName + "(";
-        SkString separator;
+    String description() const override {
+        String result = fReturnType.description() + " " + fName + "(";
+        String separator;
         for (auto p : fParameters) {
             result += separator;
             separator = ", ";
@@ -58,7 +58,7 @@
 
     /**
      * Determine the effective types of this function's parameters and return value when called with
-     * the given arguments. This is relevant for functions with generic parameter types, where this 
+     * the given arguments. This is relevant for functions with generic parameter types, where this
      * will collapse the generic types down into specific concrete types.
      *
      * Returns true if it was able to select a concrete set of types for the generic function, false
diff --git a/src/sksl/ir/SkSLFunctionDefinition.h b/src/sksl/ir/SkSLFunctionDefinition.h
index bae8825..e87ee63 100644
--- a/src/sksl/ir/SkSLFunctionDefinition.h
+++ b/src/sksl/ir/SkSLFunctionDefinition.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FUNCTIONDEFINITION
 #define SKSL_FUNCTIONDEFINITION
 
@@ -18,13 +18,13 @@
  * A function definition (a declaration plus an associated block of code).
  */
 struct FunctionDefinition : public ProgramElement {
-    FunctionDefinition(Position position, const FunctionDeclaration& declaration, 
+    FunctionDefinition(Position position, const FunctionDeclaration& declaration,
                        std::unique_ptr<Block> body)
     : INHERITED(position, kFunction_Kind)
     , fDeclaration(declaration)
     , fBody(std::move(body)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fDeclaration.description() + " " + fBody->description();
     }
 
diff --git a/src/sksl/ir/SkSLFunctionReference.h b/src/sksl/ir/SkSLFunctionReference.h
index e95833d..49ddf83 100644
--- a/src/sksl/ir/SkSLFunctionReference.h
+++ b/src/sksl/ir/SkSLFunctionReference.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_FUNCTIONREFERENCE
 #define SKSL_FUNCTIONREFERENCE
 
@@ -15,18 +15,18 @@
 namespace SkSL {
 
 /**
- * An identifier referring to a function name. This is an intermediate value: FunctionReferences are 
+ * An identifier referring to a function name. This is an intermediate value: FunctionReferences are
  * always eventually replaced by FunctionCalls in valid programs.
  */
 struct FunctionReference : public Expression {
-    FunctionReference(const Context& context, Position position, 
+    FunctionReference(const Context& context, Position position,
                       std::vector<const FunctionDeclaration*> function)
     : INHERITED(position, kFunctionReference_Kind, *context.fInvalid_Type)
     , fFunctions(function) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         ASSERT(false);
-        return SkString("<function>");
+        return String("<function>");
     }
 
     const std::vector<const FunctionDeclaration*> fFunctions;
diff --git a/src/sksl/ir/SkSLIRNode.h b/src/sksl/ir/SkSLIRNode.h
index 9a04cdd..139be32 100644
--- a/src/sksl/ir/SkSLIRNode.h
+++ b/src/sksl/ir/SkSLIRNode.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_IRNODE
 #define SKSL_IRNODE
 
@@ -13,7 +13,7 @@
 namespace SkSL {
 
 /**
- * Represents a node in the intermediate representation (IR) tree. The IR is a fully-resolved 
+ * Represents a node in the intermediate representation (IR) tree. The IR is a fully-resolved
  * version of the program (all types determined, everything validated), ready for code generation.
  */
 struct IRNode {
@@ -22,7 +22,7 @@
 
     virtual ~IRNode() {}
 
-    virtual SkString description() const = 0;
+    virtual String description() const = 0;
 
     const Position fPosition;
 };
diff --git a/src/sksl/ir/SkSLIfStatement.h b/src/sksl/ir/SkSLIfStatement.h
index 8667e93..a7e0aad 100644
--- a/src/sksl/ir/SkSLIfStatement.h
+++ b/src/sksl/ir/SkSLIfStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_IFSTATEMENT
 #define SKSL_IFSTATEMENT
 
@@ -17,15 +17,15 @@
  * An 'if' statement.
  */
 struct IfStatement : public Statement {
-    IfStatement(Position position, std::unique_ptr<Expression> test, 
+    IfStatement(Position position, std::unique_ptr<Expression> test,
                 std::unique_ptr<Statement> ifTrue, std::unique_ptr<Statement> ifFalse)
     : INHERITED(position, kIf_Kind)
     , fTest(std::move(test))
     , fIfTrue(std::move(ifTrue))
     , fIfFalse(std::move(ifFalse)) {}
 
-    SkString description() const override {
-        SkString result = "if (" + fTest->description() + ") " + fIfTrue->description();
+    String description() const override {
+        String result = "if (" + fTest->description() + ") " + fIfTrue->description();
         if (fIfFalse) {
             result += " else " + fIfFalse->description();
         }
diff --git a/src/sksl/ir/SkSLIndexExpression.h b/src/sksl/ir/SkSLIndexExpression.h
index d255c7d..68823bf 100644
--- a/src/sksl/ir/SkSLIndexExpression.h
+++ b/src/sksl/ir/SkSLIndexExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_INDEX
 #define SKSL_INDEX
 
@@ -43,7 +43,7 @@
  * An expression which extracts a value from an array or matrix, as in 'm[2]'.
  */
 struct IndexExpression : public Expression {
-    IndexExpression(const Context& context, std::unique_ptr<Expression> base, 
+    IndexExpression(const Context& context, std::unique_ptr<Expression> base,
                     std::unique_ptr<Expression> index)
     : INHERITED(base->fPosition, kIndex_Kind, index_type(context, base->fType))
     , fBase(std::move(base))
@@ -51,7 +51,7 @@
         ASSERT(fIndex->fType == *context.fInt_Type || fIndex->fType == *context.fUInt_Type);
     }
 
-    SkString description() const override {
+    String description() const override {
         return fBase->description() + "[" + fIndex->description() + "]";
     }
 
diff --git a/src/sksl/ir/SkSLIntLiteral.h b/src/sksl/ir/SkSLIntLiteral.h
index b6a23d6..2322a3d 100644
--- a/src/sksl/ir/SkSLIntLiteral.h
+++ b/src/sksl/ir/SkSLIntLiteral.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_INTLITERAL
 #define SKSL_INTLITERAL
 
@@ -23,7 +23,7 @@
     : INHERITED(position, kIntLiteral_Kind, type ? *type : *context.fInt_Type)
     , fValue(value) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return to_string(fValue);
     }
 
diff --git a/src/sksl/ir/SkSLInterfaceBlock.h b/src/sksl/ir/SkSLInterfaceBlock.h
index 0ec33e3..fc6ccec 100644
--- a/src/sksl/ir/SkSLInterfaceBlock.h
+++ b/src/sksl/ir/SkSLInterfaceBlock.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_INTERFACEBLOCK
 #define SKSL_INTERFACEBLOCK
 
@@ -25,7 +25,7 @@
  * At the IR level, this is represented by a single variable of struct type.
  */
 struct InterfaceBlock : public ProgramElement {
-    InterfaceBlock(Position position, const Variable* var, SkString typeName, SkString instanceName,
+    InterfaceBlock(Position position, const Variable* var, String typeName, String instanceName,
                    std::vector<std::unique_ptr<Expression>> sizes,
                    std::shared_ptr<SymbolTable> typeOwner)
     : INHERITED(position, kInterfaceBlock_Kind)
@@ -35,8 +35,8 @@
     , fSizes(std::move(sizes))
     , fTypeOwner(typeOwner) {}
 
-    SkString description() const override {
-        SkString result = fVariable.fModifiers.description() + fTypeName + " {\n";
+    String description() const override {
+        String result = fVariable.fModifiers.description() + fTypeName + " {\n";
         const Type* structType = &fVariable.fType;
         while (structType->kind() == Type::kArray_Kind) {
             structType = &structType->componentType();
@@ -59,8 +59,8 @@
     }
 
     const Variable& fVariable;
-    const SkString fTypeName;
-    const SkString fInstanceName;
+    const String fTypeName;
+    const String fInstanceName;
     const std::vector<std::unique_ptr<Expression>> fSizes;
     const std::shared_ptr<SymbolTable> fTypeOwner;
 
diff --git a/src/sksl/ir/SkSLLayout.h b/src/sksl/ir/SkSLLayout.h
index 5e7ec44..3a8416ac 100644
--- a/src/sksl/ir/SkSLLayout.h
+++ b/src/sksl/ir/SkSLLayout.h
@@ -8,7 +8,6 @@
 #ifndef SKSL_LAYOUT
 #define SKSL_LAYOUT
 
-#include "SkString.h"
 #include "SkSLUtil.h"
 
 namespace SkSL {
@@ -55,11 +54,11 @@
             case Format::kRGBA8I:       return "rgba8i";
             case Format::kR8I:          return "r8i";
         }
-        SkFAIL("Unexpected format");
+        ABORT("Unexpected format");
         return "";
     }
 
-    static bool ReadFormat(SkString str, Format* format) {
+    static bool ReadFormat(String str, Format* format) {
         if (str == "rgba32f") {
             *format = Format::kRGBA32F;
             return true;
@@ -125,9 +124,9 @@
     , fMaxVertices(-1)
     , fInvocations(-1) {}
 
-    SkString description() const {
-        SkString result;
-        SkString separator;
+    String description() const {
+        String result;
+        String separator;
         if (fLocation >= 0) {
             result += separator + "location = " + to_string(fLocation);
             separator = ", ";
diff --git a/src/sksl/ir/SkSLModifiers.h b/src/sksl/ir/SkSLModifiers.h
index c7a5639..9fae5b0 100644
--- a/src/sksl/ir/SkSLModifiers.h
+++ b/src/sksl/ir/SkSLModifiers.h
@@ -42,8 +42,8 @@
     : fLayout(layout)
     , fFlags(flags) {}
 
-    SkString description() const {
-        SkString result = fLayout.description();
+    String description() const {
+        String result = fLayout.description();
         if (fFlags & kUniform_Flag) {
             result += "uniform ";
         }
diff --git a/src/sksl/ir/SkSLModifiersDeclaration.h b/src/sksl/ir/SkSLModifiersDeclaration.h
index 625954d..a0ce748 100644
--- a/src/sksl/ir/SkSLModifiersDeclaration.h
+++ b/src/sksl/ir/SkSLModifiersDeclaration.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_MODIFIERDECLARATION
 #define SKSL_MODIFIERDECLARATION
 
@@ -23,7 +23,7 @@
     : INHERITED(Position(), kModifiers_Kind)
     , fModifiers(modifiers) {}
 
-    SkString description() const {
+    String description() const {
         return fModifiers.description() + ";";
     }
 
diff --git a/src/sksl/ir/SkSLPostfixExpression.h b/src/sksl/ir/SkSLPostfixExpression.h
index 05ff167..2c84af7 100644
--- a/src/sksl/ir/SkSLPostfixExpression.h
+++ b/src/sksl/ir/SkSLPostfixExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_POSTFIXEXPRESSION
 #define SKSL_POSTFIXEXPRESSION
 
@@ -22,7 +22,7 @@
     , fOperand(std::move(operand))
     , fOperator(op) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return fOperand->description() + Token::OperatorName(fOperator);
     }
 
diff --git a/src/sksl/ir/SkSLPrefixExpression.h b/src/sksl/ir/SkSLPrefixExpression.h
index dafe1e9..4fa54ca 100644
--- a/src/sksl/ir/SkSLPrefixExpression.h
+++ b/src/sksl/ir/SkSLPrefixExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_PREFIXEXPRESSION
 #define SKSL_PREFIXEXPRESSION
 
@@ -22,7 +22,7 @@
     , fOperand(std::move(operand))
     , fOperator(op) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return Token::OperatorName(fOperator) + fOperand->description();
     }
 
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index 2ca9372..96bd5c4 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -26,7 +26,11 @@
  */
 struct Program {
     struct Settings {
+#ifdef SKSL_STANDALONE
+        const StandaloneShaderCaps* fCaps = &standaloneCaps;
+#else
         const GrShaderCaps* fCaps = nullptr;
+#endif
         // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate
         // must be flipped.
         bool fFlipY = false;
diff --git a/src/sksl/ir/SkSLProgramElement.h b/src/sksl/ir/SkSLProgramElement.h
index 2f1ce77..ebb4e9a 100644
--- a/src/sksl/ir/SkSLProgramElement.h
+++ b/src/sksl/ir/SkSLProgramElement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_PROGRAMELEMENT
 #define SKSL_PROGRAMELEMENT
 
diff --git a/src/sksl/ir/SkSLReturnStatement.h b/src/sksl/ir/SkSLReturnStatement.h
index dc5ec9a..841db94 100644
--- a/src/sksl/ir/SkSLReturnStatement.h
+++ b/src/sksl/ir/SkSLReturnStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_RETURNSTATEMENT
 #define SKSL_RETURNSTATEMENT
 
@@ -21,14 +21,14 @@
     : INHERITED(position, kReturn_Kind) {}
 
     ReturnStatement(std::unique_ptr<Expression> expression)
-    : INHERITED(expression->fPosition, kReturn_Kind) 
+    : INHERITED(expression->fPosition, kReturn_Kind)
     , fExpression(std::move(expression)) {}
 
-    SkString description() const override {
+    String description() const override {
         if (fExpression) {
             return "return " + fExpression->description() + ";";
         } else {
-            return SkString("return;");
+            return String("return;");
         }
     }
 
diff --git a/src/sksl/ir/SkSLStatement.h b/src/sksl/ir/SkSLStatement.h
index c3a6f95..ba1a087 100644
--- a/src/sksl/ir/SkSLStatement.h
+++ b/src/sksl/ir/SkSLStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_STATEMENT
 #define SKSL_STATEMENT
 
diff --git a/src/sksl/ir/SkSLSwitchCase.h b/src/sksl/ir/SkSLSwitchCase.h
index 1fc2e85..8043f2e 100644
--- a/src/sksl/ir/SkSLSwitchCase.h
+++ b/src/sksl/ir/SkSLSwitchCase.h
@@ -23,8 +23,8 @@
     , fValue(std::move(value))
     , fStatements(std::move(statements)) {}
 
-    SkString description() const override {
-        SkString result;
+    String description() const override {
+        String result;
         if (fValue) {
             result.appendf("case %s:\n", fValue->description().c_str());
         } else {
diff --git a/src/sksl/ir/SkSLSwitchStatement.h b/src/sksl/ir/SkSLSwitchStatement.h
index 31765c4..88e1e70 100644
--- a/src/sksl/ir/SkSLSwitchStatement.h
+++ b/src/sksl/ir/SkSLSwitchStatement.h
@@ -23,8 +23,8 @@
     , fValue(std::move(value))
     , fCases(std::move(cases)) {}
 
-    SkString description() const override {
-        SkString result = SkStringPrintf("switch (%s) {\n", + fValue->description().c_str());
+    String description() const override {
+        String result = String::printf("switch (%s) {\n", + fValue->description().c_str());
         for (const auto& c : fCases) {
             result += c->description();
         }
diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h
index 0803f3b..1725ec2 100644
--- a/src/sksl/ir/SkSLSwizzle.h
+++ b/src/sksl/ir/SkSLSwizzle.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_SWIZZLE
 #define SKSL_SWIZZLE
 
@@ -15,7 +15,7 @@
 namespace SkSL {
 
 /**
- * Given a type and a swizzle component count, returns the type that will result from swizzling. For 
+ * Given a type and a swizzle component count, returns the type that will result from swizzling. For
  * instance, swizzling a vec3 with two components will result in a vec2. It is possible to swizzle
  * with more components than the source vector, as in 'vec2(1).xxxx'.
  */
@@ -69,8 +69,8 @@
         ASSERT(fComponents.size() >= 1 && fComponents.size() <= 4);
     }
 
-    SkString description() const override {
-        SkString result = fBase->description() + ".";
+    String description() const override {
+        String result = fBase->description() + ".";
         for (int x : fComponents) {
             result += "xyzw"[x];
         }
diff --git a/src/sksl/ir/SkSLSymbol.h b/src/sksl/ir/SkSLSymbol.h
index 10dcaf9..e883ea7 100644
--- a/src/sksl/ir/SkSLSymbol.h
+++ b/src/sksl/ir/SkSLSymbol.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_SYMBOL
 #define SKSL_SYMBOL
 
@@ -24,13 +24,13 @@
         kField_Kind
     };
 
-    Symbol(Position position, Kind kind, SkString name)
+    Symbol(Position position, Kind kind, String name)
     : INHERITED(position)
     , fKind(kind)
     , fName(std::move(name)) {}
 
     const Kind fKind;
-    const SkString fName;
+    const String fName;
 
     typedef IRNode INHERITED;
 };
diff --git a/src/sksl/ir/SkSLSymbolTable.cpp b/src/sksl/ir/SkSLSymbolTable.cpp
index 3ceeab9..4d39e8b 100644
--- a/src/sksl/ir/SkSLSymbolTable.cpp
+++ b/src/sksl/ir/SkSLSymbolTable.cpp
@@ -21,7 +21,7 @@
     }
 }
 
-const Symbol* SymbolTable::operator[](const SkString& name) {
+const Symbol* SymbolTable::operator[](const String& name) {
     const auto& entry = fSymbols.find(name);
     if (entry == fSymbols.end()) {
         if (fParent) {
@@ -64,12 +64,12 @@
     return s;
 }
 
-void SymbolTable::add(const SkString& name, std::unique_ptr<Symbol> symbol) {
+void SymbolTable::add(const String& name, std::unique_ptr<Symbol> symbol) {
     this->addWithoutOwnership(name, symbol.get());
     fOwnedPointers.push_back(std::move(symbol));
 }
 
-void SymbolTable::addWithoutOwnership(const SkString& name, const Symbol* symbol) {
+void SymbolTable::addWithoutOwnership(const String& name, const Symbol* symbol) {
     const auto& existing = fSymbols.find(name);
     if (existing == fSymbols.end()) {
         fSymbols[name] = symbol;
diff --git a/src/sksl/ir/SkSLSymbolTable.h b/src/sksl/ir/SkSLSymbolTable.h
index 948a447..6bafef2 100644
--- a/src/sksl/ir/SkSLSymbolTable.h
+++ b/src/sksl/ir/SkSLSymbolTable.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_SYMBOLTABLE
 #define SKSL_SYMBOLTABLE
 
@@ -31,11 +31,11 @@
     : fParent(parent)
     , fErrorReporter(*errorReporter) {}
 
-    const Symbol* operator[](const SkString& name);
+    const Symbol* operator[](const String& name);
 
-    void add(const SkString& name, std::unique_ptr<Symbol> symbol);
+    void add(const String& name, std::unique_ptr<Symbol> symbol);
 
-    void addWithoutOwnership(const SkString& name, const Symbol* symbol);
+    void addWithoutOwnership(const String& name, const Symbol* symbol);
 
     Symbol* takeOwnership(Symbol* s);
 
@@ -48,7 +48,7 @@
 
     std::vector<std::unique_ptr<Symbol>> fOwnedPointers;
 
-    std::unordered_map<SkString, const Symbol*> fSymbols;
+    std::unordered_map<String, const Symbol*> fSymbols;
 
     ErrorReporter& fErrorReporter;
 };
diff --git a/src/sksl/ir/SkSLTernaryExpression.h b/src/sksl/ir/SkSLTernaryExpression.h
index 0275004..9fbac19 100644
--- a/src/sksl/ir/SkSLTernaryExpression.h
+++ b/src/sksl/ir/SkSLTernaryExpression.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_TERNARYEXPRESSION
 #define SKSL_TERNARYEXPRESSION
 
@@ -26,8 +26,8 @@
         ASSERT(fIfTrue->fType == fIfFalse->fType);
     }
 
-    SkString description() const override {
-        return "(" + fTest->description() + " ? " + fIfTrue->description() + " : " + 
+    String description() const override {
+        return "(" + fTest->description() + " ? " + fIfTrue->description() + " : " +
                fIfFalse->description() + ")";
     }
 
diff --git a/src/sksl/ir/SkSLType.cpp b/src/sksl/ir/SkSLType.cpp
index d28c4f0..c919cbc 100644
--- a/src/sksl/ir/SkSLType.cpp
+++ b/src/sksl/ir/SkSLType.cpp
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #include "SkSLType.h"
 #include "SkSLContext.h"
 
@@ -22,7 +22,7 @@
         return false;
     }
     if (this->kind() == kMatrix_Kind) {
-        if (this->columns() == other.columns() && 
+        if (this->columns() == other.columns() &&
             this->rows() == other.rows()) {
             return this->componentType().determineCoercionCost(other.componentType(), outCost);
         }
diff --git a/src/sksl/ir/SkSLType.h b/src/sksl/ir/SkSLType.h
index 2f98e53..44bc262 100644
--- a/src/sksl/ir/SkSLType.h
+++ b/src/sksl/ir/SkSLType.h
@@ -26,17 +26,17 @@
 class Type : public Symbol {
 public:
     struct Field {
-        Field(Modifiers modifiers, SkString name, const Type* type)
+        Field(Modifiers modifiers, String name, const Type* type)
         : fModifiers(modifiers)
         , fName(std::move(name))
         , fType(std::move(type)) {}
 
-        const SkString description() const {
+        const String description() const {
             return fType->description() + " " + fName + ";";
         }
 
         Modifiers fModifiers;
-        SkString fName;
+        String fName;
         const Type* fType;
     };
 
@@ -53,24 +53,24 @@
 
     // Create an "other" (special) type with the given name. These types cannot be directly
     // referenced from user code.
-    Type(SkString name)
+    Type(String name)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kOther_Kind) {}
 
     // Create a generic type which maps to the listed types.
-    Type(SkString name, std::vector<const Type*> types)
+    Type(String name, std::vector<const Type*> types)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kGeneric_Kind)
     , fCoercibleTypes(std::move(types)) {}
 
     // Create a struct type with the given fields.
-    Type(Position position, SkString name, std::vector<Field> fields)
+    Type(Position position, String name, std::vector<Field> fields)
     : INHERITED(position, kType_Kind, std::move(name))
     , fTypeKind(kStruct_Kind)
     , fFields(std::move(fields)) {}
 
     // Create a scalar type.
-    Type(SkString name, bool isNumber)
+    Type(String name, bool isNumber)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kScalar_Kind)
     , fIsNumber(isNumber)
@@ -78,7 +78,7 @@
     , fRows(1) {}
 
     // Create a scalar type which can be coerced to the listed types.
-    Type(SkString name, bool isNumber, std::vector<const Type*> coercibleTypes)
+    Type(String name, bool isNumber, std::vector<const Type*> coercibleTypes)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kScalar_Kind)
     , fIsNumber(isNumber)
@@ -87,11 +87,11 @@
     , fRows(1) {}
 
     // Create a vector type.
-    Type(SkString name, const Type& componentType, int columns)
+    Type(String name, const Type& componentType, int columns)
     : Type(name, kVector_Kind, componentType, columns) {}
 
     // Create a vector or array type.
-    Type(SkString name, Kind kind, const Type& componentType, int columns)
+    Type(String name, Kind kind, const Type& componentType, int columns)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kind)
     , fComponentType(&componentType)
@@ -100,7 +100,7 @@
     , fDimensions(SpvDim1D) {}
 
     // Create a matrix type.
-    Type(SkString name, const Type& componentType, int columns, int rows)
+    Type(String name, const Type& componentType, int columns, int rows)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kMatrix_Kind)
     , fComponentType(&componentType)
@@ -109,7 +109,7 @@
     , fDimensions(SpvDim1D) {}
 
     // Create a sampler type.
-    Type(SkString name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled,
+    Type(String name, SpvDim_ dimensions, bool isDepth, bool isArrayed, bool isMultisampled,
          bool isSampled)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kSampler_Kind)
@@ -119,11 +119,11 @@
     , fIsMultisampled(isMultisampled)
     , fIsSampled(isSampled) {}
 
-    SkString name() const {
+    String name() const {
         return fName;
     }
 
-    SkString description() const override {
+    String description() const override {
         return fName;
     }
 
diff --git a/src/sksl/ir/SkSLTypeReference.h b/src/sksl/ir/SkSLTypeReference.h
index 1c6f16c..b12c185 100644
--- a/src/sksl/ir/SkSLTypeReference.h
+++ b/src/sksl/ir/SkSLTypeReference.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_TYPEREFERENCE
 #define SKSL_TYPEREFERENCE
 
@@ -14,7 +14,7 @@
 namespace SkSL {
 
 /**
- * Represents an identifier referring to a type. This is an intermediate value: TypeReferences are 
+ * Represents an identifier referring to a type. This is an intermediate value: TypeReferences are
  * always eventually replaced by Constructors in valid programs.
  */
 struct TypeReference : public Expression {
@@ -22,7 +22,7 @@
     : INHERITED(position, kTypeReference_Kind, *context.fInvalid_Type)
     , fValue(type) {}
 
-    SkString description() const override {
+    String description() const override {
         return fValue.name();
     }
 
diff --git a/src/sksl/ir/SkSLUnresolvedFunction.h b/src/sksl/ir/SkSLUnresolvedFunction.h
index 76741cf..c5fdbd0 100644
--- a/src/sksl/ir/SkSLUnresolvedFunction.h
+++ b/src/sksl/ir/SkSLUnresolvedFunction.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_UNRESOLVEDFUNCTION
 #define SKSL_UNRESOLVEDFUNCTION
 
@@ -26,7 +26,7 @@
 #endif
     }
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return fName;
     }
 
diff --git a/src/sksl/ir/SkSLVarDeclarations.h b/src/sksl/ir/SkSLVarDeclarations.h
index 5781230..5a006bd 100644
--- a/src/sksl/ir/SkSLVarDeclarations.h
+++ b/src/sksl/ir/SkSLVarDeclarations.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_VARDECLARATIONS
 #define SKSL_VARDECLARATIONS
 
@@ -17,7 +17,7 @@
 
 /**
  * A single variable declaration within a var declaration statement. For instance, the statement
- * 'int x = 2, y[3];' is a VarDeclarations statement containing two individual VarDeclaration 
+ * 'int x = 2, y[3];' is a VarDeclarations statement containing two individual VarDeclaration
  * instances.
  */
 struct VarDeclaration {
@@ -28,8 +28,8 @@
     , fSizes(std::move(sizes))
     , fValue(std::move(value)) {}
 
-    SkString description() const {
-        SkString result = fVar->fName;
+    String description() const {
+        String result = fVar->fName;
         for (const auto& size : fSizes) {
             if (size) {
                 result += "[" + size->description() + "]";
@@ -40,7 +40,7 @@
         if (fValue) {
             result += " = " + fValue->description();
         }
-        return result;        
+        return result;
     }
 
     const Variable* fVar;
@@ -52,18 +52,18 @@
  * A variable declaration statement, which may consist of one or more individual variables.
  */
 struct VarDeclarations : public ProgramElement {
-    VarDeclarations(Position position, const Type* baseType, 
+    VarDeclarations(Position position, const Type* baseType,
                     std::vector<VarDeclaration> vars)
     : INHERITED(position, kVar_Kind)
     , fBaseType(*baseType)
     , fVars(std::move(vars)) {}
 
-    SkString description() const override {
+    String description() const override {
         if (!fVars.size()) {
-            return SkString();
+            return String();
         }
-        SkString result = fVars[0].fVar->fModifiers.description() + fBaseType.description() + " ";
-        SkString separator;
+        String result = fVars[0].fVar->fModifiers.description() + fBaseType.description() + " ";
+        String separator;
         for (const auto& var : fVars) {
             result += separator;
             separator = ", ";
diff --git a/src/sksl/ir/SkSLVarDeclarationsStatement.h b/src/sksl/ir/SkSLVarDeclarationsStatement.h
index 66b570f..50365de 100644
--- a/src/sksl/ir/SkSLVarDeclarationsStatement.h
+++ b/src/sksl/ir/SkSLVarDeclarationsStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_VARDECLARATIONSSTATEMENT
 #define SKSL_VARDECLARATIONSSTATEMENT
 
@@ -21,7 +21,7 @@
     : INHERITED(decl->fPosition, kVarDeclarations_Kind)
     , fDeclaration(std::move(decl)) {}
 
-    SkString description() const override {
+    String description() const override {
         return fDeclaration->description();
     }
 
diff --git a/src/sksl/ir/SkSLVariable.h b/src/sksl/ir/SkSLVariable.h
index 2c3391d..21f17ba 100644
--- a/src/sksl/ir/SkSLVariable.h
+++ b/src/sksl/ir/SkSLVariable.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_VARIABLE
 #define SKSL_VARIABLE
 
@@ -27,7 +27,7 @@
         kParameter_Storage
     };
 
-    Variable(Position position, Modifiers modifiers, SkString name, const Type& type,
+    Variable(Position position, Modifiers modifiers, String name, const Type& type,
              Storage storage)
     : INHERITED(position, kVariable_Kind, std::move(name))
     , fModifiers(modifiers)
@@ -36,7 +36,7 @@
     , fReadCount(0)
     , fWriteCount(0) {}
 
-    virtual SkString description() const override {
+    virtual String description() const override {
         return fModifiers.description() + fType.fName + " " + fName;
     }
 
diff --git a/src/sksl/ir/SkSLVariableReference.h b/src/sksl/ir/SkSLVariableReference.h
index 7d90511..af181f8 100644
--- a/src/sksl/ir/SkSLVariableReference.h
+++ b/src/sksl/ir/SkSLVariableReference.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_VARIABLEREFERENCE
 #define SKSL_VARIABLEREFERENCE
 
@@ -67,7 +67,7 @@
         fRefKind = refKind;
     }
 
-    SkString description() const override {
+    String description() const override {
         return fVariable.fName;
     }
 
diff --git a/src/sksl/ir/SkSLWhileStatement.h b/src/sksl/ir/SkSLWhileStatement.h
index a741a04..c35d6df 100644
--- a/src/sksl/ir/SkSLWhileStatement.h
+++ b/src/sksl/ir/SkSLWhileStatement.h
@@ -4,7 +4,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
- 
+
 #ifndef SKSL_WHILESTATEMENT
 #define SKSL_WHILESTATEMENT
 
@@ -17,13 +17,13 @@
  * A 'while' loop.
  */
 struct WhileStatement : public Statement {
-    WhileStatement(Position position, std::unique_ptr<Expression> test, 
+    WhileStatement(Position position, std::unique_ptr<Expression> test,
                    std::unique_ptr<Statement> statement)
     : INHERITED(position, kWhile_Kind)
     , fTest(std::move(test))
     , fStatement(std::move(statement)) {}
 
-    SkString description() const override {
+    String description() const override {
         return "while (" + fTest->description() + ") " + fStatement->description();
     }
 
diff --git a/tests/SkSLErrorTest.cpp b/tests/SkSLErrorTest.cpp
index bde5e70..bd0c64a 100644
--- a/tests/SkSLErrorTest.cpp
+++ b/tests/SkSLErrorTest.cpp
@@ -13,17 +13,16 @@
 
 static void test_failure(skiatest::Reporter* r, const char* src, const char* error) {
     SkSL::Compiler compiler;
-    SkDynamicMemoryWStream out;
     SkSL::Program::Settings settings;
     sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
     settings.fCaps = caps.get();
     std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
                                                                      SkString(src), settings);
     if (program) {
-        SkString ignored;
+        SkSL::String ignored;
         compiler.toSPIRV(*program, &ignored);
     }
-    SkString skError(error);
+    SkSL::String skError(error);
     if (compiler.errorText() != skError) {
         SkDebugf("SKSL ERROR:\n    source: %s\n    expected: %s    received: %s", src, error,
                  compiler.errorText().c_str());
@@ -33,14 +32,13 @@
 
 static void test_success(skiatest::Reporter* r, const char* src) {
     SkSL::Compiler compiler;
-    SkDynamicMemoryWStream out;
     SkSL::Program::Settings settings;
     sk_sp<GrShaderCaps> caps = SkSL::ShaderCapsFactory::Default();
     settings.fCaps = caps.get();
     std::unique_ptr<SkSL::Program> program = compiler.convertProgram(SkSL::Program::kFragment_Kind,
                                                                      SkString(src), settings);
     REPORTER_ASSERT(r, program);
-    SkString ignored;
+    SkSL::String ignored;
     REPORTER_ASSERT(r, compiler.toSPIRV(*program, &ignored));
 }
 
diff --git a/tests/SkSLGLSLTest.cpp b/tests/SkSLGLSLTest.cpp
index 53e5c6b..efae336 100644
--- a/tests/SkSLGLSLTest.cpp
+++ b/tests/SkSLGLSLTest.cpp
@@ -15,7 +15,7 @@
                  const char* expected, SkSL::Program::Inputs* inputs,
                  SkSL::Program::Kind kind = SkSL::Program::kFragment_Kind) {
     SkSL::Compiler compiler;
-    SkString output;
+    SkSL::String output;
     std::unique_ptr<SkSL::Program> program = compiler.convertProgram(kind, SkString(src), settings);
     if (!program) {
         SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
@@ -24,7 +24,7 @@
     *inputs = program->fInputs;
     REPORTER_ASSERT(r, compiler.toGLSL(*program, &output));
     if (program) {
-        SkString skExpected(expected);
+        SkSL::String skExpected(expected);
         if (output != skExpected) {
             SkDebugf("GLSL MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
                      expected, output.c_str());