Create helper functions to use in computeInvariantOutput calls

BUG=skia:

Review URL: https://codereview.chromium.org/643743003
diff --git a/include/gpu/GrProcessor.h b/include/gpu/GrProcessor.h
index a5c8341..6b1d1e3 100644
--- a/include/gpu/GrProcessor.h
+++ b/include/gpu/GrProcessor.h
@@ -38,12 +38,58 @@
     virtual ~GrProcessor();
 
     struct InvariantOutput{
-        GrColor fColor;
-        uint32_t fValidFlags;
-        bool fIsSingleComponent;
-
         InvariantOutput() : fColor(0), fValidFlags(0), fIsSingleComponent(false) {}
 
+        void mulByUnknownOpaqueColor() {
+            if (this->isOpaque()) {
+                fValidFlags = kA_GrColorComponentFlag;
+                fIsSingleComponent = false;
+            } else {
+                // Since the current state is not opaque we no longer care if the color being
+                // multiplied is opaque.
+                this->mulByUnknownColor(); 
+            }
+        }
+
+        void mulByUnknownColor() {
+            if (this->hasZeroAlpha()) {
+                this->setToTransparentBlack();
+            } else {
+                this->setToUnknown();
+            }
+        }
+
+        void mulByUnknownAlpha() {
+            if (this->hasZeroAlpha()) {
+                this->setToTransparentBlack();
+            } else {
+                // We don't need to change fIsSingleComponent in this case
+                fValidFlags = 0;
+            }
+        }
+
+        void invalidateComponents(uint8_t invalidateFlags) {
+            fValidFlags &= ~invalidateFlags;
+            fIsSingleComponent = false;
+        }
+
+        void setToTransparentBlack() {
+            fValidFlags = kRGBA_GrColorComponentFlags;
+            fColor = 0;
+            fIsSingleComponent = true;
+        }
+
+        void setToOther(uint8_t validFlags, GrColor color) {
+            fValidFlags = validFlags;
+            fColor = color;
+            fIsSingleComponent = false;
+        }
+
+        void setToUnknown() {
+            fValidFlags = 0;
+            fIsSingleComponent = false;
+        }
+
         bool isOpaque() const {
             return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor));
         }
@@ -52,6 +98,9 @@
             return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor);
         }
 
+        GrColor color() const { return fColor; }
+        uint8_t validFlags() const { return fValidFlags; }
+
         /**
          * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the
          * same. If the flags are all set then all color components must be equal.
@@ -59,12 +108,26 @@
         SkDEBUGCODE(void validate() const;)
 
     private:
-        SkDEBUGCODE(bool colorComponentsAllEqual() const;)
+        bool hasZeroAlpha() const {
+            return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor));
+        }
 
+        SkDEBUGCODE(bool colorComponentsAllEqual() const;)
         /**
          * If alpha is valid, check that any valid R,G,B values are <= A
          */
         SkDEBUGCODE(bool validPreMulColor() const;)
