This cl moves color and coverage off of drawstate.  In an effort to keep this CL manageable, I have left the compute invariant input / output in a bit of a strange state(fixing this will be complicated).

In addition, NVPR makes this very complicated, and I haven't quite figured out a good way to handle it, so for now color and coverage DO live on optstate, but I will figure out some way to refactor that in future CLs.

BUG=skia:

Review URL: https://codereview.chromium.org/783763002
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index f875607..6f19ac9 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -92,7 +92,7 @@
                         continue;
                     }
                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
-                    gp.reset(GrCubicEffect::Create(et, *tt.target()->caps()));
+                    gp.reset(GrCubicEffect::Create(0xff000000, et, *tt.target()->caps()));
                     if (!gp) {
                         continue;
                     }
@@ -166,7 +166,6 @@
 
                     ds.setGeometryProcessor(gp);
                     ds.setRenderTarget(rt);
-                    ds.setColor(0xff000000);
 
                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
                     tt.target()->drawIndexed(&ds, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
@@ -252,7 +251,7 @@
                         continue;
                     }
                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
-                    gp.reset(GrConicEffect::Create(et, *tt.target()->caps()));
+                    gp.reset(GrConicEffect::Create(0xff000000, et, *tt.target()->caps()));
                     if (!gp) {
                         continue;
                     }
@@ -323,7 +322,6 @@
 
                     ds.setGeometryProcessor(gp);
                     ds.setRenderTarget(rt);
-                    ds.setColor(0xff000000);
 
                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
                     tt.target()->drawIndexed(&ds, kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
@@ -443,7 +441,7 @@
                         continue;
                     }
                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
-                    gp.reset(GrQuadEffect::Create(et, *tt.target()->caps()));
+                    gp.reset(GrQuadEffect::Create(0xff000000, et, *tt.target()->caps()));
                     if (!gp) {
                         continue;
                     }
@@ -509,7 +507,6 @@
 
                     ds.setGeometryProcessor(gp);
                     ds.setRenderTarget(rt);
-                    ds.setColor(0xff000000);
 
                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
                     tt.target()->drawIndexed(&ds, kTriangles_GrPrimitiveType, 0, 0, 4, 6);
diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index 1e5c601..365660d 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -133,12 +133,11 @@
                 }
 
                 GrDrawState ds;
-                const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create();
+                const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(0xff000000);
                 ds.setGeometryProcessor(gp)->unref();
                 ds.addCoverageProcessor(fp);
                 ds.setIdentityViewMatrix();
                 ds.setRenderTarget(rt);
-                ds.setColor(0xff000000);
 
                 GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, gp->getVertexStride(), 0);
                 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
@@ -191,12 +190,11 @@
                 }
 
                 GrDrawState ds;
-                const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create();
+                const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(0xff000000);
                 ds.setGeometryProcessor(gp)->unref();
                 ds.addCoverageProcessor(fp);
                 ds.setIdentityViewMatrix();
                 ds.setRenderTarget(rt);
-                ds.setColor(0xff000000);
 
                 GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, gp->getVertexStride(), 0);
                 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
diff --git a/gm/rrects.cpp b/gm/rrects.cpp
index 34e6bdb..6c672b9 100644
--- a/gm/rrects.cpp
+++ b/gm/rrects.cpp
@@ -123,12 +123,11 @@
                             drawState.addCoverageProcessor(fp);
                             drawState.setIdentityViewMatrix();
                             drawState.setRenderTarget(rt);
-                            drawState.setColor(0xff000000);
 
                             SkRect bounds = rrect.getBounds();
                             bounds.outset(2.f, 2.f);
 
-                            tt.target()->drawSimpleRect(&drawState, bounds);
+                            tt.target()->drawSimpleRect(&drawState, 0xff000000, bounds);
                         } else {
                             drew = false;
                         }
diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp
index efa7531..beb98b6 100644
--- a/gm/texturedomaineffect.cpp
+++ b/gm/texturedomaineffect.cpp
@@ -132,10 +132,9 @@
                     viewMatrix.setTranslate(x, y);
                     GrDrawState drawState(viewMatrix);
                     drawState.setRenderTarget(rt);
-                    drawState.setColor(0xffffffff);
                     drawState.addColorProcessor(fp);
 
-                    tt.target()->drawSimpleRect(&drawState, renderRect);
+                    tt.target()->drawSimpleRect(&drawState, GrColor_WHITE, renderRect);
                     x += renderRect.width() + kTestPad;
                 }
                 y += renderRect.height() + kTestPad;
diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp
index 5e7a940..dbf9cd8 100644
--- a/gm/yuvtorgbeffect.cpp
+++ b/gm/yuvtorgbeffect.cpp
@@ -117,9 +117,8 @@
                     viewMatrix.setTranslate(x, y);
                     GrDrawState drawState(viewMatrix);
                     drawState.setRenderTarget(rt);
-                    drawState.setColor(0xffffffff);
                     drawState.addColorProcessor(fp);
-                    tt.target()->drawSimpleRect(&drawState, renderRect);
+                    tt.target()->drawSimpleRect(&drawState, GrColor_WHITE, renderRect);
                 }
                 x += renderRect.width() + kTestPad;
             }
diff --git a/include/gpu/GrColor.h b/include/gpu/GrColor.h
index 50a8ec3..820b915 100644
--- a/include/gpu/GrColor.h
+++ b/include/gpu/GrColor.h
@@ -66,6 +66,9 @@
  */
 #define GrColor_ILLEGAL     (~(0xFF << GrColor_SHIFT_A))
 
+#define GrColor_WHITE 0xFFFFFFFF
+#define GrColor_TRANS_BLACK 0x0
+
 /**
  * Assert in debug builds that a GrColor is premultiplied.
  */
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index c6dd2d7..c3c11b7 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -983,6 +983,7 @@
 
     void internalDrawPath(GrDrawTarget*,
                           GrDrawState*,
+                          GrColor,
                           bool useAA,
                           const SkPath&,
                           const GrStrokeInfo&);
diff --git a/include/gpu/GrProcessorUnitTest.h b/include/gpu/GrProcessorUnitTest.h
index 3e1601d..fbf4382 100644
--- a/include/gpu/GrProcessorUnitTest.h
+++ b/include/gpu/GrProcessorUnitTest.h
@@ -8,6 +8,7 @@
 #ifndef GrProcessorUnitTest_DEFINED
 #define GrProcessorUnitTest_DEFINED
 
+#include "GrColor.h"
 #include "SkRandom.h"
 #include "SkTArray.h"
 #include "SkTypes.h"
@@ -29,6 +30,66 @@
 
 }
 
+static inline GrColor GrRandomColor(SkRandom* random) {
+    // There are only a few cases of random colors which interest us
+    enum ColorMode {
+        kAllOnes_ColorMode,
+        kAllZeros_ColorMode,
+        kAlphaOne_ColorMode,
+        kRandom_ColorMode,
+        kLast_ColorMode = kRandom_ColorMode
+    };
+
+    ColorMode colorMode = ColorMode(random->nextULessThan(kLast_ColorMode + 1));
+    GrColor color;
+    switch (colorMode) {
+        case kAllOnes_ColorMode:
+            color = GrColorPackRGBA(0xFF, 0xFF, 0xFF, 0xFF);
+            break;
+        case kAllZeros_ColorMode:
+            color = GrColorPackRGBA(0, 0, 0, 0);
+            break;
+        case kAlphaOne_ColorMode:
+            color = GrColorPackRGBA(random->nextULessThan(256),
+                                    random->nextULessThan(256),
+                                    random->nextULessThan(256),
+                                    0xFF);
+            break;
+        case kRandom_ColorMode:
+            uint8_t alpha = random->nextULessThan(256);
+            color = GrColorPackRGBA(random->nextRangeU(0, alpha),
+                                    random->nextRangeU(0, alpha),
+                                    random->nextRangeU(0, alpha),
+                                    alpha);
+            break;
+    }
+    GrColorIsPMAssert(color);
+    return color;
+}
+
+static inline uint8_t GrRandomCoverage(SkRandom* random) {
+    enum CoverageMode {
+        kZero_CoverageMode,
+        kAllOnes_CoverageMode,
+        kRandom_CoverageMode,
+        kLast_CoverageMode = kRandom_CoverageMode
+    };
+
+    CoverageMode colorMode = CoverageMode(random->nextULessThan(kLast_CoverageMode + 1));
+    uint8_t coverage;
+    switch (colorMode) {
+        case kZero_CoverageMode:
+            coverage = 0;
+        case kAllOnes_CoverageMode:
+            coverage = 0xff;
+            break;
+        case kRandom_CoverageMode:
+            coverage = random->nextULessThan(256);
+            break;
+    }
+    return coverage;
+}
+
 #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
 
 class GrContext;
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index f7c6e7f..44782dd 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -505,8 +505,8 @@
 class QuadEdgeEffect : public GrGeometryProcessor {
 public:
 
-    static GrGeometryProcessor* Create() {
-        return SkNEW(QuadEdgeEffect);
+    static GrGeometryProcessor* Create(GrColor color) {
+        return SkNEW_ARGS(QuadEdgeEffect, (color));
     }
 
     virtual ~QuadEdgeEffect() {}
@@ -586,7 +586,7 @@
     }
 
 private:
-    QuadEdgeEffect() {
+    QuadEdgeEffect(GrColor color) : INHERITED(color) {
         this->initClassID<QuadEdgeEffect>();
         fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
         fInQuadEdge = &this->addVertexAttrib(GrAttribute("inQuadEdge", kVec4f_GrVertexAttribType));
@@ -605,7 +605,7 @@
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
 
-    typedef GrFragmentProcessor INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect);
@@ -615,7 +615,7 @@
                                                 const GrDrawTargetCaps& caps,
                                                 GrTexture*[]) {
     // Doesn't work without derivative instructions.
-    return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create() : NULL;
+    return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create(GrRandomColor(random)) : NULL;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -631,6 +631,7 @@
 
 bool GrAAConvexPathRenderer::onDrawPath(GrDrawTarget* target,
                                         GrDrawState* drawState,
+                                        GrColor color,
                                         const SkPath& origPath,
                                         const SkStrokeRec&,
                                         bool antiAlias) {
@@ -678,7 +679,7 @@
     // Our computed verts should all be within one pixel of the segment control points.
     devBounds.outset(SK_Scalar1, SK_Scalar1);
 
-    GrGeometryProcessor* quadProcessor = QuadEdgeEffect::Create();
+    GrGeometryProcessor* quadProcessor = QuadEdgeEffect::Create(color);
     drawState->setGeometryProcessor(quadProcessor)->unref();
 
     GrDrawTarget::AutoReleaseGeometry arg(target, vCount, quadProcessor->getVertexStride(), iCount);
diff --git a/src/gpu/GrAAConvexPathRenderer.h b/src/gpu/GrAAConvexPathRenderer.h
index bb40e19..05f60fb 100644
--- a/src/gpu/GrAAConvexPathRenderer.h
+++ b/src/gpu/GrAAConvexPathRenderer.h
@@ -24,6 +24,7 @@
 protected:
     virtual bool onDrawPath(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkPath&,
                             const SkStrokeRec&,
                             bool antiAlias) SK_OVERRIDE;
diff --git a/src/gpu/GrAADistanceFieldPathRenderer.cpp b/src/gpu/GrAADistanceFieldPathRenderer.cpp
index 6ac504a..7a7c1e4 100755
--- a/src/gpu/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/GrAADistanceFieldPathRenderer.cpp
@@ -105,6 +105,7 @@
 
 bool GrAADistanceFieldPathRenderer::onDrawPath(GrDrawTarget* target,
                                                GrDrawState* drawState,
+                                               GrColor color,
                                                const SkPath& path,
                                                const SkStrokeRec& stroke,
                                                bool antiAlias) {
@@ -143,7 +144,7 @@
     }
 
     // use signed distance field to render
-    return this->internalDrawPath(target, drawState, path, pathData);
+    return this->internalDrawPath(target, drawState, color, path, pathData);
 }
 
 // padding around path bounds to allow for antialiased pixels
@@ -306,6 +307,7 @@
 
 bool GrAADistanceFieldPathRenderer::internalDrawPath(GrDrawTarget* target,
                                                      GrDrawState* drawState,
+                                                     GrColor color,
                                                      const SkPath& path,
                                                      const PathData* pathData) {
     GrTexture* texture = fAtlas->getTexture();
@@ -321,8 +323,9 @@
     flags |= vm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
 
     GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
-    if (flags != fEffectFlags) {
-        fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Create(texture,
+    if (flags != fEffectFlags || fCachedGeometryProcessor->getColor() != color) {
+        fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Create(color,
+                                                                                   texture,
                                                                                    params,
                                                                                    flags));
         fEffectFlags = flags;
diff --git a/src/gpu/GrAADistanceFieldPathRenderer.h b/src/gpu/GrAADistanceFieldPathRenderer.h
index 88c9d32..7b40d94 100755
--- a/src/gpu/GrAADistanceFieldPathRenderer.h
+++ b/src/gpu/GrAADistanceFieldPathRenderer.h
@@ -38,6 +38,7 @@
     
     virtual bool onDrawPath(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkPath&,
                             const SkStrokeRec&,
                             bool antiAlias) SK_OVERRIDE;
@@ -78,7 +79,7 @@
     SkTDynamicHash<PathData, PathData::Key> fPathCache;
     PathDataList                       fPathList;
     
-    bool internalDrawPath(GrDrawTarget*, GrDrawState*, const SkPath& path,
+    bool internalDrawPath(GrDrawTarget*, GrDrawState*, GrColor, const SkPath& path,
                           const PathData* pathData);
     PathData* addPathToAtlas(const SkPath& path, const SkStrokeRec& stroke, bool antiAlias,
                              uint32_t dimension, SkScalar scale);
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 15a5569..37150bd 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -643,6 +643,7 @@
 
 bool GrAAHairLinePathRenderer::createLineGeom(GrDrawTarget* target,
                                               GrDrawState* drawState,
+                                              uint8_t coverage,
                                               GrDrawTarget::AutoReleaseGeometry* arg,
                                               SkRect* devBounds,
                                               const SkPath& path,
@@ -670,7 +671,7 @@
     }
     devBounds->set(lines.begin(), lines.count());
     for (int i = 0; i < lineCnt; ++i) {
-        add_line(&lines[2*i], toSrc, drawState->getCoverage(), &verts);
+        add_line(&lines[2*i], toSrc, coverage, &verts);
     }
     // All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the end points.
     static const SkScalar kSqrtOfOneAndAQuarter = 1.118f;
@@ -803,14 +804,15 @@
 
 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
                                           GrDrawState* drawState,
+                                          GrColor color,
                                           const SkPath& path,
                                           const SkStrokeRec& stroke,
                                           bool antiAlias) {
     SkScalar hairlineCoverage;
+    uint8_t newCoverage = 0xff;
     if (IsStrokeHairlineOrEquivalent(stroke, drawState->getViewMatrix(),
                                      &hairlineCoverage)) {
-        uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * drawState->getCoverage());
-        drawState->setCoverage(newCoverage);
+        newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
     }
 
     SkIRect devClipBounds;
@@ -837,10 +839,13 @@
         uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
                            GrDefaultGeoProcFactory::kCoverage_GPType;
         GrDrawState::AutoRestoreEffects are(drawState);
-        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(gpFlags))->unref();
+        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color,
+                                                                        gpFlags,
+                                                                        newCoverage))->unref();
 
         if (!this->createLineGeom(target,
                                   drawState,
+                                  newCoverage,
                                   &arg,
                                   &devBounds,
                                   path,
@@ -911,7 +916,10 @@
 
         if (quadCnt > 0) {
             GrGeometryProcessor* hairQuadProcessor =
-                    GrQuadEffect::Create(kHairlineAA_GrProcessorEdgeType, *target->caps());
+                    GrQuadEffect::Create(color,
+                                         kHairlineAA_GrProcessorEdgeType,
+                                         *target->caps(),
+                                         newCoverage);
             SkASSERT(hairQuadProcessor);
             GrDrawState::AutoRestoreEffects are(drawState);
             target->setIndexSourceToBuffer(fQuadsIndexBuffer);
@@ -934,7 +942,7 @@
         if (conicCnt > 0) {
             GrDrawState::AutoRestoreEffects are(drawState);
             GrGeometryProcessor* hairConicProcessor = GrConicEffect::Create(
-                    kHairlineAA_GrProcessorEdgeType, *target->caps());
+                    color, kHairlineAA_GrProcessorEdgeType, *target->caps(), newCoverage);
             SkASSERT(hairConicProcessor);
 
             drawState->setGeometryProcessor(hairConicProcessor)->unref();
diff --git a/src/gpu/GrAAHairLinePathRenderer.h b/src/gpu/GrAAHairLinePathRenderer.h
index 2f44860..5d00e7e 100644
--- a/src/gpu/GrAAHairLinePathRenderer.h
+++ b/src/gpu/GrAAHairLinePathRenderer.h
@@ -30,6 +30,7 @@
 protected:
     virtual bool onDrawPath(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkPath&,
                             const SkStrokeRec&,
                             bool antiAlias) SK_OVERRIDE;
@@ -41,6 +42,7 @@
 
     bool createLineGeom(GrDrawTarget* target,
                         GrDrawState*,
+                        uint8_t coverage,
                         GrDrawTarget::AutoReleaseGeometry* arg,
                         SkRect* devBounds,
                         const SkPath& path,
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 7f61840..0cf7575 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -25,16 +25,16 @@
 };
 }
 
-static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
+static CoverageAttribType set_rect_attribs(GrDrawState* drawState, GrColor color) {
     uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
     if (drawState->canTweakAlphaForCoverage()) {
-        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
+        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
         SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
                  sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
         return kUseColor_CoverageAttribType;
     } else {
         flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
-        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
+        drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
         SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
                  sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
         return kUseCoverage_CoverageAttribType;
@@ -176,14 +176,13 @@
 
 void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
                                           GrDrawState* drawState,
+                                          GrColor color,
                                           const SkRect& rect,
                                           const SkMatrix& combinedMatrix,
                                           const SkRect& devRect) {
     GrDrawState::AutoRestoreEffects are(drawState);
 
-    GrColor color = drawState->getColor();
-
-    CoverageAttribType covAttribType = set_rect_attribs(drawState);
+    CoverageAttribType covAttribType = set_rect_attribs(drawState, color);
     if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
         drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
     }
@@ -308,6 +307,7 @@
 
 void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
                                     GrDrawState* drawState,
+                                    GrColor color,
                                     const SkRect& rect,
                                     const SkMatrix& combinedMatrix,
                                     const SkRect& devRect,
@@ -354,7 +354,7 @@
     }
 
     if (spare <= 0 && miterStroke) {
-        this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
+        this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
         return;
     }
 
@@ -371,20 +371,20 @@
         devOutsideAssist.outset(0, ry);
     }
 
-    this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside,
+    this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
                                miterStroke);
 }
 
 void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
                                             GrDrawState* drawState,
+                                            GrColor color,
                                             const SkRect& devOutside,
                                             const SkRect& devOutsideAssist,
                                             const SkRect& devInside,
                                             bool miterStroke) {
     GrDrawState::AutoRestoreEffects are(drawState);
-    CoverageAttribType covAttribType = set_rect_attribs(drawState);
+    CoverageAttribType covAttribType = set_rect_attribs(drawState, color);
 
-    GrColor color = drawState->getColor();
     if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
         drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
     }
