Add GrEffect::updateKnownColorComponents(). It is used to determine whether the output of an effect has a constant output value for r,g,b, or a.
Review URL: https://codereview.appspot.com/7064057

git-svn-id: http://skia.googlecode.com/svn/trunk@7144 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index ed34f64..2ff4fd6 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -338,6 +338,51 @@
         return cme.fMatrix == fMatrix;
     }
 
+    virtual void getConstantColorComponents(GrColor* color,
+                                            uint32_t* validFlags) const SK_OVERRIDE {
+        // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had
+        // type flags it might be worth checking the other components.
+
+        // The matrix is defined such the 4th row determines the output alpha. The first four
+        // columns of that row multiply the input r, g, b, and a, respectively, and the last column
+        // is the "translation".
+        static const ValidComponentFlags kRGBAFlags[] = {
+            kR_ValidComponentFlag,
+            kG_ValidComponentFlag,
+            kB_ValidComponentFlag,
+            kA_ValidComponentFlag
+        };
+        static const int kShifts[] = {
+            GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A,
+        };
+        enum {
+            kAlphaRowStartIdx = 15,
+            kAlphaRowTranslateIdx = 19,
+        };
+
+        SkScalar outputA = 0;
+        for (int i = 0; i < 4; ++i) {
+            // 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 (!(*validFlags & kRGBAFlags[i])) {
+                    *validFlags = 0;
+                    return;
+                } else {
+                    uint32_t component = (*color >> kShifts[i]) & 0xFF;
+                    outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
+                }
+            }
+        }
+        outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
+        *validFlags = kA_ValidComponentFlag;
+        // 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?
+        *color = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A;
+    }
+
     GR_DECLARE_EFFECT_TEST;
 
     class GLEffect : public GrGLEffect {