+
+        // Friended class that have "controller" code which loop over stages calling
+        // computeInvarianteOutput(). These controllers may need to manually adjust the internal
+        // members of InvariantOutput
+        friend class GrDrawState;
+        friend class GrOptDrawState;
+        friend class GrPaint;
+
+        GrColor fColor;
+        uint32_t fValidFlags;
+        bool fIsSingleComponent;
     };
 
     /**
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 5d4b260..7fcdeb8 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -1213,8 +1213,7 @@
     }
     
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->setToUnknown();
     }
 
     SkXfermode::Mode fMode;
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 7215aa8..823c302 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -229,12 +229,11 @@
 }
 
 void AlphaThresholdEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    if (inout->isOpaque() && GrPixelConfigIsOpaque(this->texture(0)->config())) {
-        inout->fValidFlags = kA_GrColorComponentFlag;
+    if (GrPixelConfigIsOpaque(this->texture(0)->config()) && fOuterThreshold >= 1.f) {
+        inout->mulByUnknownOpaqueColor();
     } else {
-        inout->fValidFlags = 0;
+        inout->mulByUnknownColor();
     }
-    inout->fIsSingleComponent = false;
 }
 
 #endif
diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp
index 107c784..7e0ca37 100644
--- a/src/effects/SkArithmeticMode.cpp
+++ b/src/effects/SkArithmeticMode.cpp
@@ -346,8 +346,7 @@
 
 void GrArithmeticEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     // TODO: optimize this
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->setToUnknown();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 79cf7e6..30c7206 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -692,7 +692,7 @@
     OutputRectBlurProfileLookup(fsBuilder, samplers[0], "vert_lookup", profileSizeName, "translatedPos.y", "height", "wh.y");
 
     fsBuilder->codeAppendf("\tfloat final = horiz_lookup * vert_lookup;\n");
-    fsBuilder->codeAppendf("\t%s = src * vec4(final);\n", outputColor );
+    fsBuilder->codeAppendf("\t%s = src * final;\n", outputColor );
 }
 
 void GrGLRectBlurEffect::setData(const GrGLProgramDataManager& pdman,
@@ -766,8 +766,7 @@
 }
 
 void GrRectBlurEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
@@ -930,8 +929,7 @@
 }
 
 void GrRRectBlurEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendFragmentProcessorFactory& GrRRectBlurEffect::getFactory() const {
diff --git a/src/effects/SkColorCubeFilter.cpp b/src/effects/SkColorCubeFilter.cpp
index c94afae..62d3c49 100644
--- a/src/effects/SkColorCubeFilter.cpp
+++ b/src/effects/SkColorCubeFilter.cpp
@@ -264,8 +264,7 @@
 }
 
 void GrColorProfileEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->setToUnknown();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp
index fdce937..333b21a 100644
--- a/src/effects/SkColorFilters.cpp
+++ b/src/effects/SkColorFilters.cpp
@@ -384,17 +384,15 @@
 
 void ModeColorFilterEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     float inputColor[4];
-    GrColorToRGBAFloat(inout->fColor, inputColor);
+    GrColorToRGBAFloat(inout->color(), inputColor);
     float filterColor[4];
     GrColorToRGBAFloat(fColor, filterColor);
     MaskedColorExpr result =
         color_filter_expression(fMode,
                                 MaskedColorExpr(filterColor, kRGBA_GrColorComponentFlags),
-                                MaskedColorExpr(inputColor, inout->fValidFlags));
+                                MaskedColorExpr(inputColor, inout->validFlags()));
 
-    inout->fColor = result.getColor();
-    inout->fValidFlags = result.getValidComponents();
-    inout->fIsSingleComponent = false;
+    inout->setToOther(result.getValidComponents(), result.getColor());
 }
 
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ModeColorFilterEffect);
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index e4d9f52..b3b861a 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -452,23 +452,22 @@
             // If any relevant component of the color to be passed through the matrix is non-const
             // then we can't know the final result.
             if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
-                if (!(inout->fValidFlags & kRGBAFlags[i])) {
-                    inout->fValidFlags = 0;
+                if (!(inout->validFlags() & kRGBAFlags[i])) {
+                    inout->setToUnknown();
                     return;
                 } else {
-                    uint32_t component = (inout->fColor >> kShifts[i]) & 0xFF;
+                    uint32_t component = (inout->color() >> kShifts[i]) & 0xFF;
                     outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
                 }
             }
         }
         outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
-        inout->fValidFlags = kA_GrColorComponentFlag;
         // We pin the color to [0,1]. This would happen to the *final* color output from the frag
         // shader but currently the effect does not pin its own output. So in the case of over/
         // underflow this may deviate from the actual result. Maybe the effect should pin its
         // result if the matrix could over/underflow for any component?
-        inout->fColor = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A;
-        inout->fIsSingleComponent = false;
+        inout->setToOther(kA_GrColorComponentFlag,
+                          static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A);
     }
 
     SkColorMatrix fMatrix;
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index d137fba..59768fc 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -497,8 +497,7 @@
     // and no displacement offset push any texture coordinates out of bounds OR if the constant
     // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
     // not of constant color when a displacement effect is applied.
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->setToUnknown();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index e78fd62..b882456 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -355,8 +355,7 @@
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
         // lighting shaders are complicated. We just throw up our hands.
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownColor();
     }
 
 private:
diff --git a/src/effects/SkLumaColorFilter.cpp b/src/effects/SkLumaColorFilter.cpp
index 1ca3c16..5868f4c 100644
--- a/src/effects/SkLumaColorFilter.cpp
+++ b/src/effects/SkLumaColorFilter.cpp
@@ -114,10 +114,8 @@
     }
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        // The output is always black.
-        inout->fColor = GrColorPackRGBA(0, 0, 0, GrColorUnpackA(inout->fColor));
-        inout->fValidFlags = kRGB_GrColorComponentFlags;
-        inout->fIsSingleComponent = false;
+        // The output is always black. The alpha value for the color passed in is arbitrary.
+        inout->setToOther(kRGB_GrColorComponentFlags, GrColorPackRGBA(0, 0, 0, 0));
     }
 };
 
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index 97e9068..5199ec3 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -229,7 +229,6 @@
 
 void GrMagnifierEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     this->updateInvariantOutputForModulation(inout);
-    inout->fIsSingleComponent = false;
 }
 
 #endif
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 8b6808d..3e3dbe4 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -460,7 +460,6 @@
     // This is valid because the color components of the result of the kernel all come
     // exactly from existing values in the source texture.
     this->updateInvariantOutputForModulation(inout);
-    inout->fIsSingleComponent = false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp
index e9f6c60..9254ff5 100644
--- a/src/effects/SkPerlinNoiseShader.cpp
+++ b/src/effects/SkPerlinNoiseShader.cpp
@@ -587,8 +587,7 @@
     }
 
     void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0; // This is noise. Nothing is constant.
-        inout->fIsSingleComponent = false;
+        inout->setToUnknown();
     }
 
     GrPerlinNoiseEffect(SkPerlinNoiseShader::Type type,
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index b0e61ca..487968b 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -404,19 +404,20 @@
 void ColorTableEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     // If we kept the table in the effect then we could actually run known inputs through the
     // table.
+    uint8_t invalidateFlags = 0;
     if (fFlags & SkTable_ColorFilter::kR_Flag) {
-        inout->fValidFlags &= ~kR_GrColorComponentFlag;
+        invalidateFlags |= kR_GrColorComponentFlag;
     }
     if (fFlags & SkTable_ColorFilter::kG_Flag) {
-        inout->fValidFlags &= ~kG_GrColorComponentFlag;
+        invalidateFlags |= kG_GrColorComponentFlag;
     }
     if (fFlags & SkTable_ColorFilter::kB_Flag) {
-        inout->fValidFlags &= ~kB_GrColorComponentFlag;
+        invalidateFlags |= kB_GrColorComponentFlag;
     }
     if (fFlags & SkTable_ColorFilter::kA_Flag) {
-        inout->fValidFlags &= ~kA_GrColorComponentFlag;
+        invalidateFlags |= kA_GrColorComponentFlag;
     }
-    inout->fIsSingleComponent = false;
+    inout->invalidateComponents(invalidateFlags);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 87cca3b..af21ffc 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -1213,12 +1213,11 @@
 }
 
 void GrGradientEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    if (fIsOpaque && inout->isOpaque()) {
-        inout->fValidFlags = kA_GrColorComponentFlag;
+    if (fIsOpaque) {
+        inout->mulByUnknownOpaqueColor();
     } else {
-        inout->fValidFlags = 0;
+        inout->mulByUnknownColor();
     }
-    inout->fIsSingleComponent = false;
 }
 
 int GrGradientEffect::RandomGradientParams(SkRandom* random,
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index 550d7ae..9e16177 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -589,8 +589,7 @@
     }
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     const GrShaderVar& fInQuadEdge;
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 88b0306..1a144d9 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -108,8 +108,7 @@
     virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE { return true; }
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
@@ -253,8 +252,7 @@
     virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE { return true; }
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     const GrShaderVar& fInRectEdge;
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 4dda3b5..3ba4861 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -146,8 +146,7 @@
     }
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     const GrShaderVar& fInCircleEdge;
@@ -287,8 +286,7 @@
     }
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     const GrShaderVar& fInEllipseOffset;
@@ -456,8 +454,7 @@
     }
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     const GrShaderVar& fInEllipseOffsets0;
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index 4631a2c..e6751db 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -105,8 +105,7 @@
     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     GrPrimitiveEdgeType   fEdgeType;
@@ -178,8 +177,7 @@
     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     GrPrimitiveEdgeType   fEdgeType;
@@ -253,8 +251,7 @@
     virtual bool onIsEqual(const GrProcessor& other) const SK_OVERRIDE;
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownAlpha();
     }
 
     GrPrimitiveEdgeType   fEdgeType;
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 7cdb56a..75a0861 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -171,9 +171,7 @@
 
 void GrBicubicEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     // FIXME: Perhaps we can do better.
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
-    return;
+    inout->mulByUnknownAlpha();
 }
 
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrBicubicEffect);
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 96a7be2..fb66cf4 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -128,7 +128,6 @@
 
 void GrConfigConversionEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     this->updateInvariantOutputForModulation(inout);
-    inout->fIsSingleComponent = false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index bc76e5a..87d1286 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -46,12 +46,10 @@
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
         if (fRect.isEmpty()) {
             // An empty rect will have no coverage anywhere.
-            inout->fColor = 0x00000000;
-            inout->fValidFlags = kRGBA_GrColorComponentFlags;
+            inout->setToTransparentBlack();
         } else {
-            inout->fValidFlags = 0;
+            inout->mulByUnknownAlpha();
         }
-        inout->fIsSingleComponent = false;
     }
 
     SkRect              fRect;
@@ -329,8 +327,7 @@
 GrConvexPolyEffect::~GrConvexPolyEffect() {}
 
 void GrConvexPolyEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendFragmentProcessorFactory& GrConvexPolyEffect::getFactory() const {
diff --git a/src/gpu/effects/GrConvolutionEffect.h b/src/gpu/effects/GrConvolutionEffect.h
index f61f378..6c55656 100644
--- a/src/gpu/effects/GrConvolutionEffect.h
+++ b/src/gpu/effects/GrConvolutionEffect.h
@@ -100,8 +100,7 @@
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const {
         // If the texture was opaque we could know that the output color if we knew the sum of the
         // kernel values.
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownColor();
     }
 
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
index e89e46c..40ff1b1 100644
--- a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
@@ -73,12 +73,11 @@
 }
 
 void GrCustomCoordsTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    if (inout->isOpaque() && GrPixelConfigIsOpaque(this->texture(0)->config())) {
-        inout->fValidFlags = kA_GrColorComponentFlag;
+    if (GrPixelConfigIsOpaque(this->texture(0)->config())) {
+        inout->mulByUnknownOpaqueColor();
     } else {
-        inout->fValidFlags = 0;
+        inout->mulByUnknownColor();
     }
-    inout->fIsSingleComponent = false;
 }
 
 const GrBackendGeometryProcessorFactory& GrCustomCoordsTextureEffect::getFactory() const {
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index d7a2f40..7e20809 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -585,8 +585,7 @@
 DashingCircleEffect::~DashingCircleEffect() {}
 
 void DashingCircleEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendGeometryProcessorFactory& DashingCircleEffect::getFactory() const {
@@ -809,8 +808,7 @@
 DashingLineEffect::~DashingLineEffect() {}
 
 void DashingLineEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendGeometryProcessorFactory& DashingLineEffect::getFactory() const {
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index c8ed5c9..3374adc 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -207,12 +207,7 @@
 }
 
 void GrDistanceFieldTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    if (inout->isOpaque() && GrPixelConfigIsOpaque(this->texture(0)->config())) {
-        inout->fValidFlags = kA_GrColorComponentFlag;
-    } else {
-        inout->fValidFlags = 0;
-    }
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendGeometryProcessorFactory& GrDistanceFieldTextureEffect::getFactory() const {
@@ -391,12 +386,7 @@
 }
 
 void GrDistanceFieldNoGammaTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    if (inout->isOpaque() && GrPixelConfigIsOpaque(this->texture(0)->config())) {
-        inout->fValidFlags = kA_GrColorComponentFlag;
-    } else {
-        inout->fValidFlags = 0;
-    }
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendGeometryProcessorFactory& GrDistanceFieldNoGammaTextureEffect::getFactory() const {
@@ -647,12 +637,7 @@
 }
 
 void GrDistanceFieldLCDTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    if (inout->isOpaque() && GrPixelConfigIsOpaque(this->texture(0)->config())) {
-        inout->fValidFlags = kA_GrColorComponentFlag;
-    } else {
-        inout->fValidFlags = 0;
-    }
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownColor();
 }
 
 const GrBackendGeometryProcessorFactory& GrDistanceFieldLCDTextureEffect::getFactory() const {
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
index ce8c471..96cdd75 100644
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ b/src/gpu/effects/GrDitherEffect.cpp
@@ -50,8 +50,7 @@
 };
 
 void DitherEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->setToUnknown();
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
index a9e7157..07b4851 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
@@ -58,7 +58,6 @@
                                            const char* inputColor,
                                            const TransformedCoordsArray& coords,
                                            const TextureSamplerArray& samplers) {
-    sk_ignore_unused_variable(inputColor);
     const GrTextureDomain& domain = fp.cast<GrMatrixConvolutionEffect>().domain();
 
     fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.h b/src/gpu/effects/GrMatrixConvolutionEffect.h
index 4d76f4c..c653230 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.h
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.h
@@ -81,8 +81,7 @@
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
         // TODO: Try to do better?
-        inout->fValidFlags = 0;
-        inout->fIsSingleComponent = false;
+        inout->mulByUnknownColor();
     }
 
     SkIRect         fBounds;
diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp
index c4e272a..3d8f207 100644
--- a/src/gpu/effects/GrOvalEffect.cpp
+++ b/src/gpu/effects/GrOvalEffect.cpp
@@ -57,8 +57,7 @@
 }
 
 void CircleEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendFragmentProcessorFactory& CircleEffect::getFactory() const {
@@ -232,8 +231,7 @@
 }
 
 void EllipseEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendFragmentProcessorFactory& EllipseEffect::getFactory() const {
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index 2113554..ae1daef 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -87,8 +87,7 @@
 }
 
 void CircularRRectEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendFragmentProcessorFactory& CircularRRectEffect::getFactory() const {
@@ -426,8 +425,7 @@
 }
 
 void EllipticalRRectEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
-    inout->fValidFlags = 0;
-    inout->fIsSingleComponent = false;
+    inout->mulByUnknownAlpha();
 }
 
 const GrBackendFragmentProcessorFactory& EllipticalRRectEffect::getFactory() const {
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 7abde24..4da9e8e 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -43,7 +43,6 @@
 
 void GrSimpleTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     this->updateInvariantOutputForModulation(inout);
-    inout->fIsSingleComponent = false;
 }
 
 const GrBackendFragmentProcessorFactory& GrSimpleTextureEffect::getFactory() const {
diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h
index cba322e..899755c 100644
--- a/src/gpu/effects/GrSingleTextureEffect.h
+++ b/src/gpu/effects/GrSingleTextureEffect.h
@@ -49,10 +49,10 @@
      * texture.
      */
     void updateInvariantOutputForModulation(InvariantOutput* inout) const {
-        if (inout->isOpaque() && GrPixelConfigIsOpaque(this->texture(0)->config())) {
-            inout->fValidFlags = kA_GrColorComponentFlag;
+        if (GrPixelConfigIsOpaque(this->texture(0)->config())) {
+            inout->mulByUnknownOpaqueColor();
         } else {
-            inout->fValidFlags = 0;
+            inout->mulByUnknownColor();
         }
     }
 
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index 2117857..596415e 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -271,11 +271,10 @@
 
 void GrTextureDomainEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
     if (GrTextureDomain::kDecal_Mode == fTextureDomain.mode()) { // TODO: helper
-        inout->fValidFlags = 0;
+        inout->mulByUnknownColor();
     } else {
         this->updateInvariantOutputForModulation(inout);
     }
-    inout->fIsSingleComponent = false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index ecbaf3a..e3d25a2 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -112,9 +112,7 @@
 
     virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
         // YUV is opaque
-        inout->fColor = 0xFF;
-        inout->fValidFlags = kA_GrColorComponentFlag;
-        inout->fIsSingleComponent = false;
+        inout->setToOther(kA_GrColorComponentFlag, 0xFF << GrColor_SHIFT_A);
     }
 
     GrCoordTransform fCoordTransform;
diff --git a/tests/GpuColorFilterTest.cpp b/tests/GpuColorFilterTest.cpp
index a61fe0b..90f2220 100644
--- a/tests/GpuColorFilterTest.cpp
+++ b/tests/GpuColorFilterTest.cpp
@@ -100,13 +100,11 @@
         SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(test.filterColor, test.filterMode));
         SkAutoTUnref<GrFragmentProcessor> effect(cf->asFragmentProcessor(grContext));
         GrProcessor::InvariantOutput inout;
-        inout.fColor = test.inputColor;
-        inout.fValidFlags = test.inputComponents;
-        inout.fIsSingleComponent = false;
+        inout.setToOther(test.inputComponents, test.inputColor);
         effect->computeInvariantOutput(&inout);
 
-        REPORTER_ASSERT(reporter, filterColor(inout.fColor, inout.fValidFlags) == test.outputColor);
-        REPORTER_ASSERT(reporter, test.outputComponents == inout.fValidFlags);
+        REPORTER_ASSERT(reporter, filterColor(inout.color(), inout.validFlags()) == test.outputColor);
+        REPORTER_ASSERT(reporter, test.outputComponents == inout.validFlags());
     }
 }