SkSL version of color conversion functions for new CSS gradients

Not used yet. These are direct (ie slow) translations of the reference
transformations in the spec.

Bug: skia:13108
Change-Id: Iaf29607f18e1d90485497ce1ff707dd6587d4300
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/583858
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
diff --git a/src/sksl/generated/sksl_rt_shader.minified.sksl b/src/sksl/generated/sksl_rt_shader.minified.sksl
index 70ca8da..dae0f67 100644
--- a/src/sksl/generated/sksl_rt_shader.minified.sksl
+++ b/src/sksl/generated/sksl_rt_shader.minified.sksl
@@ -1,2 +1,16 @@
 static constexpr char SKSL_MINIFIED_sksl_rt_shader[] =
-"layout(builtin=15)float4 sk_FragCoord;";
+"layout(builtin=15)float4 sk_FragCoord;$pure half3 $a(half3 a){half3 d;d.y=("
+"a.x+16.)/116.;d.x=a.y/500.+d.y;d.z=d.y-a.z/200.;half3 g=pow(d,half3(3.));half3"
+" h=half3(g.x>.008856452?g.x:(116.*d.x-16.)/903.2963,a.x>8.000001?g.y:a.x/903.2963"
+",g.z>.008856452?g.z:(116.*d.z-16.)/903.2963);return h*half3(.9642956,1.,.825104535"
+");}$pure half3 $b(half3 a){return half3(a.x,a.y*cos(radians(a.z)),a.y*sin(radians"
+"(a.z)));}$pure half3 $c(half3 a){return $a($b(a));}$pure half3 $d(half3 a){"
+"half3 d=half3(float3x3(1.,.396337777,.215803757,1.,-.105561346,-.06385417,1."
+",-.089484185,-1.29148555)*float3(a));return half3x3(1.22687984,-.557815,.281391054"
+",-.04057576,1.11228681,-.07171106,-.07637295,-.421493322,1.58692408)*pow(d,"
+"half3(3.));}$pure half3 $e(half3 a){return $d($b(a));}$pure half3 $f(half3 b"
+"){b.x=mod(b.x,360.);if(b.x<0.){b.x+=360.;}b.yz/=100.;half3 c=mod(half3(0.,8."
+",4.)+b.x/30.,12.);half d=b.y*min(b.z,1.-b.z);return b.z-d*clamp(min(c-3.,9."
+"-c),-1.,1.);}$pure half3 $g(half3 a){a.yz/=100.;if(a.y+a.z>=1.){half b=a.y/"
+"(a.y+a.z);return half3(b);}half3 b=$f(half3(a.x,100.,50.));b*=(1.-a.y)-a.z;"
+"b+=a.y;return b;}";
diff --git a/src/sksl/generated/sksl_rt_shader.unoptimized.sksl b/src/sksl/generated/sksl_rt_shader.unoptimized.sksl
index 70ca8da..8a9c65a 100644
--- a/src/sksl/generated/sksl_rt_shader.unoptimized.sksl
+++ b/src/sksl/generated/sksl_rt_shader.unoptimized.sksl
@@ -1,2 +1,21 @@
 static constexpr char SKSL_MINIFIED_sksl_rt_shader[] =
-"layout(builtin=15)float4 sk_FragCoord;";
+"layout(builtin=15)float4 sk_FragCoord;$pure half3 $css_Lab_to_XYZ(half3 Lab"
+"){const half k=903.2963;const half e=.008856452;half3 f;f.y=(Lab.x+16.)/116."
+";f.x=Lab.y/500.+f.y;f.z=f.y-Lab.z/200.;half3 f_cubed=pow(f,half3(3.));half3"
+" xyz=half3(f_cubed.x>e?f_cubed.x:(116.*f.x-16.)/k,Lab.x>8.000001?f_cubed.y:"
+"Lab.x/k,f_cubed.z>e?f_cubed.z:(116.*f.z-16.)/k);const half3 D50=half3(.9642956"
+",1.,.825104535);return xyz*D50;}$pure half3 $css_LCH_to_Lab(half3 LCH){return"
+" half3(LCH.x,LCH.y*cos(radians(LCH.z)),LCH.y*sin(radians(LCH.z)));}$pure half3"
+" $css_LCH_to_XYZ(half3 LCH){return $css_Lab_to_XYZ($css_LCH_to_Lab(LCH));}$pure"
+" half3 $css_OKLab_to_XYZ(half3 OKLab){const half3x3 LMStoXYZ=half3x3(1.22687984"
+",-.557815,.281391054,-.04057576,1.11228681,-.07171106,-.07637295,-.421493322"
+",1.58692408);const float3x3 OKLabToLMS=float3x3(1.,.396337777,.215803757,1."
+",-.105561346,-.06385417,1.,-.089484185,-1.29148555);half3 LMSnl=half3(OKLabToLMS"
+"*float3(OKLab));return LMStoXYZ*pow(LMSnl,half3(3.));}$pure half3 $css_OKLCH_to_XYZ"
+"(half3 OKLCH){return $css_OKLab_to_XYZ($css_LCH_to_Lab(OKLCH));}$pure half3"
+" $css_hsl_to_sRGB(half3 hsl){hsl.x=mod(hsl.x,360.);if(hsl.x<0.){hsl.x+=360."
+";}hsl.yz/=100.;half3 k=mod(half3(0.,8.,4.)+hsl.x/30.,12.);half a=hsl.y*min("
+"hsl.z,1.-hsl.z);return hsl.z-a*clamp(min(k-3.,9.-k),-1.,1.);}$pure half3 $css_hwb_to_sRGB"
+"(half3 hwb){hwb.yz/=100.;if(hwb.y+hwb.z>=1.){half gray=hwb.y/(hwb.y+hwb.z);"
+"return half3(gray);}half3 rgb=$css_hsl_to_sRGB(half3(hwb.x,100.,50.));rgb*="
+"(1.-hwb.y)-hwb.z;rgb+=hwb.y;return rgb;}";
diff --git a/src/sksl/sksl_rt_shader.sksl b/src/sksl/sksl_rt_shader.sksl
index abae147..d6a3ef3 100644
--- a/src/sksl/sksl_rt_shader.sksl
+++ b/src/sksl/sksl_rt_shader.sksl
@@ -1 +1,86 @@
 layout(builtin=15) float4 sk_FragCoord;