@@ -510,6 +510,7 @@
 
 void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
                                          GrDrawState* drawState,
+                                         GrColor color,
                                          const SkRect rects[2],
                                          const SkMatrix& combinedMatrix) {
     SkASSERT(combinedMatrix.rectStaysRect());
@@ -521,9 +522,10 @@
     combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
 
     if (devInside.isEmpty()) {
-        this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
+        this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
         return;
     }
 
-    this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside, true);
+    this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
+                               true);
 }
diff --git a/src/gpu/GrAARectRenderer.h b/src/gpu/GrAARectRenderer.h
index a8ba085..b1780ad 100644
--- a/src/gpu/GrAARectRenderer.h
+++ b/src/gpu/GrAARectRenderer.h
@@ -8,6 +8,7 @@
 #ifndef GrAARectRenderer_DEFINED
 #define GrAARectRenderer_DEFINED
 
+#include "GrColor.h"
 #include "SkMatrix.h"
 #include "SkRect.h"
 #include "SkRefCnt.h"
@@ -43,14 +44,16 @@
 
     void fillAARect(GrDrawTarget* target,
                     GrDrawState* ds,
+                    GrColor color,
                     const SkRect& rect,
                     const SkMatrix& combinedMatrix,
                     const SkRect& devRect) {
-        this->geometryFillAARect(target, ds, rect, combinedMatrix, devRect);
+        this->geometryFillAARect(target, ds, color, rect, combinedMatrix, devRect);
     }
 
     void strokeAARect(GrDrawTarget*,
                       GrDrawState*,
+                      GrColor,
                       const SkRect& rect,
                       const SkMatrix& combinedMatrix,
                       const SkRect& devRect,
@@ -59,6 +62,7 @@
     // First rect is outer; second rect is inner
     void fillAANestedRects(GrDrawTarget*,
                            GrDrawState*,
+                           GrColor,
                            const SkRect rects[2],
                            const SkMatrix& combinedMatrix);
 
@@ -67,12 +71,14 @@
 
     void geometryFillAARect(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkRect& rect,
                             const SkMatrix& combinedMatrix,
                             const SkRect& devRect);
 
     void geometryStrokeAARect(GrDrawTarget*,
                               GrDrawState*,
+                              GrColor,
                               const SkRect& devOutside,
                               const SkRect& devOutsideAssist,
                               const SkRect& devInside,
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index 1853fa4..6a624ae 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -528,34 +528,15 @@
         SkASSERT(SkIsAlign4(fCurrVertex));
         SkASSERT(fCurrTexture);
 
-        // This effect could be stored with one of the cache objects (atlas?)
-        GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
-        if (kARGB_GrMaskFormat == fCurrMaskFormat) {
-            uint32_t flags = GrDefaultGeoProcFactory::kLocalCoord_GPType;
-            drawState.setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
-            GrFragmentProcessor* fragProcessor = GrSimpleTextureEffect::Create(fCurrTexture,
-                                                                               SkMatrix::I(),
-                                                                               params);
-            drawState.addColorProcessor(fragProcessor)->unref();
-        } else {
-            uint32_t textureUniqueID = fCurrTexture->getUniqueID();
-            if (textureUniqueID != fEffectTextureUniqueID) {
-                bool useColorAttrib = kA8_GrMaskFormat == fCurrMaskFormat;
-                fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(fCurrTexture,
-                                                                           params,
-                                                                           useColorAttrib));
-                fEffectTextureUniqueID = textureUniqueID;
-            }
-            drawState.setGeometryProcessor(fCachedGeometryProcessor.get());
-        }
-
         SkASSERT(fStrike);
+        GrColor color = fPaint.getColor();
         switch (fCurrMaskFormat) {
                 // Color bitmap text
-            case kARGB_GrMaskFormat:
-                SkASSERT(!drawState.hasColorVertexAttribute());
-                drawState.setAlpha(fSkPaint.getAlpha());
+            case kARGB_GrMaskFormat: {
+                int a = fSkPaint.getAlpha();
+                color = SkColorSetARGB(a, a, a, a);
                 break;
+            }
                 // LCD text
             case kA565_GrMaskFormat: {
                 // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD
@@ -564,19 +545,45 @@
                 if (!drawState.getXPFactory()->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
                     SkDebugf("LCD Text will not draw correctly.\n");
                 }
-                SkASSERT(!drawState.hasColorVertexAttribute());
                 break;
             }
                 // Grayscale/BW text
             case kA8_GrMaskFormat:
                 drawState.setHint(GrDrawState::kVertexColorsAreOpaque_Hint,
                                    0xFF == GrColorUnpackA(fPaint.getColor()));
-                // We're using per-vertex color.
-                SkASSERT(drawState.hasColorVertexAttribute());
                 break;
             default:
                 SkFAIL("Unexpected mask format.");
         }
+
+        GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
+        // TODO cache these GPs
+        if (kARGB_GrMaskFormat == fCurrMaskFormat) {
+            uint32_t textureUniqueID = fCurrTexture->getUniqueID();
+            if (textureUniqueID != fEffectTextureUniqueID ||
+                fCachedGeometryProcessor->getColor() != color) {
+                uint32_t flags = GrDefaultGeoProcFactory::kLocalCoord_GPType;
+                fCachedGeometryProcessor.reset(GrDefaultGeoProcFactory::Create(color, flags));
+                fCachedTextureProcessor.reset(GrSimpleTextureEffect::Create(fCurrTexture,
+                                                                            SkMatrix::I(),
+                                                                            params));
+            }
+            drawState.setGeometryProcessor(fCachedGeometryProcessor.get());
+            drawState.addColorProcessor(fCachedTextureProcessor.get());
+        } else {
+            uint32_t textureUniqueID = fCurrTexture->getUniqueID();
+            if (textureUniqueID != fEffectTextureUniqueID ||
+                fCachedGeometryProcessor->getColor() != color) {
+                bool hasColor = kA8_GrMaskFormat == fCurrMaskFormat;
+                fCachedGeometryProcessor.reset(GrBitmapTextGeoProc::Create(color,
+                                                                                   fCurrTexture,
+                                                                                   params,
+                                                                                   hasColor));
+                fEffectTextureUniqueID = textureUniqueID;
+            }
+            drawState.setGeometryProcessor(fCachedGeometryProcessor.get());
+        }
+
         int nGlyphs = fCurrVertex / kVerticesPerGlyph;
         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
         fDrawTarget->drawIndexedInstances(&drawState,
diff --git a/src/gpu/GrBitmapTextContext.h b/src/gpu/GrBitmapTextContext.h
index 747facf..9aa5dbd 100644
--- a/src/gpu/GrBitmapTextContext.h
+++ b/src/gpu/GrBitmapTextContext.h
@@ -31,7 +31,8 @@
     SkRect                            fVertexBounds;
     GrTexture*                        fCurrTexture;
     GrMaskFormat                      fCurrMaskFormat;
-    SkAutoTUnref<GrGeometryProcessor> fCachedGeometryProcessor;
+    SkAutoTUnref<const GrGeometryProcessor> fCachedGeometryProcessor;
+    SkAutoTUnref<const GrFragmentProcessor> fCachedTextureProcessor;
     // Used to check whether fCachedEffect is still valid.
     uint32_t                          fEffectTextureUniqueID;
 
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index e87c7e1..5af6fb6 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -362,6 +362,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 bool GrClipMaskManager::drawElement(GrDrawState* drawState,
+                                    GrColor color,
                                     GrTexture* target,
                                     const SkClipStack::Element* element,
                                     GrPathRenderer* pr) {
@@ -380,11 +381,12 @@
             if (element->isAA()) {
                 this->getContext()->getAARectRenderer()->fillAARect(fClipTarget,
                                                                     drawState,
+                                                                    color,
                                                                     element->getRect(),
                                                                     SkMatrix::I(),
                                                                     element->getRect());
             } else {
-                fClipTarget->drawSimpleRect(drawState, element->getRect());
+                fClipTarget->drawSimpleRect(drawState, color, element->getRect());
             }
             return true;
         default: {
@@ -406,7 +408,7 @@
                 return false;
             }
 
-            pr->drawPath(fClipTarget, drawState, path, stroke, element->isAA());
+            pr->drawPath(fClipTarget, drawState, color, path, stroke, element->isAA());
             break;
         }
     }
@@ -460,7 +462,7 @@
                                       GrTextureDomain::MakeTexelDomain(srcMask, srcBound),
                                       GrTextureDomain::kDecal_Mode,
                                       GrTextureParams::kNone_FilterMode))->unref();
-    fClipTarget->drawSimpleRect(drawState, SkRect::Make(dstBound));
+    fClipTarget->drawSimpleRect(drawState, GrColor_WHITE, SkRect::Make(dstBound));
 }
 
 GrTexture* GrClipMaskManager::createTempMask(int width, int height) {
@@ -617,13 +619,12 @@
                 setup_boolean_blendcoeffs(op, &drawState);
             }
 
-            drawState.setAlpha(invert ? 0x00 : 0xff);
-
             // We have to backup the drawstate because the drawElement call may call into
             // renderers which consume it.
             GrDrawState backupDrawState(drawState);
 
-            if (!this->drawElement(&drawState, dst, element, pr)) {
+            if (!this->drawElement(&drawState, invert ? GrColor_TRANS_BLACK :
+                                                        GrColor_WHITE, dst, element, pr)) {
                 fAACache.reset();
                 return NULL;
             }
@@ -639,7 +640,6 @@
                                 maskSpaceElementIBounds);
             } else {
                 // Draw to the exterior pixels (those with a zero stencil value).
-                backupDrawState.setAlpha(invert ? 0xff : 0x00);
                 GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
                                              kZero_StencilOp,
                                              kZero_StencilOp,
@@ -648,7 +648,9 @@
                                              0x0000,
                                              0xffff);
                 backupDrawState.setStencil(kDrawOutsideElement);
-                fClipTarget->drawSimpleRect(&backupDrawState, clipSpaceIBounds);
+                fClipTarget->drawSimpleRect(&backupDrawState,
+                                            invert ? GrColor_WHITE : GrColor_TRANS_BLACK,
+                                            clipSpaceIBounds);
             }
         } else {
             GrDrawState drawState(translate);
@@ -656,9 +658,8 @@
                                   GrDrawState::kClip_StateBit);
 
             // all the remaining ops can just be directly draw into the accumulation buffer
-            drawState.setAlpha(0xff);
             setup_boolean_blendcoeffs(op, &drawState);
-            this->drawElement(&drawState, result, element);
+            this->drawElement(&drawState, GrColor_WHITE, result, element);
         }
     }
 
@@ -783,13 +784,14 @@
                                              0xffff);
                 if (Element::kRect_Type == element->getType()) {
                     *drawState.stencil() = gDrawToStencil;
-                    fClipTarget->drawSimpleRect(&drawState, element->getRect());
+                    fClipTarget->drawSimpleRect(&drawState, GrColor_WHITE, element->getRect());
                 } else {
                     if (!clipPath.isEmpty()) {
                         GrDrawTarget::AutoGeometryPush agp(fClipTarget);
                         if (canRenderDirectToStencil) {
                             *drawState.stencil() = gDrawToStencil;
-                            pr->drawPath(fClipTarget, &drawState, clipPath, stroke, false);
+                            pr->drawPath(fClipTarget, &drawState, GrColor_WHITE, clipPath, stroke,
+                                         false);
                         } else {
                             pr->stencilPath(fClipTarget, &drawState, clipPath, stroke);
                         }
@@ -806,15 +808,17 @@
 
                 if (canDrawDirectToClip) {
                     if (Element::kRect_Type == element->getType()) {
-                        fClipTarget->drawSimpleRect(&drawStateCopy, element->getRect());
+                        fClipTarget->drawSimpleRect(&drawStateCopy, GrColor_WHITE,
+                                                    element->getRect());
                     } else {
                         GrDrawTarget::AutoGeometryPush agp(fClipTarget);
-                        pr->drawPath(fClipTarget, &drawStateCopy, clipPath, stroke, false);
+                        pr->drawPath(fClipTarget, &drawStateCopy, GrColor_WHITE, clipPath, stroke, false);
                     }
                 } else {
                     // The view matrix is setup to do clip space -> stencil space translation, so
                     // draw rect in clip space.
-                    fClipTarget->drawSimpleRect(&drawStateCopy, SkRect::Make(clipSpaceIBounds));
+                    fClipTarget->drawSimpleRect(&drawStateCopy, GrColor_WHITE,
+                                                SkRect::Make(clipSpaceIBounds));
                 }
             }
         }
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 3aec257..f93fa4a 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -152,6 +152,7 @@
     // desired blend operation. Optionally if the caller already selected a path renderer it can
     // be passed. Otherwise the function will select one if the element is a path.
     bool drawElement(GrDrawState*,
+                     GrColor,
                      GrTexture* target,
                      const SkClipStack::Element*,
                      GrPathRenderer* pr = NULL);
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 78d005f..9d07fdf 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -315,7 +315,7 @@
 
         uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType |
                          GrDefaultGeoProcFactory::kLocalCoord_GPType;
-        const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(flags);
+        const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(GrColor_WHITE, flags);
         drawState.setGeometryProcessor(gp)->unref();
 
         GrDrawTarget::AutoReleaseGeometry arg(fDrawBuffer, 4, gp->getVertexStride(),  0);
@@ -622,8 +622,10 @@
                              SkRect* devBoundRect,
                              const SkRect& rect,
                              SkScalar strokeWidth,
