When applying a color matrix, unpremultiply the source, and premultiply the
result.  If the input color is missing, set to all-zeros or all-ones as
appropriate.  Add an alpha test case to the colormatrix GM.

Review URL:  http://codereview.appspot.com/5520046/



git-svn-id: http://skia.googlecode.com/svn/trunk@2974 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/colormatrix.cpp b/gm/colormatrix.cpp
index 7d57b32..0a4acfd 100644
--- a/gm/colormatrix.cpp
+++ b/gm/colormatrix.cpp
@@ -90,6 +90,19 @@
         matrix.setYUV2RGB();
         filter->setMatrix(matrix);
         canvas->drawBitmap(fBitmap, 80, 160, &paint);
+
+        SkScalar s1 = SK_Scalar1;
+        SkScalar s255 = SkIntToScalar(255);
+        // Move red into alpha, set color to white
+        SkScalar data[20] = {
+            0,  0, 0, 0, s255,
+            0,  0, 0, 0, s255,
+            0,  0, 0, 0, s255,
+            s1, 0, 0, 0, 0,
+        };
+
+        filter->setArray(data);
+        canvas->drawBitmap(fBitmap, 160, 160, &paint);
     }
     
 private:
diff --git a/src/gpu/GrGLProgram.cpp b/src/gpu/GrGLProgram.cpp
index ce87b85..2e391e3 100644
--- a/src/gpu/GrGLProgram.cpp
+++ b/src/gpu/GrGLProgram.cpp
@@ -373,7 +373,8 @@
  */
 static void addColorMatrix(GrStringBuilder* fsCode, const char * outputVar,
                            const char* inColor) {
-    fsCode->appendf("%s = %s * %s + %s;\n", outputVar, COL_MATRIX_UNI_NAME, inColor, COL_MATRIX_VEC_UNI_NAME);
+    fsCode->appendf("\t%s = %s * vec4(%s.rgb / %s.a, %s.a) + %s;\n", outputVar, COL_MATRIX_UNI_NAME, inColor, inColor, inColor, COL_MATRIX_VEC_UNI_NAME);
+    fsCode->appendf("\t%s.rgb *= %s.a;\n", outputVar, outputVar);
 }
 
 namespace {
@@ -652,6 +653,19 @@
 #endif
 }
 
+const char* GrGLProgram::adjustInColor(const GrStringBuilder& inColor) const {
+    const char* color;
+    if (inColor.size()) {
+          return inColor.c_str();
+    } else {
+        if (ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput) {
+            return all_ones_vec(4);
+        } else {
+            return all_zeros_vec(4);
+        }
+    }
+}
+
 bool GrGLProgram::genProgram(const GrGLInterface* gl,
                              GrGLSLGeneration glslGeneration,
                              GrGLProgram::CachedData* programData) const {
@@ -818,16 +832,7 @@
         wroteFragColorZero = true;
     } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
         segments.fFSCode.appendf("\tvec4 filteredColor;\n");
-        const char* color;
-        if (inColor.size()) {
-            color = inColor.c_str();
-        } else {
-            if (ProgramDesc::kSolidWhite_ColorInput == fProgramDesc.fColorInput) {
-                color = all_ones_vec(4);
-            } else {
-                color = all_zeros_vec(4);
-            }
-        }
+        const char* color = adjustInColor(inColor);
         addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
                        colorCoeff, color);
         inColor = "filteredColor";
@@ -842,7 +847,8 @@
         programData->fUniLocations.fColorMatrixUni = kUseUniform;
         programData->fUniLocations.fColorMatrixVecUni = kUseUniform;
         segments.fFSCode.appendf("\tvec4 matrixedColor;\n");
-        addColorMatrix(&segments.fFSCode, "matrixedColor", inColor.c_str());
+        const char* color = adjustInColor(inColor);
+        addColorMatrix(&segments.fFSCode, "matrixedColor", color);
         inColor = "matrixedColor";
     }
 
diff --git a/src/gpu/GrGLProgram.h b/src/gpu/GrGLProgram.h
index 7d19f7a..b4ad4af 100644
--- a/src/gpu/GrGLProgram.h
+++ b/src/gpu/GrGLProgram.h
@@ -231,6 +231,7 @@
 private:
 
     const ProgramDesc& getDesc() { return fProgramDesc; }
+    const char* adjustInColor(const GrStringBuilder& inColor) const;
 
 public:
     enum {