+
+// Color conversion functions used in gradient interpolation, based on
+// https://www.w3.org/TR/css-color-4/#color-conversion-code
+// TODO(skia:13108): For all of these, we can eliminate any linear math at the beginning
+// (by removing the corresponding linear math at the end of the CPU code).
+$pure half3 $css_Lab_to_XYZ(half3 Lab) {
+    const half k = 24389 / 27.0;
+    const half e = 216 / 24389.0;
+
+    half3 f;
+    f[1] = (Lab[0] + 16) / 116;
+    f[0] = (Lab[1] / 500) + f[1];
+    f[2] = f[1] - (Lab[2] / 200);
+
+    half3 f_cubed = pow(f, half3(3));
+
+    half3 xyz = half3(
+        f_cubed[0] > e ? f_cubed[0] : (116 * f[0] - 16) / k,
+        Lab[0] > k * e ? f_cubed[1] : Lab[0] / k,
+        f_cubed[2] > e ? f_cubed[2] : (116 * f[2] - 16) / k
+    );
+
+    const half3 D50 = half3(0.3457 / 0.3585, 1.0, (1.0 - 0.3457 - 0.3585) / 0.3585);
+    return xyz * D50;
+}
+
+// Also used by OKLCH -> OKLab
+$pure half3 $css_LCH_to_Lab(half3 LCH) {
+    return half3(
+        LCH[0],
+        LCH[1] * cos(radians(LCH[2])),
+        LCH[1] * sin(radians(LCH[2]))
+    );
+}
+
+$pure half3 $css_LCH_to_XYZ(half3 LCH) {
+    return $css_Lab_to_XYZ($css_LCH_to_Lab(LCH));
+}
+
+$pure half3 $css_OKLab_to_XYZ(half3 OKLab) {
+    const half3x3 LMStoXYZ = half3x3(
+         1.2268798733741557,  -0.5578149965554813,  0.28139105017721583,
+        -0.04057576262431372,  1.1122868293970594, -0.07171106666151701,
+        -0.07637294974672142, -0.4214933239627914,  1.5869240244272418
+    );
+    // TODO(skia:13794): Switch this back to half3x3 when it no longer triggers sk_Caps errors
+    const float3x3 OKLabToLMS = half3x3(
+        0.99999999845051981432,  0.39633779217376785678,   0.21580375806075880339,
+        1.0000000088817607767,  -0.1055613423236563494,   -0.063854174771705903402,
+        1.0000000546724109177,  -0.089484182094965759684, -1.2914855378640917399
+    );
+    half3 LMSnl = half3(OKLabToLMS * OKLab);
+    return LMStoXYZ * pow(LMSnl, half3(3));
+}
+
+$pure half3 $css_OKLCH_to_XYZ(half3 OKLCH) {
+    return $css_OKLab_to_XYZ($css_LCH_to_Lab(OKLCH));
+}
+
+// TODO(skia:13108): Use our optimized version (though it has different range)
+// Doing so might require fixing (re-deriving?) the math for the HWB version below
+$pure half3 $css_hsl_to_sRGB(half3 hsl) {
+    hsl.x = mod(hsl.x, 360);
+    if (hsl.x < 0) {
+        hsl.x += 360;
+    }
+
+    hsl.yz /= 100;
+
+    half3 k = mod(half3(0, 8, 4) + hsl.x/30, 12);
+    half a = hsl.y * min(hsl.z, 1 - hsl.z);
+    return hsl.z - a * clamp(min(k - 3, 9 - k), -1, 1);
+}
+
+$pure half3 $css_hwb_to_sRGB(half3 hwb) {
+    hwb.yz /= 100;
+    if (hwb.y + hwb.z >= 1) {
+        half gray = hwb.y / (hwb.y + hwb.z);
+        return half3(gray);
+    }
+    half3 rgb = $css_hsl_to_sRGB(half3(hwb.x, 100, 50));
+    rgb *= (1 - hwb.y - hwb.z);
+    rgb += hwb.y;
+    return rgb;
+}