-                             const SkMatrix& combinedMatrix) {
-    if (!ds->canTweakAlphaForCoverage() && !ds->couldApplyCoverage(*target->caps())) {
+                             const SkMatrix& combinedMatrix,
+                             GrColor color) {
+    if (!ds->canTweakAlphaForCoverage() && !ds->canUseFracCoveragePrimProc(color,
+                                                                           *target->caps())) {
 #ifdef SK_DEBUG
         //SkDebugf("Turning off AA to correctly apply blend.\n");
 #endif
@@ -722,9 +724,11 @@
         }
     }
 
+    GrColor color = paint.getColor();
     SkRect devBoundRect;
     bool needAA = paint.isAntiAlias() && !drawState.getRenderTarget()->isMultisampled();
-    bool doAA = needAA && apply_aa_to_rect(target, &drawState, &devBoundRect, rect, width, matrix);
+    bool doAA = needAA && apply_aa_to_rect(target, &drawState, &devBoundRect, rect, width, matrix,
+                                           color);
 
     if (doAA) {
         GrDrawState::AutoViewMatrixRestore avmr;
@@ -736,13 +740,14 @@
             const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
             fAARectRenderer->strokeAARect(target,
                                           &drawState,
+                                          color,
                                           rect,
                                           matrix,
                                           devBoundRect,
                                           strokeRec);
         } else {
             // filled AA rect
-            fAARectRenderer->fillAARect(target, &drawState, rect, matrix, devBoundRect);
+            fAARectRenderer->fillAARect(target, &drawState, color, rect, matrix, devBoundRect);
         }
         return;
     }
@@ -753,7 +758,7 @@
         // unitSquareVertexBuffer()
 
         static const int worstCaseVertCount = 10;
-        const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create();
+        const GrGeometryProcessor* gp = GrDefaultGeoProcFactory::Create(color);
         drawState.setGeometryProcessor(gp)->unref();
         GrDrawTarget::AutoReleaseGeometry geo(target,
                                               worstCaseVertCount,
@@ -788,7 +793,7 @@
         target->drawNonIndexed(&drawState, primType, 0, vertCount);
     } else {
         // filled BW rect
-        target->drawSimpleRect(&drawState, rect);
+        target->drawSimpleRect(&drawState, color, rect);
     }
 }
 
@@ -805,14 +810,15 @@
 
     GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
 
-    target->drawRect(&drawState, dstRect, &localRect, localMatrix);
+    target->drawRect(&drawState, paint.getColor(), dstRect, &localRect, localMatrix);
 }
 
 static void set_vertex_attributes(GrDrawState* drawState,
                                   const SkPoint* texCoords,
                                   const GrColor* colors,
                                   int* colorOffset,
-                                  int* texOffset) {
+                                  int* texOffset,
+                                  GrColor color) {
     *texOffset = -1;
     *colorOffset = -1;
 
@@ -829,7 +835,7 @@
         *colorOffset = sizeof(SkPoint);
         flags |= GrDefaultGeoProcFactory::kColor_GPType;
     }
