Fix HWUI/Skia Gradients to premultiply the colors prior to interpolation

This is fixed in Skia by passing the appropriate flag when the shader is
generated.  The fix in HWUI is to reverse the premultiplication and
interpolation steps.

Test: bit CtsUiRenderingTestCases:.testclasses.ShaderTests
Bug: 34323783
Change-Id: I3417141949f62fcc696b6d8213a4b446d7d0cbf8
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index a77ed62..1a35330 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -10,6 +10,14 @@
 
 using namespace android::uirenderer;
 
+/**
+ * By default Skia gradients will interpolate their colors in unpremul space
+ * and then premultiply each of the results. We must set this flag to preserve
+ * backwards compatiblity by premultiplying the colors of the gradient first,
+ * and then interpolating between them.
+ */
+static const uint32_t sGradientShaderFlags = SkGradientShader::kInterpolateColorsInPremul_Flag;
+
 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
     if (NULL == ptr) {
         doThrowIAE(env);
@@ -89,7 +97,7 @@
 
     SkShader* shader = SkGradientShader::MakeLinear(pts,
             reinterpret_cast<const SkColor*>(colorValues), pos, count,
-            static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
 
     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
     ThrowIAE_IfNull(env, shader);
@@ -109,7 +117,7 @@
     colors[1] = color1;
 
     SkShader* s = SkGradientShader::MakeLinear(pts, colors, NULL, 2,
-            (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
 
     ThrowIAE_IfNull(env, s);
     return reinterpret_cast<jlong>(s);
@@ -135,7 +143,7 @@
 
     SkShader* shader = SkGradientShader::MakeRadial(center, radius,
             reinterpret_cast<const SkColor*>(colorValues), pos, count,
-            static_cast<SkShader::TileMode>(tileMode), /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
     env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues),
                                  JNI_ABORT);
 
@@ -154,7 +162,7 @@
     colors[1] = color1;
 
     SkShader* s = SkGradientShader::MakeRadial(center, radius, colors, NULL, 2,
-            (SkShader::TileMode)tileMode, /* flags */ 0, matrix).release();
+            static_cast<SkShader::TileMode>(tileMode), sGradientShaderFlags, matrix).release();
     ThrowIAE_IfNull(env, s);
     return reinterpret_cast<jlong>(s);
 }
@@ -174,8 +182,8 @@
     #error Need to convert float array to SkScalar array before calling the following function.
 #endif
 
-    SkShader* shader = SkGradientShader::MakeSweep(x, y,
-            reinterpret_cast<const SkColor*>(colors), pos, count, /* flags */ 0, matrix).release();
+    SkShader* shader = SkGradientShader::MakeSweep(x, y, reinterpret_cast<const SkColor*>(colors),
+            pos, count, sGradientShaderFlags, matrix).release();
     env->ReleaseIntArrayElements(jcolors, const_cast<jint*>(colors),
                                  JNI_ABORT);
     ThrowIAE_IfNull(env, shader);
@@ -189,7 +197,7 @@
     colors[0] = color0;
     colors[1] = color1;
     SkShader* s = SkGradientShader::MakeSweep(x, y, colors, NULL, 2,
-            /* flags */ 0, matrix).release();
+            sGradientShaderFlags, matrix).release();
     ThrowIAE_IfNull(env, s);
     return reinterpret_cast<jlong>(s);
 }
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index dceb285..d4d0c99 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -189,9 +189,9 @@
         float amount, uint8_t*& dst) const {
     float oppAmount = 1.0f - amount;
     float a = start.a * oppAmount + end.a * amount;
-    *dst++ = uint8_t(a * OECF(start.r * oppAmount + end.r * amount) * 255.0f);
-    *dst++ = uint8_t(a * OECF(start.g * oppAmount + end.g * amount) * 255.0f);
-    *dst++ = uint8_t(a * OECF(start.b * oppAmount + end.b * amount) * 255.0f);
+    *dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f);
+    *dst++ = uint8_t(OECF(start.g * oppAmount + end.g * amount) * 255.0f);
+    *dst++ = uint8_t(OECF(start.b * oppAmount + end.b * amount) * 255.0f);
     *dst++ = uint8_t(a * 255.0f);
 }
 
@@ -202,13 +202,13 @@
     float* d = (float*) dst;
 #ifdef ANDROID_ENABLE_LINEAR_BLENDING
     // We want to stay linear
-    *d++ = a * (start.r * oppAmount + end.r * amount);
-    *d++ = a * (start.g * oppAmount + end.g * amount);
-    *d++ = a * (start.b * oppAmount + end.b * amount);
+    *d++ = (start.r * oppAmount + end.r * amount);
+    *d++ = (start.g * oppAmount + end.g * amount);
+    *d++ = (start.b * oppAmount + end.b * amount);
 #else
-    *d++ = a * OECF(start.r * oppAmount + end.r * amount);
-    *d++ = a * OECF(start.g * oppAmount + end.g * amount);
-    *d++ = a * OECF(start.b * oppAmount + end.b * amount);
+    *d++ = OECF(start.r * oppAmount + end.r * amount);
+    *d++ = OECF(start.g * oppAmount + end.g * amount);
+    *d++ = OECF(start.b * oppAmount + end.b * amount);
 #endif
     *d++ = a;
     dst += 4 * sizeof(float);
@@ -229,10 +229,10 @@
     ChannelMixer mix = gMixers[mUseFloatTexture];
 
     FloatColor start;
-    start.setUnPreMultiplied(colors[0]);
+    start.set(colors[0]);
 
     FloatColor end;
-    end.setUnPreMultiplied(colors[1]);
+    end.set(colors[1]);
 
     int currentPos = 1;
     float startPos = positions[0];
@@ -247,7 +247,7 @@
 
             currentPos++;
 
-            end.setUnPreMultiplied(colors[currentPos]);
+            end.set(colors[currentPos]);
             distance = positions[currentPos] - startPos;
         }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 1f78e09..d0f0949 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -295,10 +295,6 @@
         vec4 dither(const vec4 color) {
             return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
         }
-        vec4 gradientMix(const vec4 a, const vec4 b, float v) {
-            vec4 c = mix(a, b, v);
-            return vec4(c.rgb * c.a, c.a);
-        }
         )__SHADER__",
         // sRGB framebuffer
         R"__SHADER__(
@@ -306,10 +302,6 @@
             vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
             return vec4(dithered * dithered, color.a);
         }
-        vec4 gradientMixMix(const vec4 a, const vec4 b, float v) {
-            vec4 c = mix(a, b, v);
-            return vec4(c.rgb * c.a, c.a);
-        }
         )__SHADER__",
 };
 
@@ -364,19 +356,19 @@
         // Linear
         "    vec4 gradientColor = texture2D(gradientSampler, linear);\n",
 
-        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
 
         // Circular
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
 
-        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
 
         // Sweep
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
 
         "    highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
-        "    vec4 gradientColor = gradientMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+        "    vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
 };
 const char* gFS_Main_FetchBitmap =
         "    vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n";
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 8a504d4..5c5378b 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -173,8 +173,8 @@
         outData->gradientSampler = 0;
         outData->gradientTexture = nullptr;
 
-        outData->startColor.setUnPreMultiplied(gradInfo.fColors[0]);
-        outData->endColor.setUnPreMultiplied(gradInfo.fColors[1]);
+        outData->startColor.set(gradInfo.fColors[0]);
+        outData->endColor.set(gradInfo.fColors[1]);
     }
 
     return true;