-    drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
+    drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
 }
 
 void GrContext::drawVertices(const GrPaint& paint,
@@ -852,7 +858,8 @@
     GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
 
     int colorOffset = -1, texOffset = -1;
-    set_vertex_attributes(&drawState, texCoords, colors, &colorOffset, &texOffset);
+    set_vertex_attributes(&drawState, texCoords, colors, &colorOffset, &texOffset,
+                          paint.getColor());
 
     size_t vertexStride = drawState.getGeometryProcessor()->getVertexStride();
     SkASSERT(vertexStride == sizeof(SkPoint) + (SkToBool(texCoords) ? sizeof(SkPoint) : 0)
@@ -915,11 +922,12 @@
 
     const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
 
-    if (!fOvalRenderer->drawRRect(target, &drawState, this, paint.isAntiAlias(), rrect,
+    GrColor color = paint.getColor();
+    if (!fOvalRenderer->drawRRect(target, &drawState, color, this, paint.isAntiAlias(), rrect,
                                   strokeRec)) {
         SkPath path;
         path.addRRect(rrect);
-        this->internalDrawPath(target, &drawState, paint.isAntiAlias(), path, strokeInfo);
+        this->internalDrawPath(target, &drawState, color, paint.isAntiAlias(), path, strokeInfo);
     }
 }
 
@@ -938,14 +946,16 @@
 
     GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
 
-    if (!fOvalRenderer->drawDRRect(target, &drawState, this, paint.isAntiAlias(), outer, inner)) {
+    GrColor color = paint.getColor();
+    if (!fOvalRenderer->drawDRRect(target, &drawState, color, this, paint.isAntiAlias(), outer,
+                                   inner)) {
         SkPath path;
         path.addRRect(inner);
         path.addRRect(outer);
         path.setFillType(SkPath::kEvenOdd_FillType);
 
         GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
-        this->internalDrawPath(target, &drawState, paint.isAntiAlias(), path, fillRec);
+        this->internalDrawPath(target, &drawState, color, paint.isAntiAlias(), path, fillRec);
     }
 }
 
@@ -976,17 +986,19 @@
 
     const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
 
-
-    if (!fOvalRenderer->drawOval(target, &drawState, this, paint.isAntiAlias(), oval, strokeRec)) {
+    GrColor color = paint.getColor();
+    if (!fOvalRenderer->drawOval(target, &drawState, color, this, paint.isAntiAlias(), oval,
+                                 strokeRec)) {
         SkPath path;
         path.addOval(oval);
-        this->internalDrawPath(target, &drawState, paint.isAntiAlias(), path, strokeInfo);
+        this->internalDrawPath(target, &drawState, color, paint.isAntiAlias(), path, strokeInfo);
     }
 }
 
 // Can 'path' be drawn as a pair of filled nested rectangles?
 static bool is_nested_rects(GrDrawTarget* target,
                             GrDrawState* drawState,
+                            GrColor color,
                             const SkPath& path,
                             const SkStrokeRec& stroke,
                             SkRect rects[2]) {
@@ -1002,7 +1014,8 @@
         return false;
     }
 
-    if (!drawState->canTweakAlphaForCoverage() && !drawState->couldApplyCoverage(*target->caps())) {
+    if (!drawState->canTweakAlphaForCoverage() &&
+        !drawState->canUseFracCoveragePrimProc(color, *target->caps())) {
         return false;
     }
 
@@ -1048,6 +1061,7 @@
        return;
     }
 
+    GrColor color = paint.getColor();
     if (strokeInfo.isDashed()) {
         SkPoint pts[2];
         if (path.isLine(pts)) {
@@ -1061,7 +1075,7 @@
             SkMatrix origViewMatrix = drawState.getViewMatrix();
             GrDrawState::AutoViewMatrixRestore avmr;
             if (avmr.setIdentity(&drawState)) {
-                if (GrDashingEffect::DrawDashLine(fGpu, target, &drawState, pts, paint,
+                if (GrDashingEffect::DrawDashLine(fGpu, target, &drawState, color, pts, paint,
                                                   strokeInfo, origViewMatrix)) {
                     return;
                 }
@@ -1104,14 +1118,14 @@
         // Concave AA paths are expensive - try to avoid them for special cases
         SkRect rects[2];
 
-        if (is_nested_rects(target, &drawState, path, strokeRec, rects)) {
+        if (is_nested_rects(target, &drawState, color, path, strokeRec, rects)) {
             SkMatrix origViewMatrix = drawState.getViewMatrix();
             GrDrawState::AutoViewMatrixRestore avmr;
             if (!avmr.setIdentity(&drawState)) {
                 return;
             }
 
-            fAARectRenderer->fillAANestedRects(target, &drawState, rects, origViewMatrix);
+            fAARectRenderer->fillAANestedRects(target, &drawState, color, rects, origViewMatrix);
             return;
         }
     }
@@ -1120,14 +1134,15 @@
     bool isOval = path.isOval(&ovalRect);
 
     if (!isOval || path.isInverseFillType()
-        || !fOvalRenderer->drawOval(target, &drawState, this, paint.isAntiAlias(), ovalRect,
+        || !fOvalRenderer->drawOval(target, &drawState, color, this, paint.isAntiAlias(), ovalRect,
                                     strokeRec)) {
-        this->internalDrawPath(target, &drawState, paint.isAntiAlias(), path, strokeInfo);
+        this->internalDrawPath(target, &drawState, color, paint.isAntiAlias(), path, strokeInfo);
     }
 }
 
 void GrContext::internalDrawPath(GrDrawTarget* target,
                                  GrDrawState* drawState,
+                                 GrColor color,
                                  bool useAA,
                                  const SkPath& path,
                                  const GrStrokeInfo& strokeInfo) {
@@ -1142,7 +1157,7 @@
     // thing WRT to the blend then we'll need some query on the PR.
     bool useCoverageAA = useAA &&
         !drawState->getRenderTarget()->isMultisampled() &&
-        drawState->couldApplyCoverage(*target->caps());
+        drawState->canUseFracCoveragePrimProc(color, *target->caps());
 
 
     GrPathRendererChain::DrawType type =
@@ -1179,7 +1194,7 @@
         return;
     }
 
-    pr->drawPath(target, drawState, *pathPtr, *stroke, useCoverageAA);
+    pr->drawPath(target, drawState, color, *pathPtr, *stroke, useCoverageAA);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1320,8 +1335,8 @@
         GrDrawState drawState(matrix);
         drawState.addColorProcessor(fp);
         drawState.setRenderTarget(renderTarget);
-        drawTarget->drawSimpleRect(&drawState, SkRect::MakeWH(SkIntToScalar(width),
-                                                              SkIntToScalar(height)));
+        drawTarget->drawSimpleRect(&drawState, GrColor_WHITE,SkRect::MakeWH(SkIntToScalar(width),
+                                                                            SkIntToScalar(height)));
     }
 
     if (kFlushWrites_PixelOp & pixelOpsFlags) {
@@ -1442,7 +1457,7 @@
 
                     drawState.setRenderTarget(tempTexture->asRenderTarget());
                     SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
-                    fDrawBuffer->drawSimpleRect(&drawState, rect);
+                    fDrawBuffer->drawSimpleRect(&drawState, GrColor_WHITE, rect);
                     // we want to read back from the scratch's origin
                     left = 0;
                     top = 0;
@@ -1543,8 +1558,8 @@
             SkASSERT(acf);
             ds->setFromPaint(*paint, fViewMatrix, fRenderTarget.get());
 #if GR_DEBUG_PARTIAL_COVERAGE_CHECK
-            if ((paint->hasMask() || 0xff != paint->fCoverage) &&
-                !fDrawState->couldApplyCoverage(fGpu->caps())) {
+            if ((paint->hasMask()) &&
+                !fDrawState->canUseFracCoveragePrimProc(paint.getColor(), fGpu->caps())) {
                 SkDebugf("Partial pixel coverage will be incorrectly blended.\n");
             }
 #endif
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index 6b9d2c2..dca6c1c 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -21,8 +21,8 @@
 
 class DefaultGeoProc : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(uint32_t gpTypeFlags) {
-        return SkNEW_ARGS(DefaultGeoProc, (gpTypeFlags));
+    static GrGeometryProcessor* Create(GrColor color, uint8_t coverage, uint32_t gpTypeFlags) {
+        return SkNEW_ARGS(DefaultGeoProc, (color, coverage, gpTypeFlags));
     }
 
     virtual const char* name() const SK_OVERRIDE { return "DefaultGeometryProcessor"; }
@@ -95,8 +95,9 @@
     }
 
 private:
-    DefaultGeoProc(uint32_t gpTypeFlags)
-        : fInPosition(NULL)
+    DefaultGeoProc(GrColor color, uint8_t coverage, uint32_t gpTypeFlags)
+        : INHERITED(color, coverage)
+        , fInPosition(NULL)
         , fInColor(NULL)
         , fInLocalCoords(NULL)
         , fInCoverage(NULL)
@@ -143,7 +144,7 @@
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
 
-    typedef GrFragmentProcessor INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
@@ -163,9 +164,10 @@
         flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
     }
 
-    return DefaultGeoProc::Create(flags);
+    return DefaultGeoProc::Create(GrRandomColor(random), GrRandomCoverage(random), flags);
 }
 
-const GrGeometryProcessor* GrDefaultGeoProcFactory::Create(uint32_t gpTypeFlags) {
-    return DefaultGeoProc::Create(gpTypeFlags);
+const GrGeometryProcessor* GrDefaultGeoProcFactory::Create(GrColor color, uint32_t gpTypeFlags,
+                                                           uint8_t coverage) {
+    return DefaultGeoProc::Create(color, coverage, gpTypeFlags);
 }
diff --git a/src/gpu/GrDefaultGeoProcFactory.h b/src/gpu/GrDefaultGeoProcFactory.h
index a39c76d..53fb4b8 100644
--- a/src/gpu/GrDefaultGeoProcFactory.h
+++ b/src/gpu/GrDefaultGeoProcFactory.h
@@ -80,7 +80,9 @@
      *
      * You must unref the return from Create.
      */
-    static const GrGeometryProcessor* Create(uint32_t gpTypeFlags = 0);
+    static const GrGeometryProcessor* Create(GrColor, uint32_t gpTypeFlags = 0,
+                                             uint8_t coverage = 0xff);
+    static size_t DefaultVertexStride() { return sizeof(PositionAttr); }
 };
 
 #endif
diff --git a/src/gpu/GrDefaultPathRenderer.cpp b/src/gpu/GrDefaultPathRenderer.cpp
index 4d9026f..24d3c45 100644
--- a/src/gpu/GrDefaultPathRenderer.cpp
+++ b/src/gpu/GrDefaultPathRenderer.cpp
@@ -233,12 +233,10 @@
         }
     }
 
-    // TODO this is really wierd, I just need default vertex stride, can I think of a better way?
-    SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Create());
-    if (!arg->set(target, maxPts, gp->getVertexStride(), maxIdxs)) {
+    if (!arg->set(target, maxPts, GrDefaultGeoProcFactory::DefaultVertexStride(), maxIdxs)) {
         return false;
     }
-    SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
+    SkASSERT(GrDefaultGeoProcFactory::DefaultVertexStride() == sizeof(SkPoint));
 
     uint16_t* idxBase = reinterpret_cast<uint16_t*>(arg->indices());
     uint16_t* idx = idxBase;
@@ -330,6 +328,7 @@
 
 bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
                                              GrDrawState* drawState,
+                                             GrColor color,
                                              const SkPath& path,
                                              const SkStrokeRec& origStroke,
                                              bool stencilOnly) {
@@ -337,10 +336,10 @@
     SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke);
 
     SkScalar hairlineCoverage;
+    uint8_t newCoverage = 0xff;
     if (IsStrokeHairlineOrEquivalent(*stroke, drawState->getViewMatrix(),
                                      &hairlineCoverage)) {
-        uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * drawState->getCoverage());
-        drawState->setCoverage(newCoverage);
+        newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
 
         if (!stroke->isHairlineStyle()) {
             stroke.writable()->setHairlineStyle();
@@ -493,13 +492,16 @@
                 bounds = path.getBounds();
             }
             GrDrawTarget::AutoGeometryPush agp(target);
-            target->drawSimpleRect(drawState, bounds);
+            target->drawSimpleRect(drawState, color, bounds);
         } else {
             if (passCount > 1) {
                 drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
             }
             GrDrawState::AutoRestoreEffects are(drawState);
-            drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create())->unref();
+            drawState->setGeometryProcessor(
+                    GrDefaultGeoProcFactory::Create(color,
+                                                    GrDefaultGeoProcFactory::kPosition_GPType,
+                                                    newCoverage))->unref();
             if (indexCnt) {
                 target->drawIndexed(drawState,
                                     primType,
@@ -530,11 +532,13 @@
 
 bool GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
                                        GrDrawState* drawState,
+                                       GrColor color,
                                        const SkPath& path,
                                        const SkStrokeRec& stroke,
                                        bool antiAlias) {
     return this->internalDrawPath(target,
                                   drawState,
+                                  color,
                                   path,
                                   stroke,
                                   false);
@@ -546,5 +550,5 @@
                                           const SkStrokeRec& stroke) {
     SkASSERT(SkPath::kInverseEvenOdd_FillType != path.getFillType());
     SkASSERT(SkPath::kInverseWinding_FillType != path.getFillType());
-    this->internalDrawPath(target, drawState, path, stroke, true);
+    this->internalDrawPath(target, drawState, GrColor_WHITE, path, stroke, true);
 }
diff --git a/src/gpu/GrDefaultPathRenderer.h b/src/gpu/GrDefaultPathRenderer.h
index 0f90daa..aa481e5 100644
--- a/src/gpu/GrDefaultPathRenderer.h
+++ b/src/gpu/GrDefaultPathRenderer.h
@@ -34,6 +34,7 @@
 
     virtual bool onDrawPath(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkPath&,
                             const SkStrokeRec&,
                             bool antiAlias) SK_OVERRIDE;
@@ -45,6 +46,7 @@
 
     bool internalDrawPath(GrDrawTarget*,
                           GrDrawState*,
+                          GrColor,
                           const SkPath&,
                           const SkStrokeRec&,
                           bool stencilOnly);
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index 1f4070f..d35ba23 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -403,9 +403,11 @@
     if (textureUniqueID != fEffectTextureUniqueID ||
         filteredColor != fEffectColor ||
         flags != fEffectFlags) {
+        GrColor color = fPaint.getColor();
         if (fUseLCDText) {
             GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
-            fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Create(fCurrTexture,
+            fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Create(color,
+                                                                                   fCurrTexture,
                                                                                    params,
                                                                                    fGammaTexture,
                                                                                    gammaParams,
@@ -416,15 +418,18 @@
 #ifdef SK_GAMMA_APPLY_TO_A8
             U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.gamma(),
                                                                 filteredColor);
-            fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(fCurrTexture,
+            fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(color,
+                                                                                fCurrTexture,
                                                                                 params,
                                                                                 fGammaTexture,
                                                                                 gammaParams,
                                                                                 lum/255.f,
                                                                                 flags));
 #else
-            fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Create(fCurrTexture,
-                                                                                params, flags));
+            fCachedGeometryProcessor.reset(GrDistanceFieldNoGammaTextureEffect::Create(color,
+                                                                                       fCurrTexture,
+                                                                                       params,
+                                                                                       flags));
 #endif
         }
         fEffectTextureUniqueID = textureUniqueID;
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index 51ef6cf..a91a43c 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -15,11 +15,6 @@
 #include "effects/GrPorterDuffXferProcessor.h"
 
 bool GrDrawState::isEqual(const GrDrawState& that) const {
-    bool usingVertexColors = this->hasColorVertexAttribute();
-    if (!usingVertexColors && this->fColor != that.fColor) {
-        return false;
-    }
-
     if (this->getRenderTarget() != that.getRenderTarget() ||
         this->fColorStages.count() != that.fColorStages.count() ||
         this->fCoverageStages.count() != that.fCoverageStages.count() ||
@@ -30,11 +25,6 @@
         return false;
     }
 
-    bool usingVertexCoverage = this->hasCoverageVertexAttribute();
-    if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
-        return false;
-    }
-
     bool explicitLocalCoords = this->hasLocalCoordAttribute();
     if (this->hasGeometryProcessor()) {
         if (!that.hasGeometryProcessor()) {
@@ -83,11 +73,9 @@
 
 GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
     fRenderTarget.reset(SkSafeRef(that.fRenderTarget.get()));
-    fColor = that.fColor;
     fViewMatrix = that.fViewMatrix;
     fFlagBits = that.fFlagBits;
     fStencilSettings = that.fStencilSettings;
-    fCoverage = that.fCoverage;
     fDrawFace = that.fDrawFace;
     fGeometryProcessor.reset(SkSafeRef(that.fGeometryProcessor.get()));
     fXPFactory.reset(SkRef(that.getXPFactory()));
@@ -116,7 +104,6 @@
     fColorStages.reset();
     fCoverageStages.reset();
 
-    fColor = 0xffffffff;
     if (NULL == initialViewMatrix) {
         fViewMatrix.reset();
     } else {
@@ -124,7 +111,6 @@
     }
     fFlagBits = 0x0;
     fStencilSettings.setDisabled();
-    fCoverage = 0xff;
     fDrawFace = kBoth_DrawFace;
 
     fHints = 0;
@@ -181,29 +167,34 @@
     // Enable the clip bit
     this->enableState(GrDrawState::kClip_StateBit);
 
-    this->setColor(paint.getColor());
     this->setState(GrDrawState::kDither_StateBit, paint.isDither());
     this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
 
-    this->setCoverage(0xFF);
     fColorProcInfoValid = false;
     fCoverageProcInfoValid = false;
+
+    fColorCache = GrColor_ILLEGAL;
+    fCoverageCache = GrColor_ILLEGAL;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
+bool GrDrawState::canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCaps& caps) const {
     if (caps.dualSourceBlendingSupport()) {
         return true;
     }
 
-    this->calcColorInvariantOutput();
-    this->calcCoverageInvariantOutput();
+    this->calcColorInvariantOutput(color);
+
+    // The coverage isn't actually white, its unknown, but this will produce the same effect
+    // TODO we want to cache the result of this call, but we can probably clean up the interface
+    // so we don't have to pass in a seemingly known coverage
+    this->calcCoverageInvariantOutput(GrColor_WHITE);
     return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo,
                                         this->isCoverageDrawing(), this->isColorWriteDisabled());
 }
 
-bool GrDrawState::hasSolidCoverage() const {
+bool GrDrawState::hasSolidCoverage(GrColor coverage) const {
     // If we're drawing coverage directly then coverage is effectively treated as color.
     if (this->isCoverageDrawing()) {
         return true;
@@ -213,15 +204,15 @@
         return false;
     }
 
-    this->calcCoverageInvariantOutput();
+    this->calcCoverageInvariantOutput(coverage);
     return fCoverageProcInfo.isSolidWhite();
 }
 
 //////////////////////////////////////////////////////////////////////////////s
 
-bool GrDrawState::willEffectReadDstColor() const {
-    this->calcColorInvariantOutput();
-    this->calcCoverageInvariantOutput();
+bool GrDrawState::willEffectReadDstColor(GrColor color, GrColor coverage) const {
+    this->calcColorInvariantOutput(color);
+    this->calcCoverageInvariantOutput(coverage);
     // TODO: Remove need to create the XP here.
     //       Also once all custom blends are turned into XPs we can remove the need
     //       to check other stages since only xp's will be able to read dst
@@ -378,25 +369,24 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrDrawState::srcAlphaWillBeOne() const {
-    this->calcColorInvariantOutput();
+bool GrDrawState::srcAlphaWillBeOne(GrColor color, GrColor coverage) const {
+    this->calcColorInvariantOutput(color);
     if (this->isCoverageDrawing()) {
-        this->calcCoverageInvariantOutput();
+        this->calcCoverageInvariantOutput(coverage);
         return (fColorProcInfo.isOpaque() && fCoverageProcInfo.isOpaque());
     }
     return fColorProcInfo.isOpaque();
 }
 
-bool GrDrawState::willBlendWithDst() const {
-    this->calcColorInvariantOutput();
-    this->calcCoverageInvariantOutput();
+bool GrDrawState::willBlendWithDst(GrColor color, GrColor coverage) const {
+    this->calcColorInvariantOutput(color);
+    this->calcCoverageInvariantOutput(coverage);
     return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo,
                                         this->isCoverageDrawing(), this->isColorWriteDisabled());
 }
 
-void GrDrawState::calcColorInvariantOutput() const {
-    if (!fColorProcInfoValid) {
-        GrColor color;
+void GrDrawState::calcColorInvariantOutput(GrColor color) const {
+    if (!fColorProcInfoValid || color != fColorCache) {
         GrColorComponentFlags flags;
         if (this->hasColorVertexAttribute()) {
             if (fHints & kVertexColorsAreOpaque_Hint) {
@@ -408,28 +398,27 @@
             }
         } else {
             flags = kRGBA_GrColorComponentFlags;
-            color = this->getColor();
         }
         fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(),
                                              color, flags, false);
         fColorProcInfoValid = true;
+        fColorCache = color;
     }
 }
 
-void GrDrawState::calcCoverageInvariantOutput() const {
-    if (!fCoverageProcInfoValid) {
-        GrColor color;
+void GrDrawState::calcCoverageInvariantOutput(GrColor coverage) const {
+    if (!fCoverageProcInfoValid || coverage != fCoverageCache) {
         GrColorComponentFlags flags;
         // Check if per-vertex or constant color may have partial alpha
         if (this->hasCoverageVertexAttribute()) {
             flags = static_cast<GrColorComponentFlags>(0);
-            color = 0;
+            coverage = 0;
         } else {
             flags = kRGBA_GrColorComponentFlags;
-            color = this->getCoverageColor();
         }
         fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(),
-                                                color, flags, true, fGeometryProcessor.get());
+                                                coverage, flags, true, fGeometryProcessor.get());
         fCoverageProcInfoValid = true;
+        fCoverageCache = coverage;
     }
 }
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 68c71f0..17bd0f4 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -92,73 +92,21 @@
      *
      * This function considers the current draw state and the draw target's capabilities to
      * determine whether coverage can be handled correctly. This function assumes that the caller
-     * intends to specify fractional pixel coverage (via setCoverage(), through a coverage vertex
-     * attribute, or a coverage effect) but may not have specified it yet.
+     * intends to specify fractional pixel coverage via a primitive processor but may not have
+     * specified it yet.
      */
-    bool couldApplyCoverage(const GrDrawTargetCaps& caps) const;
+    bool canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCaps& caps) const;
 
     /**
      * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw.
      */
-    bool hasSolidCoverage() const;
+    bool hasSolidCoverage(GrColor coverage) const;
 
     /**
      * This function returns true if the render target destination pixel values will be read for
      * blending during draw.
      */
-    bool willBlendWithDst() const;
-
-    /// @}
-
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Color
-    ////
-
-    GrColor getColor() const { return fColor; }
-
-    /**
-     *  Sets color for next draw to a premultiplied-alpha color.
-     *
-     *  @param color    the color to set.
-     */
-    void setColor(GrColor color) {
-        if (color != fColor) {
-            fColor = color;
-            fColorProcInfoValid = false;
-        }
-    }
-
-    /**
-     *  Sets the color to be used for the next draw to be
-     *  (r,g,b,a) = (alpha, alpha, alpha, alpha).
-     *
-     *  @param alpha The alpha value to set as the color.
-     */
-    void setAlpha(uint8_t a) { this->setColor((a << 24) | (a << 16) | (a << 8) | a); }
-
-    /// @}
-
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Coverage
-    ////
-
-    uint8_t getCoverage() const { return fCoverage; }
-
-    GrColor getCoverageColor() const {
-        return GrColorPackRGBA(fCoverage, fCoverage, fCoverage, fCoverage);
-    }
-
-    /**
-     * Sets a constant fractional coverage to be applied to the draw. The
-     * initial value (after construction or reset()) is 0xff. The constant
-     * coverage is ignored when per-vertex coverage is provided.
-     */
-    void setCoverage(uint8_t coverage) {
-        if (coverage != fCoverage) {
-            fCoverage = coverage;
-            fCoverageProcInfoValid = false;
-        }
-    }
+    bool willBlendWithDst(GrColor color, GrColor coverage) const;
 
     /// @}
 
@@ -213,8 +161,9 @@
 
     /**
      * Checks whether any of the effects will read the dst pixel color.
+     * TODO remove when we have an XP
      */
-    bool willEffectReadDstColor() const;
+    bool willEffectReadDstColor(GrColor color, GrColor coverage) const;
 
     /**
      * The xfer processor factory.
@@ -608,32 +557,32 @@
 private:
     bool isEqual(const GrDrawState& that) const;
 
-    const GrProcOptInfo& colorProcInfo() const { 
-        this->calcColorInvariantOutput();
+    const GrProcOptInfo& colorProcInfo(GrColor color) const { 
+        this->calcColorInvariantOutput(color);
         return fColorProcInfo;
     }
 
-    const GrProcOptInfo& coverageProcInfo() const {
-        this->calcCoverageInvariantOutput();
+    const GrProcOptInfo& coverageProcInfo(GrColor coverage) const {
+        this->calcCoverageInvariantOutput(coverage);
         return fCoverageProcInfo;
     }
 
     /**
      * Determines whether src alpha is guaranteed to be one for all src pixels
      */
-    bool srcAlphaWillBeOne() const;
+    bool srcAlphaWillBeOne(GrColor color, GrColor coverage) const;
 
     /**
      * If fColorProcInfoValid is false, function calculates the invariant output for the color
      * stages and results are stored in fColorProcInfo.
      */
-    void calcColorInvariantOutput() const;
+    void calcColorInvariantOutput(GrColor) const;
 
     /**
      * If fCoverageProcInfoValid is false, function calculates the invariant output for the coverage
      * stages and results are stored in fCoverageProcInfo.
      */
-    void calcCoverageInvariantOutput() const;
+    void calcCoverageInvariantOutput(GrColor) const;
 
     void onReset(const SkMatrix* initialViewMatrix);
 
@@ -644,11 +593,9 @@
     typedef SkSTArray<4, GrFragmentStage> FragmentStageArray;
 
     SkAutoTUnref<GrRenderTarget>            fRenderTarget;
-    GrColor                                 fColor;
     SkMatrix                                fViewMatrix;
     uint32_t                                fFlagBits;
     GrStencilSettings                       fStencilSettings;
-    uint8_t                                 fCoverage;
     DrawFace                                fDrawFace;
     SkAutoTUnref<const GrGeometryProcessor> fGeometryProcessor;
     SkAutoTUnref<const GrXPFactory>         fXPFactory;
@@ -660,6 +607,8 @@
     mutable GrProcOptInfo fCoverageProcInfo;
     mutable bool fColorProcInfoValid;
     mutable bool fCoverageProcInfoValid;
+    mutable GrColor fColorCache;
+    mutable GrColor fCoverageCache;
 
     friend class GrOptDrawState;
 };
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 0d6a388..adb7128 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -383,9 +383,12 @@
 }
 
 bool GrDrawTarget::setupDstReadIfNecessary(GrDrawState* ds,
+                                           GrColor color,
+                                           uint8_t coverage,
                                            GrDeviceCoordTexture* dstCopy,
                                            const SkRect* drawBounds) {
-    if (this->caps()->dstReadInShaderSupport() || !ds->willEffectReadDstColor()) {
+    GrColor c = GrColorPackRGBA(coverage, coverage, coverage, coverage);
+    if (this->caps()->dstReadInShaderSupport() || !ds->willEffectReadDstColor(color, c)) {
         return true;
     }
     SkIRect copyRect;
@@ -468,10 +471,12 @@
 
         // TODO: We should continue with incorrect blending.
         GrDeviceCoordTexture dstCopy;
-        if (!this->setupDstReadIfNecessary(ds, &dstCopy, devBounds)) {
+        const GrGeometryProcessor* gp = ds->getGeometryProcessor();
+        if (!this->setupDstReadIfNecessary(ds, gp->getColor(), gp->getCoverage(), &dstCopy,
+                                           devBounds)) {
             return;
         }
-        this->setDrawBuffers(&info, ds->getGeometryProcessor()->getVertexStride());
+        this->setDrawBuffers(&info, gp->getVertexStride());
 
         this->onDraw(*ds, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
     }
@@ -510,11 +515,13 @@
 
         // TODO: We should continue with incorrect blending.
         GrDeviceCoordTexture dstCopy;
-        if (!this->setupDstReadIfNecessary(ds, &dstCopy, devBounds)) {
+        const GrGeometryProcessor* gp = ds->getGeometryProcessor();
+        if (!this->setupDstReadIfNecessary(ds, gp->getColor(), gp->getCoverage(), &dstCopy,
+                                           devBounds)) {
             return;
         }
 
-        this->setDrawBuffers(&info, ds->getGeometryProcessor()->getVertexStride());
+        this->setDrawBuffers(&info, gp->getVertexStride());
 
         this->onDraw(*ds, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
     }
@@ -581,6 +588,7 @@
 }
 
 void GrDrawTarget::drawPath(GrDrawState* ds,
+                            GrColor color,
                             const GrPath* path,
                             GrPathRendering::FillType fill) {
     // TODO: extract portions of checkDraw that are relevant to path rendering.
@@ -607,14 +615,16 @@
                                             &stencilSettings);
 
     GrDeviceCoordTexture dstCopy;
-    if (!this->setupDstReadIfNecessary(ds, &dstCopy, &devBounds)) {
+    if (!this->setupDstReadIfNecessary(ds, color, 0xff, &dstCopy, &devBounds)) {
         return;
     }
 
-    this->onDrawPath(*ds, path, scissorState, stencilSettings, dstCopy.texture() ? &dstCopy : NULL);
+    this->onDrawPath(*ds, color, path, scissorState, stencilSettings, dstCopy.texture() ? &dstCopy :
+                                                                                          NULL);
 }
 
 void GrDrawTarget::drawPaths(GrDrawState* ds,
+                             GrColor color,
                              const GrPathRange* pathRange,
                              const void* indices,
                              PathIndexType indexType,
@@ -649,12 +659,12 @@
     // point, because any context that supports NV_path_rendering will also
     // support NV_blend_equation_advanced.
     GrDeviceCoordTexture dstCopy;
-    if (!this->setupDstReadIfNecessary(ds, &dstCopy, NULL)) {
+    if (!this->setupDstReadIfNecessary(ds, color, 0xff, &dstCopy, NULL)) {
         return;
     }
 
-    this->onDrawPaths(*ds, pathRange, indices, indexType, transformValues, transformType, count,
-                      scissorState, stencilSettings, dstCopy.texture() ? &dstCopy : NULL);
+    this->onDrawPaths(*ds, color, pathRange, indices, indexType, transformValues, transformType,
+                      count, scissorState, stencilSettings, dstCopy.texture() ? &dstCopy : NULL);
 }
 
 void GrDrawTarget::clear(const SkIRect* rect,
@@ -673,11 +683,9 @@
         }
 
         GrDrawState drawState;
-
-        drawState.setColor(color);
         drawState.setRenderTarget(renderTarget);
 
-        this->drawSimpleRect(&drawState, *rect);
+        this->drawSimpleRect(&drawState, color, *rect);
     } else {       
         this->onClear(rect, color, canIgnoreRect, renderTarget);
     }
@@ -763,7 +771,8 @@
 
     // TODO: We should continue with incorrect blending.
     GrDeviceCoordTexture dstCopy;
-    if (!this->setupDstReadIfNecessary(ds, &dstCopy, devBounds)) {
+    const GrGeometryProcessor* gp = ds->getGeometryProcessor();
+    if (!this->setupDstReadIfNecessary(ds, gp->getColor(), gp->getCoverage(), &dstCopy,devBounds)) {
         return;
     }
 
@@ -778,7 +787,7 @@
                             info.fStartIndex,
                             info.fVertexCount,
                             info.fIndexCount)) {
-            this->setDrawBuffers(&info, ds->getGeometryProcessor()->getVertexStride());
+            this->setDrawBuffers(&info, gp->getVertexStride());
             this->onDraw(*ds, info, scissorState, dstCopy.texture() ? &dstCopy : NULL);
         }
         info.fStartVertex += info.fVertexCount;
@@ -944,7 +953,7 @@
                                         clippedDstPoint.fY,
                                         clippedSrcRect.width(),
                                         clippedSrcRect.height());
-    this->drawSimpleRect(&drawState, dstRect);
+    this->drawSimpleRect(&drawState, GrColor_WHITE, dstRect);
     return true;
 }
 
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index c7f45d3..fc2ee76 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -269,7 +269,7 @@
      * Draws a path. Fill must not be a hairline. It will respect the HW
      * antialias flag on the draw state (if possible in the 3D API).
      */
-    void drawPath(GrDrawState*, const GrPath*, GrPathRendering::FillType fill);
+    void drawPath(GrDrawState*, GrColor, const GrPath*, GrPathRendering::FillType fill);
 
     /**
      * Draws the aggregate path from combining multiple. Note that this will not
@@ -284,7 +284,9 @@
      * @param count           Number of paths to draw
      * @param fill            Fill type for drawing all the paths
      */
-    void drawPaths(GrDrawState*, const GrPathRange* pathRange,
+    void drawPaths(GrDrawState*,
+                   GrColor,
+                   const GrPathRange* pathRange,
                    const void* indices,
                    PathIndexType indexType,
                    const float transformValues[],
@@ -305,22 +307,23 @@
      *                    srcMatrix can be NULL when no srcMatrix is desired.
      */
     void drawRect(GrDrawState* ds,
+                  GrColor color,
                   const SkRect& rect,
                   const SkRect* localRect,
                   const SkMatrix* localMatrix) {
         AutoGeometryPush agp(this);
-        this->onDrawRect(ds, rect, localRect, localMatrix);
+        this->onDrawRect(ds, color, rect, localRect, localMatrix);
     }
 
     /**
      * Helper for drawRect when the caller doesn't need separate local rects or matrices.
      */
-    void drawSimpleRect(GrDrawState* ds, const SkRect& rect) {
-        this->drawRect(ds, rect, NULL, NULL);
+    void drawSimpleRect(GrDrawState* ds, GrColor color, const SkRect& rect) {
+        this->drawRect(ds, color, rect, NULL, NULL);
     }
-    void drawSimpleRect(GrDrawState* ds, const SkIRect& irect) {
+    void drawSimpleRect(GrDrawState* ds, GrColor color, const SkIRect& irect) {
         SkRect rect = SkRect::Make(irect);
-        this->drawRect(ds, rect, NULL, NULL);
+        this->drawRect(ds, color, rect, NULL, NULL);
     }
 
     /**
@@ -653,6 +656,8 @@
     // but couldn't be made. Otherwise, returns true.  This method needs to be protected because it
     // needs to be accessed by GLPrograms to setup a correct drawstate
     bool setupDstReadIfNecessary(GrDrawState*,
+                                 GrColor,
+                                 uint8_t,
                                  GrDeviceCoordTexture* dstCopy,
                                  const SkRect* drawBounds);
 
@@ -698,6 +703,7 @@
                         const GrDeviceCoordTexture* dstCopy) = 0;
     // TODO copy in order drawbuffer onDrawRect to here
     virtual void onDrawRect(GrDrawState*,
+                            GrColor color,
                             const SkRect& rect,
                             const SkRect* localRect,
                             const SkMatrix* localMatrix) = 0;
@@ -707,11 +713,13 @@
                                const GrClipMaskManager::ScissorState&,
                                const GrStencilSettings&) = 0;
     virtual void onDrawPath(const GrDrawState&,
+                            GrColor,
                             const GrPath*,
                             const GrClipMaskManager::ScissorState&,
                             const GrStencilSettings&,
                             const GrDeviceCoordTexture* dstCopy) = 0;
     virtual void onDrawPaths(const GrDrawState&,
+                             GrColor,
                              const GrPathRange*,
                              const void* indices,
                              PathIndexType,
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index 9e621d8..4801069 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -8,6 +8,7 @@
 #ifndef GrGeometryProcessor_DEFINED
 #define GrGeometryProcessor_DEFINED
 
+#include "GrColor.h"
 #include "GrGeometryData.h"
 #include "GrProcessor.h"
 #include "GrShaderVar.h"
@@ -50,8 +51,10 @@
  */
 class GrGeometryProcessor : public GrProcessor {
 public:
-    GrGeometryProcessor()
+    GrGeometryProcessor(GrColor color, uint8_t coverage = 0xff)
         : fVertexStride(0)
+        , fColor(color)
+        , fCoverage(coverage)
         , fWillUseGeoShader(false)
         , fHasVertexColor(false)
         , fHasVertexCoverage(false)
@@ -107,6 +110,14 @@
         if (this->classID() != that.classID() || !this->hasSameTextureAccesses(that)) {
             return false;
         }
+
+        if (!fHasVertexColor && this->getColor() != that.getColor()) {
+            return false;
+        }
+
+        if (!fHasVertexCoverage && this->getCoverage() != that.getCoverage()) {
+            return false;
+        }
         return this->onIsEqual(that);
     }
 
@@ -119,12 +130,17 @@
 
     virtual void initBatchTracker(GrBatchTracker*, const InitBT&) const {}
 
+    GrColor getColor() const { return fColor; }
+    uint8_t getCoverage() const { return fCoverage; }
+
     // TODO this is a total hack until the gp can own whether or not it uses uniform
     // color / coverage
     bool hasVertexColor() const { return fHasVertexColor; }
     bool hasVertexCoverage() const { return fHasVertexCoverage; }
     bool hasLocalCoords() const { return fHasLocalCoords; }
 
+    void computeInvariantColor(GrInvariantOutput* inout) const;
+
 protected:
     /**
      * Subclasses call this from their constructor to register vertex attributes.  Attributes
@@ -149,6 +165,8 @@
 
     SkSTArray<kMaxVertexAttribs, GrAttribute, true> fAttribs;
     size_t fVertexStride;
+    GrColor fColor;
+    uint8_t fCoverage;
     bool fWillUseGeoShader;
     bool fHasVertexColor;
     bool fHasVertexCoverage;
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 3c7b146..493420d 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -66,7 +66,7 @@
     uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType |
                      GrDefaultGeoProcFactory::kColor_GPType;
     flags |= hasLocalCoords ? GrDefaultGeoProcFactory::kLocalCoord_GPType : 0;
-    drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
+    drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
     if (0xFF == GrColorUnpackA(color)) {
         drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
     }
@@ -110,12 +110,12 @@
 static inline bool cmd_has_trace_marker(uint8_t cmd) { return SkToBool(cmd & kTraceCmdBit); }
 
 void GrInOrderDrawBuffer::onDrawRect(GrDrawState* ds,
+                                     GrColor color,
                                      const SkRect& rect,
                                      const SkRect* localRect,
                                      const SkMatrix* localMatrix) {
     GrDrawState::AutoRestoreEffects are(ds);
 
-    GrColor color = ds->getColor();
     set_vertex_attributes(ds, SkToBool(localRect),  color);
 
     size_t vstride = ds->getGeometryProcessor()->getVertexStride();
@@ -226,7 +226,9 @@
                                  const GrDeviceCoordTexture* dstCopy) {
     SkASSERT(info.vertexBuffer() && (!info.isIndexed() || info.indexBuffer()));
 
-    if (!this->recordStateAndShouldDraw(ds, GrGpu::PrimTypeToDrawType(info.primitiveType()),
+    const GrGeometryProcessor* gp = ds.getGeometryProcessor();
+    if (!this->recordStateAndShouldDraw(ds, gp->getColor(), gp->getCoverage(),
+                                        GrGpu::PrimTypeToDrawType(info.primitiveType()),
                                         scissorState, dstCopy)) {
         return;
     }
@@ -251,7 +253,8 @@
                                         const GrClipMaskManager::ScissorState& scissorState,
                                         const GrStencilSettings& stencilSettings) {
     // Only compare the subset of GrDrawState relevant to path stenciling?
-    if (!this->recordStateAndShouldDraw(ds, GrGpu::kStencilPath_DrawType, scissorState, NULL)) {
+    if (!this->recordStateAndShouldDraw(ds, GrColor_WHITE, 0xff, GrGpu::kStencilPath_DrawType,
+                                        scissorState, NULL)) {
         return;
     }
     StencilPath* sp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, StencilPath, (path));
@@ -260,12 +263,14 @@
 }
 
 void GrInOrderDrawBuffer::onDrawPath(const GrDrawState& ds,
+                                     GrColor color,
                                      const GrPath* path,
                                      const GrClipMaskManager::ScissorState& scissorState,
                                      const GrStencilSettings& stencilSettings,
                                      const GrDeviceCoordTexture* dstCopy) {
     // TODO: Only compare the subset of GrDrawState relevant to path covering?
-    if (!this->recordStateAndShouldDraw(ds, GrGpu::kDrawPath_DrawType, scissorState, dstCopy)) {
+    if (!this->recordStateAndShouldDraw(ds, color, 0xff, GrGpu::kDrawPath_DrawType, scissorState,
+                                        dstCopy)) {
         return;
     }
     DrawPath* dp = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, DrawPath, (path));
@@ -274,6 +279,7 @@
 }
 
 void GrInOrderDrawBuffer::onDrawPaths(const GrDrawState& ds,
+                                      GrColor color,
                                       const GrPathRange* pathRange,
                                       const void* indices,
                                       PathIndexType indexType,
@@ -287,7 +293,8 @@
     SkASSERT(indices);
     SkASSERT(transformValues);
 
-    if (!this->recordStateAndShouldDraw(ds, GrGpu::kDrawPath_DrawType, scissorState, dstCopy)) {
+    if (!this->recordStateAndShouldDraw(ds, color, 0xff, GrGpu::kDrawPath_DrawType, scissorState,
+                                        dstCopy)) {
         return;
     }
 
@@ -317,7 +324,7 @@
             transformType == previous->fTransformType &&
             stencilSettings == previous->fStencilSettings &&
             path_fill_type_is_winding(stencilSettings) &&
-            !ds.willBlendWithDst()) {
+            !ds.willBlendWithDst(color, GrColor_WHITE)) {
             // Fold this DrawPaths call into the one previous.
             previous->fCount += count;
             return;
@@ -483,12 +490,14 @@
 }
 
 bool GrInOrderDrawBuffer::recordStateAndShouldDraw(const GrDrawState& ds,
+                                                   GrColor color,
+                                                   uint8_t coverage,
                                                    GrGpu::DrawType drawType,
                                                    const GrClipMaskManager::ScissorState& scissor,
                                                    const GrDeviceCoordTexture* dstCopy) {
     SetState* ss = GrNEW_APPEND_TO_RECORDER(fCmdBuffer, SetState,
-                                            (ds, *this->getGpu()->caps(), scissor, dstCopy,
-                                             drawType));
+                                            (ds, color, coverage, *this->getGpu()->caps(), scissor,
+                                             dstCopy, drawType));
     if (ss->fState.mustSkip()) {
         fCmdBuffer.pop_back();
         return false;
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index 01e560a..6771fcc 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -171,11 +171,11 @@
     };
 
     struct SetState : public Cmd {
-        SetState(const GrDrawState& drawState, const GrDrawTargetCaps& caps,
-                 const ScissorState& scissor, const GrDeviceCoordTexture* dstCopy,
-                 GrGpu::DrawType drawType)
+        SetState(const GrDrawState& drawState, GrColor color, uint8_t coverage,
+                 const GrDrawTargetCaps& caps, const ScissorState& scissor,
+                 const GrDeviceCoordTexture* dstCopy, GrGpu::DrawType drawType)
         : Cmd(kSetState_Cmd)
-        , fState(drawState, caps, scissor, dstCopy, drawType) {}
+        , fState(drawState, color, coverage, caps, scissor, dstCopy, drawType) {}
 
         void execute(GrInOrderDrawBuffer*, const GrOptDrawState*) SK_OVERRIDE;
 
@@ -194,6 +194,7 @@
                 const ScissorState&,
                 const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
     void onDrawRect(GrDrawState*,
+                    GrColor,
                     const SkRect& rect,
                     const SkRect* localRect,
                     const SkMatrix* localMatrix) SK_OVERRIDE;
@@ -203,11 +204,13 @@
                        const ScissorState&,
                        const GrStencilSettings&) SK_OVERRIDE;
     void onDrawPath(const GrDrawState&,
+                    GrColor,
                     const GrPath*,
                     const ScissorState&,
                     const GrStencilSettings&,
                     const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
     void onDrawPaths(const GrDrawState&,
+                     GrColor,
                      const GrPathRange*,
                      const void* indices,
                      PathIndexType,
@@ -234,6 +237,8 @@
     // records it. If the draw can be skipped false is returned and no new GrOptDrawState is
     // recorded.
     bool SK_WARN_UNUSED_RESULT recordStateAndShouldDraw(const GrDrawState&,
+                                                        GrColor,
+                                                        uint8_t coverage,
                                                         GrGpu::DrawType,
                                                         const GrClipMaskManager::ScissorState&,
                                                         const GrDeviceCoordTexture*);
diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp
index d317201..409305c 100644
--- a/src/gpu/GrOptDrawState.cpp
+++ b/src/gpu/GrOptDrawState.cpp
@@ -14,18 +14,21 @@
 #include "GrXferProcessor.h"
 
 GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
+                               GrColor color,
+                               uint8_t coverage,
                                const GrDrawTargetCaps& caps,
                                const ScissorState& scissorState,
                                const GrDeviceCoordTexture* dstCopy,
                                GrGpu::DrawType drawType)
     : fFinalized(false) {
+    GrColor coverageColor = GrColorPackRGBA(coverage, coverage, coverage, coverage);
     fDrawType = drawType;
 
-    const GrProcOptInfo& colorPOI = drawState.colorProcInfo();
-    const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo();
+    const GrProcOptInfo& colorPOI = drawState.colorProcInfo(color);
+    const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(coverageColor);
     
     fColor = colorPOI.inputColorToEffectiveStage();
-    fCoverage = drawState.getCoverage();
+    fCoverage = coverage;
 
     // Create XferProcessor from DS's XPFactory
     SkAutoTUnref<GrXferProcessor> xferProcessor(
@@ -144,10 +147,11 @@
         fGeometryProcessor->initBatchTracker(&fBatchTracker, init);
     }
 
-    this->setOutputStateInfo(drawState, optFlags, caps);
+    this->setOutputStateInfo(drawState, coverageColor, optFlags, caps);
 }
 
 void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
+                                        GrColor coverage,
                                         GrXferProcessor::OptFlags optFlags,
                                         const GrDrawTargetCaps& caps) {
     // Set this default and then possibly change our mind if there is coverage.
@@ -157,7 +161,7 @@
     // Determine whether we should use dual source blending or shader code to keep coverage
     // separate from color.
     bool keepCoverageSeparate = !(optFlags & GrXferProcessor::kSetCoverageDrawing_OptFlag);
-    if (keepCoverageSeparate && !ds.hasSolidCoverage()) {
+    if (keepCoverageSeparate && !ds.hasSolidCoverage(coverage)) {
         if (caps.dualSourceBlendingSupport()) {
             if (kZero_GrBlendCoeff == fDstBlend) {
                 // write the coverage value to second color
diff --git a/src/gpu/GrOptDrawState.h b/src/gpu/GrOptDrawState.h
index 1878d16..cf57373 100644
--- a/src/gpu/GrOptDrawState.h
+++ b/src/gpu/GrOptDrawState.h
@@ -30,8 +30,8 @@
 
     typedef GrClipMaskManager::ScissorState ScissorState;
 
-    GrOptDrawState(const GrDrawState& drawState, const GrDrawTargetCaps&, const ScissorState&,
-                   const GrDeviceCoordTexture* dstCopy, GrGpu::DrawType);
+    GrOptDrawState(const GrDrawState& drawState, GrColor, uint8_t coverage, const GrDrawTargetCaps&,
+                   const ScissorState&, const GrDeviceCoordTexture* dstCopy, GrGpu::DrawType);
 
     bool operator== (const GrOptDrawState& that) const;
     bool operator!= (const GrOptDrawState& that) const { return !(*this == that); }
@@ -206,7 +206,7 @@
      * the function may adjust the blend coefficients. After this function is called the src and dst
      * blend coeffs will represent those used by backend API.
      */
-    void setOutputStateInfo(const GrDrawState& ds, GrXferProcessor::OptFlags,
+    void setOutputStateInfo(const GrDrawState& ds, GrColor coverage, GrXferProcessor::OptFlags,
                             const GrDrawTargetCaps&);
 
     enum Flags {
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 4d7912a..eac6fb4 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -59,8 +59,8 @@
 
 class CircleEdgeEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(bool stroke) {
-        return SkNEW_ARGS(CircleEdgeEffect, (stroke));
+    static GrGeometryProcessor* Create(GrColor color, bool stroke) {
+        return SkNEW_ARGS(CircleEdgeEffect, (color, stroke));
     }
 
     const GrAttribute* inPosition() const { return fInPosition; }
@@ -131,7 +131,7 @@
     }
 
 private:
-    CircleEdgeEffect(bool stroke) {
+    CircleEdgeEffect(GrColor color, bool stroke) : INHERITED(color) {
         this->initClassID<CircleEdgeEffect>();
         fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
         fInCircleEdge = &this->addVertexAttrib(GrAttribute("inCircleEdge",
@@ -163,7 +163,7 @@
                                                   GrContext* context,
                                                   const GrDrawTargetCaps&,
                                                   GrTexture* textures[]) {
-    return CircleEdgeEffect::Create(random->nextBool());
+    return CircleEdgeEffect::Create(GrRandomColor(random), random->nextBool());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -178,8 +178,8 @@
 
 class EllipseEdgeEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(bool stroke) {
-        return SkNEW_ARGS(EllipseEdgeEffect, (stroke));
+    static GrGeometryProcessor* Create(GrColor color, bool stroke) {
+        return SkNEW_ARGS(EllipseEdgeEffect, (color, stroke));
     }
 
     virtual ~EllipseEdgeEffect() {}
@@ -275,7 +275,7 @@
     }
 
 private:
-    EllipseEdgeEffect(bool stroke) {
+    EllipseEdgeEffect(GrColor color, bool stroke) : INHERITED(color) {
         this->initClassID<EllipseEdgeEffect>();
         fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
         fInEllipseOffset = &this->addVertexAttrib(GrAttribute("inEllipseOffset",
@@ -310,7 +310,7 @@
                                                    GrContext* context,
                                                    const GrDrawTargetCaps&,
                                                    GrTexture* textures[]) {
-    return EllipseEdgeEffect::Create(random->nextBool());
+    return EllipseEdgeEffect::Create(GrRandomColor(random), random->nextBool());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -328,8 +328,8 @@
 public:
     enum Mode { kStroke = 0, kHairline, kFill };
 
-    static GrGeometryProcessor* Create(Mode mode) {
-        return SkNEW_ARGS(DIEllipseEdgeEffect, (mode));
+    static GrGeometryProcessor* Create(GrColor color, Mode mode) {
+        return SkNEW_ARGS(DIEllipseEdgeEffect, (color, mode));
     }
 
     virtual ~DIEllipseEdgeEffect() {}
@@ -440,7 +440,7 @@
     }
 
 private:
-    DIEllipseEdgeEffect(Mode mode) {
+    DIEllipseEdgeEffect(GrColor color, Mode mode) : INHERITED(color) {
         this->initClassID<DIEllipseEdgeEffect>();
         fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
         fInEllipseOffsets0 = &this->addVertexAttrib(GrAttribute("inEllipseOffsets0",
@@ -475,7 +475,7 @@
                                                      GrContext* context,
                                                      const GrDrawTargetCaps&,
                                                      GrTexture* textures[]) {
-    return DIEllipseEdgeEffect::Create((Mode)(random->nextRangeU(0,2)));
+    return DIEllipseEdgeEffect::Create(GrRandomColor(random), (Mode)(random->nextRangeU(0,2)));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -487,6 +487,7 @@
 
 bool GrOvalRenderer::drawOval(GrDrawTarget* target,
                               GrDrawState* drawState,
+                              GrColor color,
                               const GrContext* context,
                               bool useAA,
                               const SkRect& oval,
@@ -494,7 +495,7 @@
 {
     bool useCoverageAA = useAA &&
         !drawState->getRenderTarget()->isMultisampled() &&
-        drawState->couldApplyCoverage(*target->caps());
+        drawState->canUseFracCoveragePrimProc(color, *target->caps());
 
     if (!useCoverageAA) {
         return false;
@@ -505,13 +506,13 @@
     // we can draw circles
     if (SkScalarNearlyEqual(oval.width(), oval.height())
         && circle_stays_circle(vm)) {
-        this->drawCircle(target, drawState, context, useCoverageAA, oval, stroke);
+        this->drawCircle(target, drawState, color, context, useCoverageAA, oval, stroke);
     // if we have shader derivative support, render as device-independent
     } else if (target->caps()->shaderDerivativeSupport()) {
-        return this->drawDIEllipse(target, drawState, context, useCoverageAA, oval, stroke);
+        return this->drawDIEllipse(target, drawState, color, context, useCoverageAA, oval, stroke);
     // otherwise axis-aligned ellipses only
     } else if (vm.rectStaysRect()) {
-        return this->drawEllipse(target, drawState, context, useCoverageAA, oval, stroke);
+        return this->drawEllipse(target, drawState, color, context, useCoverageAA, oval, stroke);
     } else {
         return false;
     }
@@ -523,6 +524,7 @@
 
 void GrOvalRenderer::drawCircle(GrDrawTarget* target,
                                 GrDrawState* drawState,
+                                GrColor color,
                                 const GrContext* context,
                                 bool useCoverageAA,
                                 const SkRect& circle,
@@ -560,7 +562,7 @@
         }
     }
 
-    GrGeometryProcessor* gp = CircleEdgeEffect::Create(isStrokeOnly && innerRadius > 0);
+    GrGeometryProcessor* gp = CircleEdgeEffect::Create(color, isStrokeOnly && innerRadius > 0);
     drawState->setGeometryProcessor(gp)->unref();
 
     GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(),  0);
@@ -615,6 +617,7 @@
 
 bool GrOvalRenderer::drawEllipse(GrDrawTarget* target,
                                  GrDrawState* drawState,
+                                 GrColor color,
                                  const GrContext* context,
                                  bool useCoverageAA,
                                  const SkRect& ellipse,
@@ -686,7 +689,8 @@
         return false;
     }
 
-    GrGeometryProcessor* gp = EllipseEdgeEffect::Create(isStrokeOnly &&
+    GrGeometryProcessor* gp = EllipseEdgeEffect::Create(color,
+                                                        isStrokeOnly &&
                                                         innerXRadius > 0 && innerYRadius > 0);
 
     drawState->setGeometryProcessor(gp)->unref();
@@ -748,6 +752,7 @@
 
 bool GrOvalRenderer::drawDIEllipse(GrDrawTarget* target,
                                    GrDrawState* drawState,
+                                   GrColor color,
                                    const GrContext* context,
                                    bool useCoverageAA,
                                    const SkRect& ellipse,
@@ -804,7 +809,7 @@
     SkScalar innerRatioX = SkScalarDiv(xRadius, innerXRadius);
     SkScalar innerRatioY = SkScalarDiv(yRadius, innerYRadius);
 
-    GrGeometryProcessor* gp = DIEllipseEdgeEffect::Create(mode);
+    GrGeometryProcessor* gp = DIEllipseEdgeEffect::Create(color, mode);
 
     drawState->setGeometryProcessor(gp)->unref();
 
@@ -905,13 +910,14 @@
 
 bool GrOvalRenderer::drawDRRect(GrDrawTarget* target,
                                 GrDrawState* drawState,
+                                GrColor color,
                                 GrContext* context,
                                 bool useAA,
                                 const SkRRect& origOuter,
                                 const SkRRect& origInner) {
     bool applyAA = useAA &&
                    !drawState->getRenderTarget()->isMultisampled() &&
-                   drawState->couldApplyCoverage(*target->caps());
+                   drawState->canUseFracCoveragePrimProc(color, *target->caps());
     GrDrawState::AutoRestoreEffects are;
     if (!origInner.isEmpty()) {
         SkTCopyOnFirstWrite<SkRRect> inner(origInner);
@@ -923,6 +929,7 @@
         GrPrimitiveEdgeType edgeType = applyAA ?
                 kInverseFillAA_GrProcessorEdgeType :
                 kInverseFillBW_GrProcessorEdgeType;
+        // TODO this needs to be a geometry processor
         GrFragmentProcessor* fp = GrRRectEffect::Create(edgeType, *inner);
         if (NULL == fp) {
             return false;
@@ -932,7 +939,7 @@
     }
 
     SkStrokeRec fillRec(SkStrokeRec::kFill_InitStyle);
-    if (this->drawRRect(target, drawState, context, useAA, origOuter, fillRec)) {
+    if (this->drawRRect(target, drawState, color, context, useAA, origOuter, fillRec)) {
         return true;
     }
 
@@ -961,23 +968,24 @@
     if (applyAA) {
         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
     }
-    target->drawRect(drawState, bounds, NULL, NULL);
+    target->drawRect(drawState, color, bounds, NULL, NULL);
     return true;
 }
 
 bool GrOvalRenderer::drawRRect(GrDrawTarget* target,
                                GrDrawState* drawState,
+                               GrColor color,
                                GrContext* context,
                                bool useAA,
                                const SkRRect& rrect,
                                const SkStrokeRec& stroke) {
     if (rrect.isOval()) {
-        return this->drawOval(target, drawState, context, useAA, rrect.getBounds(), stroke);
+        return this->drawOval(target, drawState, color, context, useAA, rrect.getBounds(), stroke);
     }
 
     bool useCoverageAA = useAA &&
         !drawState->getRenderTarget()->isMultisampled() &&
-        drawState->couldApplyCoverage(*target->caps());
+        drawState->canUseFracCoveragePrimProc(color, *target->caps());
 
     // only anti-aliased rrects for now
     if (!useCoverageAA) {
@@ -1069,7 +1077,7 @@
 
         isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
 
-        GrGeometryProcessor* effect = CircleEdgeEffect::Create(isStrokeOnly);
+        GrGeometryProcessor* effect = CircleEdgeEffect::Create(color, isStrokeOnly);
         drawState->setGeometryProcessor(effect)->unref();
 
         GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(),  0);
@@ -1171,7 +1179,7 @@
 
         isStrokeOnly = (isStrokeOnly && innerXRadius >= 0 && innerYRadius >= 0);
 
-        GrGeometryProcessor* effect = EllipseEdgeEffect::Create(isStrokeOnly);
+        GrGeometryProcessor* effect = EllipseEdgeEffect::Create(color, isStrokeOnly);
         drawState->setGeometryProcessor(effect)->unref();
 
         GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStride(),  0);
diff --git a/src/gpu/GrOvalRenderer.h b/src/gpu/GrOvalRenderer.h
index abad623..85a9354 100644
--- a/src/gpu/GrOvalRenderer.h
+++ b/src/gpu/GrOvalRenderer.h
@@ -33,18 +33,21 @@
 
     bool drawOval(GrDrawTarget*,
                   GrDrawState*,
+                  GrColor,
                   const GrContext*,
                   bool useAA,
                   const SkRect& oval,
                   const SkStrokeRec& stroke);
     bool drawRRect(GrDrawTarget*,
                    GrDrawState*,
+                   GrColor,
                    GrContext*,
                    bool useAA,
                    const SkRRect& rrect,
                    const SkStrokeRec& stroke);
     bool drawDRRect(GrDrawTarget* target,
                     GrDrawState*,
+                    GrColor,
                     GrContext* context,
                     bool useAA,
                     const SkRRect& outer,
@@ -53,18 +56,21 @@
 private:
     bool drawEllipse(GrDrawTarget* target,
                      GrDrawState*,
+                     GrColor,
                      const GrContext* context,
                      bool useCoverageAA,
                      const SkRect& ellipse,
                      const SkStrokeRec& stroke);
     bool drawDIEllipse(GrDrawTarget* target,
                        GrDrawState*,
+                       GrColor,
                        const GrContext* context,
                        bool useCoverageAA,
                        const SkRect& ellipse,
                        const SkStrokeRec& stroke);
     void drawCircle(GrDrawTarget* target,
                     GrDrawState*,
+                    GrColor,
                     const GrContext* context,
                     bool useCoverageAA,
                     const SkRect& circle,
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index 8f2d465..f4276b4 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -117,6 +117,7 @@
      */
     bool drawPath(GrDrawTarget* target,
                   GrDrawState* ds,
+                  GrColor color,
                   const SkPath& path,
                   const SkStrokeRec& stroke,
                   bool antiAlias) {
@@ -125,7 +126,7 @@
         SkASSERT(ds->getStencil().isDisabled() ||
                  kNoRestriction_StencilSupport == this->getStencilSupport(target, ds, path,
                                                                           stroke));
-        return this->onDrawPath(target, ds, path, stroke, antiAlias);
+        return this->onDrawPath(target, ds, color, path, stroke, antiAlias);
     }
 
     /**
@@ -175,6 +176,7 @@
      */
     virtual bool onDrawPath(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkPath&,
                             const SkStrokeRec&,
                             bool antiAlias) = 0;
@@ -196,7 +198,7 @@
                                      0xffff);
         drawState->setStencil(kIncrementStencil);
         drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
-        this->drawPath(target, drawState, path, stroke, false);
+        this->drawPath(target, drawState, GrColor_WHITE,  path, stroke, false);
     }
 
     // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 96dd9ea..ccd4d7f 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -9,6 +9,7 @@
 #include "GrContext.h"
 #include "GrCoordTransform.h"
 #include "GrGeometryData.h"
+#include "GrGeometryProcessor.h"
 #include "GrInvariantOutput.h"
 #include "GrMemoryPool.h"
 #include "GrXferProcessor.h"
@@ -170,6 +171,12 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
+void GrGeometryProcessor::computeInvariantColor(GrInvariantOutput* intout) const {
+
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
 /*
  * GrGeometryData shares the same pool so it lives in this file too
  */
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index 590a040..142cd92 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -348,6 +348,7 @@
 void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
                                               GrDrawTarget* target,
                                               GrDrawState* drawState,
+                                              GrColor color,
                                               const SkIRect& rect) {
     GrDrawState::AutoViewMatrixRestore avmr;
     if (!avmr.setIdentity(drawState)) {
@@ -375,5 +376,5 @@
                                                        GrTextureParams::kNone_FilterMode,
                                                        kPosition_GrCoordSet))->unref();
 
-    target->drawSimpleRect(drawState, dstRect);
+    target->drawSimpleRect(drawState, color, dstRect);
 }
diff --git a/src/gpu/GrSWMaskHelper.h b/src/gpu/GrSWMaskHelper.h
index 54a3897..1eef46e 100644
--- a/src/gpu/GrSWMaskHelper.h
+++ b/src/gpu/GrSWMaskHelper.h
@@ -93,6 +93,7 @@
     static void DrawToTargetWithPathMask(GrTexture* texture,
                                          GrDrawTarget* target,
                                          GrDrawState* drawState,
+                                         GrColor,
                                          const SkIRect& rect);
 
 private:
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 9a9cf32..157e81d 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -78,6 +78,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 void draw_around_inv_path(GrDrawTarget* target,
                           GrDrawState* drawState,
+                          GrColor color,
                           const SkIRect& devClipBounds,
                           const SkIRect& devPathBounds) {
     GrDrawState::AutoViewMatrixRestore avmr;
@@ -88,22 +89,22 @@
     if (devClipBounds.fTop < devPathBounds.fTop) {
         rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
                   devClipBounds.fRight, devPathBounds.fTop);
-        target->drawSimpleRect(drawState, rect);
+        target->drawSimpleRect(drawState, color, rect);
     }
     if (devClipBounds.fLeft < devPathBounds.fLeft) {
         rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
                   devPathBounds.fLeft, devPathBounds.fBottom);
-        target->drawSimpleRect(drawState, rect);
+        target->drawSimpleRect(drawState, color, rect);
     }
     if (devClipBounds.fRight > devPathBounds.fRight) {
         rect.iset(devPathBounds.fRight, devPathBounds.fTop,
                   devClipBounds.fRight, devPathBounds.fBottom);
-        target->drawSimpleRect(drawState, rect);
+        target->drawSimpleRect(drawState, color, rect);
     }
     if (devClipBounds.fBottom > devPathBounds.fBottom) {
         rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
                   devClipBounds.fRight, devClipBounds.fBottom);
-        target->drawSimpleRect(drawState, rect);
+        target->drawSimpleRect(drawState, color, rect);
     }
 }
 
@@ -113,6 +114,7 @@
 // return true on success; false on failure
 bool GrSoftwarePathRenderer::onDrawPath(GrDrawTarget* target,
                                         GrDrawState* drawState,
+                                        GrColor color,
                                         const SkPath& path,
                                         const SkStrokeRec& stroke,
                                         bool antiAlias) {
@@ -127,7 +129,7 @@
     if (!get_path_and_clip_bounds(target, drawState, path, vm,
                                   &devPathBounds, &devClipBounds)) {
         if (path.isInverseFillType()) {
-            draw_around_inv_path(target, drawState, devClipBounds, devPathBounds);
+            draw_around_inv_path(target, drawState, color, devClipBounds, devPathBounds);
         }
         return true;
     }
@@ -141,10 +143,10 @@
     }
 
     GrDrawState copy = *drawState;
-    GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, &copy, devPathBounds);
+    GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, &copy, color, devPathBounds);
 
     if (path.isInverseFillType()) {
-        draw_around_inv_path(target, drawState, devClipBounds, devPathBounds);
+        draw_around_inv_path(target, drawState, color, devClipBounds, devPathBounds);
     }
 
     return true;
diff --git a/src/gpu/GrSoftwarePathRenderer.h b/src/gpu/GrSoftwarePathRenderer.h
index 620e00b..226cb35 100644
--- a/src/gpu/GrSoftwarePathRenderer.h
+++ b/src/gpu/GrSoftwarePathRenderer.h
@@ -36,6 +36,7 @@
 
     virtual bool onDrawPath(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkPath&,
                             const SkStrokeRec&,
                             bool antiAlias) SK_OVERRIDE;
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index 022ed94..e7c4fc8 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -91,6 +91,7 @@
 
 bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target,
                                                GrDrawState* drawState,
+                                               GrColor color,
                                                const SkPath& path,
                                                const SkStrokeRec& stroke,
                                                bool antiAlias) {
@@ -133,7 +134,7 @@
         } else {
             avmr.setIdentity(drawState);
         }
-        target->drawSimpleRect(drawState, bounds);
+        target->drawSimpleRect(drawState, color, bounds);
     } else {
         GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
             kZero_StencilOp,
@@ -144,7 +145,7 @@
             0xffff);
 
         drawState->setStencil(kStencilPass);
-        target->drawPath(drawState, p, convert_skpath_filltype(path.getFillType()));
+        target->drawPath(drawState, color, p, convert_skpath_filltype(path.getFillType()));
     }
 
     drawState->stencil()->setDisabled();
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.h b/src/gpu/GrStencilAndCoverPathRenderer.h
index dacdcd0..be04c4a 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.h
+++ b/src/gpu/GrStencilAndCoverPathRenderer.h
@@ -39,6 +39,7 @@
 
     virtual bool onDrawPath(GrDrawTarget*,
                             GrDrawState*,
+                            GrColor,
                             const SkPath&,
                             const SkStrokeRec&,
                             bool antiAlias) SK_OVERRIDE;
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index a8653fe..bf1e58d 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -399,7 +399,7 @@
 
 void GrStencilAndCoverTextContext::flush() {
     if (fQueuedGlyphCount > 0) {
-        fDrawTarget->drawPaths(&fDrawState, fGlyphs,
+        fDrawTarget->drawPaths(&fDrawState, fPaint.getColor(), fGlyphs,
                                fGlyphIndices, GrPathRange::kU16_PathIndexType,
                                get_xy_scalar_array(fGlyphPositions),
                                GrPathRendering::kTranslate_PathTransformType,
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 5abd293..6ad1537 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -139,8 +139,8 @@
     return SkNEW_ARGS(GrGLConicEffect, (*this, bt));
 }
 
-GrConicEffect::GrConicEffect(GrPrimitiveEdgeType edgeType)
-    : fEdgeType(edgeType) {
+GrConicEffect::GrConicEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType)
+    : INHERITED(color, coverage), fEdgeType(edgeType) {
     this->initClassID<GrConicEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInConicCoeffs = &this->addVertexAttrib(GrAttribute("inConicCoeffs",
@@ -164,7 +164,7 @@
     do {
         GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
                                                     random->nextULessThan(kGrProcessorEdgeTypeCnt));
-        gp = GrConicEffect::Create(edgeType, caps);
+        gp = GrConicEffect::Create(GrRandomColor(random), edgeType, caps);
     } while (NULL == gp);
     return gp;
 }
@@ -286,8 +286,8 @@
     return SkNEW_ARGS(GrGLQuadEffect, (*this, bt));
 }
 
-GrQuadEffect::GrQuadEffect(GrPrimitiveEdgeType edgeType)
-    : fEdgeType(edgeType) {
+GrQuadEffect::GrQuadEffect(GrColor color, uint8_t coverage, GrPrimitiveEdgeType edgeType)
+    : INHERITED(color, coverage), fEdgeType(edgeType) {
     this->initClassID<GrQuadEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInHairQuadEdge = &this->addVertexAttrib(GrAttribute("inHairQuadEdge",
@@ -311,7 +311,7 @@
     do {
         GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
                 random->nextULessThan(kGrProcessorEdgeTypeCnt));
-        gp = GrQuadEffect::Create(edgeType, caps);
+        gp = GrQuadEffect::Create(GrRandomColor(random), edgeType, caps);
     } while (NULL == gp);
     return gp;
 }
@@ -474,8 +474,8 @@
     return SkNEW_ARGS(GrGLCubicEffect, (*this, bt));
 }
 
-GrCubicEffect::GrCubicEffect(GrPrimitiveEdgeType edgeType)
-    : fEdgeType(edgeType) {
+GrCubicEffect::GrCubicEffect(GrColor color, GrPrimitiveEdgeType edgeType)
+    : INHERITED(color), fEdgeType(edgeType) {
     this->initClassID<GrCubicEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInCubicCoeffs = &this->addVertexAttrib(GrAttribute("inCubicCoeffs",
@@ -499,7 +499,7 @@
     do {
         GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(
                                                     random->nextULessThan(kGrProcessorEdgeTypeCnt));
-        gp = GrCubicEffect::Create(edgeType, caps);
+        gp = GrCubicEffect::Create(GrRandomColor(random), edgeType, caps);
     } while (NULL == gp);
     return gp;
 }
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index dfab3a9..a9cbeb0 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -58,21 +58,24 @@
 
 class GrConicEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
-                                       const GrDrawTargetCaps& caps) {
+    static GrGeometryProcessor* Create(GrColor color,
+                                       const GrPrimitiveEdgeType edgeType,
+                                       const GrDrawTargetCaps& caps,
+                                       uint8_t coverage = 0xff) {
         switch (edgeType) {
             case kFillAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrConicEffect, (kFillAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrConicEffect, (color, coverage, kFillAA_GrProcessorEdgeType));
             case kHairlineAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrConicEffect, (kHairlineAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrConicEffect, (color, coverage,
+                                                  kHairlineAA_GrProcessorEdgeType));
             case kFillBW_GrProcessorEdgeType:
-                return SkNEW_ARGS(GrConicEffect, (kFillBW_GrProcessorEdgeType));;
+                return SkNEW_ARGS(GrConicEffect, (color, coverage, kFillBW_GrProcessorEdgeType));;
             default:
                 return NULL;
         }
@@ -95,7 +98,7 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    GrConicEffect(GrPrimitiveEdgeType);
+    GrConicEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
@@ -125,21 +128,23 @@
 
 class GrQuadEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
-                                       const GrDrawTargetCaps& caps) {
+    static GrGeometryProcessor* Create(GrColor color,
+                                       const GrPrimitiveEdgeType edgeType,
+                                       const GrDrawTargetCaps& caps,
+                                       uint8_t coverage = 0xff) {
         switch (edgeType) {
             case kFillAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrQuadEffect, (kFillAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kFillAA_GrProcessorEdgeType));
             case kHairlineAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrQuadEffect, (kHairlineAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kHairlineAA_GrProcessorEdgeType));
             case kFillBW_GrProcessorEdgeType:
-                return SkNEW_ARGS(GrQuadEffect, (kFillBW_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrQuadEffect, (color, coverage, kFillBW_GrProcessorEdgeType));
             default:
                 return NULL;
         }
@@ -162,7 +167,7 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    GrQuadEffect(GrPrimitiveEdgeType);
+    GrQuadEffect(GrColor, uint8_t coverage, GrPrimitiveEdgeType);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
@@ -194,21 +199,22 @@
 
 class GrCubicEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(const GrPrimitiveEdgeType edgeType,
+    static GrGeometryProcessor* Create(GrColor color,
+                                       const GrPrimitiveEdgeType edgeType,
                                        const GrDrawTargetCaps& caps) {
         switch (edgeType) {
             case kFillAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrCubicEffect, (kFillAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrCubicEffect, (color, kFillAA_GrProcessorEdgeType));
             case kHairlineAA_GrProcessorEdgeType:
                 if (!caps.shaderDerivativeSupport()) {
                     return NULL;
                 }
-                return SkNEW_ARGS(GrCubicEffect, (kHairlineAA_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrCubicEffect, (color, kHairlineAA_GrProcessorEdgeType));
             case kFillBW_GrProcessorEdgeType:
-                return SkNEW_ARGS(GrCubicEffect, (kFillBW_GrProcessorEdgeType));
+                return SkNEW_ARGS(GrCubicEffect, (color, kFillBW_GrProcessorEdgeType));
             default:
                 return NULL;
         }
@@ -231,7 +237,7 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    GrCubicEffect(GrPrimitiveEdgeType);
+    GrCubicEffect(GrColor, GrPrimitiveEdgeType);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 6eaaf30..1578fd8 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -65,9 +65,9 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrTexture* texture, const GrTextureParams& params,
-                                         bool useColorAttrib)
-    : fTextureAccess(texture, params), fInColor(NULL) {
+GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, GrTexture* texture,
+                                         const GrTextureParams& params, bool useColorAttrib)
+    : INHERITED(color), fTextureAccess(texture, params), fInColor(NULL) {
     this->initClassID<GrBitmapTextGeoProc>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     if (useColorAttrib) {
@@ -128,5 +128,6 @@
     GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
                                                            GrTextureParams::kNone_FilterMode);
 
-    return GrBitmapTextGeoProc::Create(textures[texIdx], params, random->nextBool());
+    return GrBitmapTextGeoProc::Create(GrRandomColor(random), textures[texIdx], params,
+                                       random->nextBool());
 }
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index ecbf4f9..ce235ae 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -21,9 +21,9 @@
  */
 class GrBitmapTextGeoProc : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(GrTexture* tex, const GrTextureParams& p,
+    static GrGeometryProcessor* Create(GrColor color, GrTexture* tex, const GrTextureParams& p,
                                        bool useColorAttrib) {
-        return SkNEW_ARGS(GrBitmapTextGeoProc, (tex, p, useColorAttrib));
+        return SkNEW_ARGS(GrBitmapTextGeoProc, (color, tex, p, useColorAttrib));
     }
 
     virtual ~GrBitmapTextGeoProc() {}
@@ -41,7 +41,7 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    GrBitmapTextGeoProc(GrTexture* texture, const GrTextureParams& params, bool useColorAttrib);
+    GrBitmapTextGeoProc(GrColor, GrTexture* texture, const GrTextureParams& params, bool useColorAttrib);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 53485f6..b59b2a6 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -165,7 +165,7 @@
 }
 
 bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, GrDrawState* drawState,
-                                   const SkPoint pts[2], const GrPaint& paint,
+                                   GrColor color, const SkPoint pts[2], const GrPaint& paint,
                                    const GrStrokeInfo& strokeInfo, const SkMatrix& vm) {
 
     if (!can_fast_path_dash(pts, strokeInfo, *target, *drawState, vm)) {
@@ -347,10 +347,10 @@
         bool isRoundCap = SkPaint::kRound_Cap == cap;
         GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap :
                                                         GrDashingEffect::kNonRound_DashCap;
-        gp = GrDashingEffect::Create(edgeType, devInfo, strokeWidth, capType);
+        gp = GrDashingEffect::Create(color, edgeType, devInfo, strokeWidth, capType);
     } else {
         // Set up the vertex data for the line and start/end dashes
-        gp = GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType);
+        gp = GrDefaultGeoProcFactory::Create(color, GrDefaultGeoProcFactory::kPosition_GPType);
     }
 
     drawState->setGeometryProcessor(gp)->unref();
@@ -456,7 +456,8 @@
 public:
     typedef SkPathEffect::DashInfo DashInfo;
 
-    static GrGeometryProcessor* Create(GrPrimitiveEdgeType edgeType,
+    static GrGeometryProcessor* Create(GrColor,
+                                       GrPrimitiveEdgeType edgeType,
                                        const DashInfo& info,
                                        SkScalar radius);
 
@@ -483,7 +484,8 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker&) const SK_OVERRIDE;
 
 private:
-    DashingCircleEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info, SkScalar radius);
+    DashingCircleEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
+                        SkScalar radius);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
@@ -599,13 +601,15 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-GrGeometryProcessor* DashingCircleEffect::Create(GrPrimitiveEdgeType edgeType, const DashInfo& info,
+GrGeometryProcessor* DashingCircleEffect::Create(GrColor color,
+                                                 GrPrimitiveEdgeType edgeType,
+                                                 const DashInfo& info,
                                                  SkScalar radius) {
     if (info.fCount != 2 || info.fIntervals[0] != 0) {
         return NULL;
     }
 
-    return SkNEW_ARGS(DashingCircleEffect, (edgeType, info, radius));
+    return SkNEW_ARGS(DashingCircleEffect, (color, edgeType, info, radius));
 }
 
 DashingCircleEffect::~DashingCircleEffect() {}
@@ -624,9 +628,11 @@
     return SkNEW_ARGS(GLDashingCircleEffect, (*this, bt));
 }
 
-DashingCircleEffect::DashingCircleEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info,
+DashingCircleEffect::DashingCircleEffect(GrColor color,
+                                         GrPrimitiveEdgeType edgeType,
+                                         const DashInfo& info,
                                          SkScalar radius)
-    : fEdgeType(edgeType) {
+    : INHERITED(color), fEdgeType(edgeType) {
     this->initClassID<DashingCircleEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInCoord = &this->addVertexAttrib(GrAttribute("inCoord", kVec2f_GrVertexAttribType));
@@ -662,7 +668,7 @@
     info.fIntervals[1] = random->nextRangeScalar(0, 10.f);
     info.fPhase = random->nextRangeScalar(0, info.fIntervals[1]);
 
-    return DashingCircleEffect::Create(edgeType, info, strokeWidth);
+    return DashingCircleEffect::Create(GrRandomColor(random), edgeType, info, strokeWidth);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -682,7 +688,8 @@
 public:
     typedef SkPathEffect::DashInfo DashInfo;
 
-    static GrGeometryProcessor* Create(GrPrimitiveEdgeType edgeType,
+    static GrGeometryProcessor* Create(GrColor,
+                                       GrPrimitiveEdgeType edgeType,
                                        const DashInfo& info,
                                        SkScalar strokeWidth);
 
@@ -707,7 +714,8 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    DashingLineEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info, SkScalar strokeWidth);
+    DashingLineEffect(GrColor, GrPrimitiveEdgeType edgeType, const DashInfo& info,
+                      SkScalar strokeWidth);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
 
@@ -836,14 +844,15 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-GrGeometryProcessor* DashingLineEffect::Create(GrPrimitiveEdgeType edgeType,
+GrGeometryProcessor* DashingLineEffect::Create(GrColor color,
+                                               GrPrimitiveEdgeType edgeType,
                                                const DashInfo& info,
                                                SkScalar strokeWidth) {
     if (info.fCount != 2) {
         return NULL;
     }
 
-    return SkNEW_ARGS(DashingLineEffect, (edgeType, info, strokeWidth));
+    return SkNEW_ARGS(DashingLineEffect, (color, edgeType, info, strokeWidth));
 }
 
 DashingLineEffect::~DashingLineEffect() {}
@@ -862,9 +871,11 @@
     return SkNEW_ARGS(GLDashingLineEffect, (*this, bt));
 }
 
-DashingLineEffect::DashingLineEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info,
+DashingLineEffect::DashingLineEffect(GrColor color,
+                                     GrPrimitiveEdgeType edgeType,
+                                     const DashInfo& info,
                                      SkScalar strokeWidth)
-    : fEdgeType(edgeType) {
+    : INHERITED(color), fEdgeType(edgeType) {
     this->initClassID<DashingLineEffect>();
     fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
     fInCoord = &this->addVertexAttrib(GrAttribute("inCoord", kVec2f_GrVertexAttribType));
@@ -900,20 +911,21 @@
     info.fIntervals[1] = random->nextRangeScalar(0, 10.f);
     info.fPhase = random->nextRangeScalar(0, info.fIntervals[0] + info.fIntervals[1]);
 
-    return DashingLineEffect::Create(edgeType, info, strokeWidth);
+    return DashingLineEffect::Create(GrRandomColor(random), edgeType, info, strokeWidth);
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
-GrGeometryProcessor* GrDashingEffect::Create(GrPrimitiveEdgeType edgeType,
+GrGeometryProcessor* GrDashingEffect::Create(GrColor color,
+                                             GrPrimitiveEdgeType edgeType,
                                              const SkPathEffect::DashInfo& info,
                                              SkScalar strokeWidth,
                                              GrDashingEffect::DashCap cap) {
     switch (cap) {
         case GrDashingEffect::kRound_DashCap:
-            return DashingCircleEffect::Create(edgeType, info, SkScalarHalf(strokeWidth));
+            return DashingCircleEffect::Create(color, edgeType, info, SkScalarHalf(strokeWidth));
         case GrDashingEffect::kNonRound_DashCap:
-            return DashingLineEffect::Create(edgeType, info, strokeWidth);
+            return DashingLineEffect::Create(color, edgeType, info, strokeWidth);
         default:
             SkFAIL("Unexpected dashed cap.");
     }
diff --git a/src/gpu/effects/GrDashingEffect.h b/src/gpu/effects/GrDashingEffect.h
index 14df1ae..492c690 100644
--- a/src/gpu/effects/GrDashingEffect.h
+++ b/src/gpu/effects/GrDashingEffect.h
@@ -9,6 +9,7 @@
 #ifndef GrDashingEffect_DEFINED
 #define GrDashingEffect_DEFINED
 
+#include "GrColor.h"
 #include "GrTypesPriv.h"
 #include "SkPathEffect.h"
 
@@ -23,7 +24,7 @@
 class SkPath;
 
 namespace GrDashingEffect {
-    bool DrawDashLine(GrGpu*, GrDrawTarget*, GrDrawState*, const SkPoint pts[2],
+    bool DrawDashLine(GrGpu*, GrDrawTarget*, GrDrawState*, GrColor, const SkPoint pts[2],
                       const GrPaint& paint, const GrStrokeInfo& strokeInfo,
                       const SkMatrix& vm);
 
@@ -38,7 +39,8 @@
      * Bounding geometry is rendered and the effect computes coverage based on the fragment's
      * position relative to the dashed line.
      */
-    GrGeometryProcessor* Create(GrPrimitiveEdgeType edgeType,
+    GrGeometryProcessor* Create(GrColor,
+                                GrPrimitiveEdgeType edgeType,
                                 const SkPathEffect::DashInfo& info,
                                 SkScalar strokeWidth,
                                 DashCap cap);
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index eff2ee5..f408d2d 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -165,7 +165,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture,
+GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrColor color,
+                                                           GrTexture* texture,
                                                            const GrTextureParams& params,
 #ifdef SK_GAMMA_APPLY_TO_A8
                                                            GrTexture* gamma,
@@ -173,7 +174,8 @@
                                                            float luminance,
 #endif
                                                            uint32_t flags)
-    : fTextureAccess(texture, params)
+    : INHERITED(color)
+    , fTextureAccess(texture, params)
 #ifdef SK_GAMMA_APPLY_TO_A8
     , fGammaTextureAccess(gamma, gammaParams)
     , fLuminance(luminance)
@@ -249,7 +251,7 @@
                                                             GrTextureParams::kNone_FilterMode);
 #endif
 
-    return GrDistanceFieldTextureEffect::Create(textures[texIdx], params,
+    return GrDistanceFieldTextureEffect::Create(GrRandomColor(random), textures[texIdx], params,
 #ifdef SK_GAMMA_APPLY_TO_A8
                                                 textures[texIdx2], params2,
                                                 random->nextF(),
@@ -378,10 +380,13 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrDistanceFieldNoGammaTextureEffect::GrDistanceFieldNoGammaTextureEffect(GrTexture* texture,
-                                                                    const GrTextureParams& params,
-                                                                    uint32_t flags)
-    : fTextureAccess(texture, params)
+GrDistanceFieldNoGammaTextureEffect::GrDistanceFieldNoGammaTextureEffect(
+        GrColor color,
+        GrTexture* texture,
+        const GrTextureParams& params,
+        uint32_t flags)
+    : INHERITED(color)
+    , fTextureAccess(texture, params)
     , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
     , fInColor(NULL) {
     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
@@ -439,7 +444,8 @@
     GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode 
                                                          : GrTextureParams::kNone_FilterMode);
 
-    return GrDistanceFieldNoGammaTextureEffect::Create(textures[texIdx], params,
+    return GrDistanceFieldNoGammaTextureEffect::Create(GrRandomColor(random), textures[texIdx],
+                                                       params,
         random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0);
 }
 
@@ -634,11 +640,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
+                                                  GrColor color,
                                                   GrTexture* texture, const GrTextureParams& params,
                                                   GrTexture* gamma, const GrTextureParams& gParams,
                                                   SkColor textColor,
                                                   uint32_t flags)
-    : fTextureAccess(texture, params)
+    : INHERITED(color)
+    , fTextureAccess(texture, params)
     , fGammaTextureAccess(gamma, gParams)
     , fTextColor(textColor)
     , fFlags(flags & kLCD_DistanceFieldEffectMask){
@@ -705,7 +713,7 @@
     uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
     flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
     flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
-    return GrDistanceFieldLCDTextureEffect::Create(textures[texIdx], params,
+    return GrDistanceFieldLCDTextureEffect::Create(GrRandomColor(random), textures[texIdx], params,
                                                    textures[texIdx2], params2,
                                                    textColor,
                                                    flags);
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.h b/src/gpu/effects/GrDistanceFieldTextureEffect.h
index 1dfa1b4..f0f7e3b 100644
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.h
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.h
@@ -47,16 +47,16 @@
 class GrDistanceFieldTextureEffect : public GrGeometryProcessor {
 public:
 #ifdef SK_GAMMA_APPLY_TO_A8
-    static GrGeometryProcessor* Create(GrTexture* tex, const GrTextureParams& params,
+    static GrGeometryProcessor* Create(GrColor color, GrTexture* tex, const GrTextureParams& params,
                                        GrTexture* gamma, const GrTextureParams& gammaParams,
                                        float lum, uint32_t flags) {
-       return SkNEW_ARGS(GrDistanceFieldTextureEffect, (tex, params, gamma, gammaParams, lum,
+       return SkNEW_ARGS(GrDistanceFieldTextureEffect, (color, tex, params, gamma, gammaParams, lum,
                                                         flags));
     }
 #else
-    static GrGeometryProcessor* Create(GrTexture* tex, const GrTextureParams& params,
+    static GrGeometryProcessor* Create(GrColor color, GrTexture* tex, const GrTextureParams& params,
                                        uint32_t flags) {
-        return  SkNEW_ARGS(GrDistanceFieldTextureEffect, (tex, params, flags));
+        return  SkNEW_ARGS(GrDistanceFieldTextureEffect, (color, tex, params, flags));
     }
 #endif
 
@@ -79,7 +79,7 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    GrDistanceFieldTextureEffect(GrTexture* texture, const GrTextureParams& params,
+    GrDistanceFieldTextureEffect(GrColor, GrTexture* texture, const GrTextureParams& params,
 #ifdef SK_GAMMA_APPLY_TO_A8
                                  GrTexture* gamma, const GrTextureParams& gammaParams, float lum,
 #endif
@@ -113,9 +113,9 @@
 */
 class GrDistanceFieldNoGammaTextureEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(GrTexture* tex, const GrTextureParams& params,
+    static GrGeometryProcessor* Create(GrColor color, GrTexture* tex, const GrTextureParams& params,
                                        uint32_t flags) {
-        return SkNEW_ARGS(GrDistanceFieldNoGammaTextureEffect, (tex, params, flags));
+        return SkNEW_ARGS(GrDistanceFieldNoGammaTextureEffect, (color, tex, params, flags));
     }
 
     virtual ~GrDistanceFieldNoGammaTextureEffect() {}
@@ -134,7 +134,7 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    GrDistanceFieldNoGammaTextureEffect(GrTexture* texture, const GrTextureParams& params,
+    GrDistanceFieldNoGammaTextureEffect(GrColor, GrTexture* texture, const GrTextureParams& params,
                                         uint32_t flags);
 
     virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE;
@@ -160,11 +160,11 @@
  */
 class GrDistanceFieldLCDTextureEffect : public GrGeometryProcessor {
 public:
-    static GrGeometryProcessor* Create(GrTexture* tex, const GrTextureParams& params,
+    static GrGeometryProcessor* Create(GrColor color, GrTexture* tex, const GrTextureParams& params,
                                        GrTexture* gamma, const GrTextureParams& gammaParams,
                                        SkColor textColor, uint32_t flags) {
         return SkNEW_ARGS(GrDistanceFieldLCDTextureEffect,
-                          (tex, params, gamma, gammaParams, textColor, flags));
+                          (color, tex, params, gamma, gammaParams, textColor, flags));
     }
 
     virtual ~GrDistanceFieldLCDTextureEffect() {}
@@ -183,7 +183,7 @@
     virtual GrGLGeometryProcessor* createGLInstance(const GrBatchTracker& bt) const SK_OVERRIDE;
 
 private:
-    GrDistanceFieldLCDTextureEffect(GrTexture* texture, const GrTextureParams& params,
+    GrDistanceFieldLCDTextureEffect(GrColor, GrTexture* texture, const GrTextureParams& params,
                                     GrTexture* gamma, const GrTextureParams& gammaParams,
                                     SkColor textColor,
                                     uint32_t flags);
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 56707a0..253e4ae 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -181,68 +181,6 @@
     }
 }
 
-// There are only a few cases of random colors which interest us
-enum ColorMode {
-    kAllOnes_ColorMode,
-    kAllZeros_ColorMode,
-    kAlphaOne_ColorMode,
-    kRandom_ColorMode,
-    kLast_ColorMode = kRandom_ColorMode
-};
-
-static void set_random_color(GrDrawState* ds, SkRandom* random) {
-    ColorMode colorMode = ColorMode(random->nextULessThan(kLast_ColorMode + 1));
-    GrColor color;
-    switch (colorMode) {
-        case kAllOnes_ColorMode:
-            color = GrColorPackRGBA(0xFF, 0xFF, 0xFF, 0xFF);
-            break;
-        case kAllZeros_ColorMode:
-            color = GrColorPackRGBA(0, 0, 0, 0);
-            break;
-        case kAlphaOne_ColorMode:
-            color = GrColorPackRGBA(random->nextULessThan(256),
-                                    random->nextULessThan(256),
-                                    random->nextULessThan(256),
-                                    0xFF);
-            break;
-        case kRandom_ColorMode:
-            uint8_t alpha = random->nextULessThan(256);
-            color = GrColorPackRGBA(random->nextRangeU(0, alpha),
-                                    random->nextRangeU(0, alpha),
-                                    random->nextRangeU(0, alpha),
-                                    alpha);
-            break;
-    }
-    GrColorIsPMAssert(color);
-    ds->setColor(color);
-}
-
-// There are only a few cases of random coverages which interest us
-enum CoverageMode {
-    kZero_CoverageMode,
-    kFF_CoverageMode,
-    kRandom_CoverageMode,
-    kLast_CoverageMode = kRandom_CoverageMode
-};
-
-static void set_random_coverage(GrDrawState* ds, SkRandom* random) {
-    CoverageMode coverageMode = CoverageMode(random->nextULessThan(kLast_CoverageMode + 1));
-    uint8_t coverage;
-    switch (coverageMode) {
-        case kZero_CoverageMode:
-            coverage = 0;
-            break;
-        case kFF_CoverageMode:
-            coverage = 0xFF;
-            break;
-        case kRandom_CoverageMode:
-            coverage = uint8_t(random->nextU());
-            break;
-    }
-    ds->setCoverage(coverage);
-}
-
 static void set_random_hints(GrDrawState* ds, SkRandom* random) {
     for (int i = 1; i <= GrDrawState::kLast_Hint; i <<= 1) {
         ds->setHint(GrDrawState::Hints(i), random->nextBool());
@@ -372,8 +310,6 @@
                                          usePathRendering,
                                          &random,
                                          dummyTextures);
-        set_random_color(&ds, &random);
-        set_random_coverage(&ds, &random);
         set_random_hints(&ds, &random);
         set_random_state(&ds, &random);
         set_random_blend_func(&ds, &random);
@@ -381,14 +317,19 @@
 
         GrDeviceCoordTexture dstCopy;
 
-        if (!this->setupDstReadIfNecessary(&ds, &dstCopy, NULL)) {
+        // TODO take color off the PP when its installed
+        GrColor color = ds.hasGeometryProcessor() ? ds.getGeometryProcessor()->getColor() :
+                                                    GrColor_WHITE;
+        uint8_t coverage = ds.hasGeometryProcessor() ? ds.getGeometryProcessor()->getCoverage() :
+                                                       0xff;
+        if (!this->setupDstReadIfNecessary(&ds, color, coverage, &dstCopy, NULL)) {
             SkDebugf("Couldn't setup dst read texture");
             return false;
         }
 
         // create optimized draw state, setup readDst texture if required, and build a descriptor
         // and program.  ODS creation can fail, so we have to check
-        GrOptDrawState ods(ds, *gpu->caps(), scissor, &dstCopy, drawType);
+        GrOptDrawState ods(ds, color, coverage, *gpu->caps(), scissor, &dstCopy, drawType);
         if (ods.mustSkip()) {
             continue;
         }