Remove clamp-to-1 behavior from blend_porter_duff.

"Plus" blend mode now uses a dedicated function, and blend_porter_duff
blends no longer add an extra clamp. This will preserve wide-gamut
colors.

Bug: b/351797081
Change-Id: I4fe48e0d37fabd8b9ffdc1f9684c197dae6bd072
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/875037
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/Blend.cpp b/src/gpu/Blend.cpp
index a374eee..4775ca7 100644
--- a/src/gpu/Blend.cpp
+++ b/src/gpu/Blend.cpp
@@ -63,7 +63,6 @@
     static constexpr float kSrcATop[]    = {0, 0,  1, -1};
     static constexpr float kDstATop[]    = {0, 0, -1,  1};
     static constexpr float kXor[]        = {0, 0, -1, -1};
-    static constexpr float kPlus[]       = {1, 1,  0,  0};
 
     switch (mode) {
         case SkBlendMode::kClear:      return SkSpan(kClear);
@@ -78,7 +77,6 @@
         case SkBlendMode::kSrcATop:    return SkSpan(kSrcATop);
         case SkBlendMode::kDstATop:    return SkSpan(kDstATop);
         case SkBlendMode::kXor:        return SkSpan(kXor);
-        case SkBlendMode::kPlus:       return SkSpan(kPlus);
         default:                       return {};
     }
 }
@@ -95,6 +93,7 @@
     static constexpr float kDarken[]     = {1};
     static constexpr float kLighten[]    = {-1};
 
+    // This switch must be kept in sync with BlendKey() in src/ganesh/glsl/GrGLSLBlend.cpp.
     switch (mode) {
         // Clear/src/dst are intentionally omitted; using the built-in blend_xxxxx functions is
         // preferable, since that gives us an opportunity to eliminate the src/dst entirely.
@@ -107,8 +106,8 @@
         case SkBlendMode::kDstOut:
         case SkBlendMode::kSrcATop:
         case SkBlendMode::kDstATop:
-        case SkBlendMode::kXor:
-        case SkBlendMode::kPlus:    return {"blend_porter_duff", GetPorterDuffBlendConstants(mode)};
+        case SkBlendMode::kXor:        return {"blend_porter_duff",
+                                               GetPorterDuffBlendConstants(mode)};
 
         case SkBlendMode::kHue:        return {"blend_hslc", SkSpan(kHue)};
         case SkBlendMode::kSaturation: return {"blend_hslc", SkSpan(kSaturation)};
diff --git a/src/gpu/ganesh/glsl/GrGLSLBlend.cpp b/src/gpu/ganesh/glsl/GrGLSLBlend.cpp
index 15bce7a..f0e9b73 100644
--- a/src/gpu/ganesh/glsl/GrGLSLBlend.cpp
+++ b/src/gpu/ganesh/glsl/GrGLSLBlend.cpp
@@ -38,6 +38,7 @@
 }
 
 int BlendKey(SkBlendMode mode) {
+    // This switch must be kept in sync with GetReducedBlendModeInfo() in src/gpu/Blend.cpp.
     switch (mode) {
         case SkBlendMode::kSrcOver:
         case SkBlendMode::kDstOver:
@@ -48,25 +49,24 @@
         case SkBlendMode::kSrcATop:
         case SkBlendMode::kDstATop:
         case SkBlendMode::kXor:
-        case SkBlendMode::kPlus:
-            return -1;
+            return -1;  // blend_porter_duff
 
         case SkBlendMode::kHue:
         case SkBlendMode::kSaturation:
         case SkBlendMode::kLuminosity:
         case SkBlendMode::kColor:
-            return -2;
+            return -2;  // blend_hslc
 
         case SkBlendMode::kOverlay:
         case SkBlendMode::kHardLight:
-            return -3;
+            return -3;  // blend_overlay
 
         case SkBlendMode::kDarken:
         case SkBlendMode::kLighten:
-            return -4;
+            return -4;  // blend_darken
 
         default:
-            return (int)mode;
+            return (int)mode;  // uses a dedicated SkSL blend function
     }
 }
 
diff --git a/src/sksl/generated/sksl_gpu.minified.sksl b/src/sksl/generated/sksl_gpu.minified.sksl
index 3c9803f..581d273 100644
--- a/src/sksl/generated/sksl_gpu.minified.sksl
+++ b/src/sksl/generated/sksl_gpu.minified.sksl
@@ -27,59 +27,59 @@
 "return(1.-b.w)*a;}$pure half4 blend_dst_out(half4 a,half4 b){return(1.-a.w)"
 "*b;}$pure half4 blend_src_atop(half4 a,half4 b){return b.w*a+(1.-a.w)*b;}$pure"
 " half4 blend_dst_atop(half4 a,half4 b){return(1.-b.w)*a+a.w*b;}$pure half4 blend_xor"
-"(half4 a,half4 b){return(1.-b.w)*a+(1.-a.w)*b;}$pure half4 blend_plus(half4"
-" a,half4 b){return min(a+b,1.);}$pure half4 blend_porter_duff(half4 a,half4"
-" b,half4 c){half2 d=a.xy+a.zw*(half2(c.w,b.w)+min(a.zw,0.));return min(half4"
-"(1.),b*d.x+c*d.y);}$pure half4 blend_modulate(half4 a,half4 b){return a*b;}"
-"$pure half4 blend_screen(half4 a,half4 b){return a+(1.-a)*b;}$pure half $b("
-"half2 a,half2 b){return 2.*b.x<=b.y?(2.*a.x)*b.x:a.y*b.y-(2.*(b.y-b.x))*(a."
-"y-a.x);}$pure half4 blend_overlay(half4 a,half4 b){half4 c=half4($b(a.xw,b."
-"xw),$b(a.yw,b.yw),$b(a.zw,b.zw),a.w+(1.-a.w)*b.w);c.xyz+=b.xyz*(1.-a.w)+a.xyz"
-"*(1.-b.w);return c;}$pure half4 blend_overlay(half c,half4 d,half4 e){return"
-" blend_overlay(bool(c)?e:d,bool(c)?d:e);}$pure half4 blend_lighten(half4 a,"
-"half4 b){half4 c=blend_src_over(a,b);c.xyz=max(c.xyz,(1.-b.w)*a.xyz+b.xyz);"
-"return c;}$pure half4 blend_darken(half c,half4 d,half4 e){half4 f=blend_src_over"
-"(d,e);half3 g=(1.-e.w)*d.xyz+e.xyz;f.xyz=c*min(f.xyz*c,g*c);return f;}$pure"
-" half4 blend_darken(half4 a,half4 b){return blend_darken(1.,a,b);}const half"
-" $kGuardedDivideEpsilon=half(sk_Caps.mustGuardDivisionEvenAfterExplicitZeroCheck"
-"?1e-08:0.);$pure inline half $c(half a,half b){return a/(b+$kGuardedDivideEpsilon"
-");}$pure inline half3 $c(half3 a,half b){return a/(b+$kGuardedDivideEpsilon"
-");}$pure half $d(half2 a,half2 b){if(b.x==0.)return a.x*(1.-b.y);else{half c"
-"=a.y-a.x;if(c==0.)return(a.y*b.y+a.x*(1.-b.y))+b.x*(1.-a.y);else{c=min(b.y,"
-"$c(b.x*a.y,c));return(c*a.y+a.x*(1.-b.y))+b.x*(1.-a.y);}}}$pure half4 blend_color_dodge"
-"(half4 a,half4 b){return half4($d(a.xw,b.xw),$d(a.yw,b.yw),$d(a.zw,b.zw),a."
-"w+(1.-a.w)*b.w);}$pure half $e(half2 a,half2 b){if(b.y==b.x)return(a.y*b.y+"
-"a.x*(1.-b.y))+b.x*(1.-a.y);else if(a.x==0.)return b.x*(1.-a.y);else{half c="
-"max(0.,b.y-$c((b.y-b.x)*a.y,a.x));return(c*a.y+a.x*(1.-b.y))+b.x*(1.-a.y);}"
-"}$pure half4 blend_color_burn(half4 a,half4 b){return half4($e(a.xw,b.xw),$e"
-"(a.yw,b.yw),$e(a.zw,b.zw),a.w+(1.-a.w)*b.w);}$pure half4 blend_hard_light(half4"
-" a,half4 b){return blend_overlay(b,a);}$pure half $f(half2 a,half2 b){if(2."
-"*a.x<=a.y)return($c((b.x*b.x)*(a.y-2.*a.x),b.y)+(1.-b.y)*a.x)+b.x*((-a.y+2."
-"*a.x)+1.);else if(4.*b.x<=b.y){half c=b.x*b.x;half e=c*b.x;half f=b.y*b.y;half"
-" g=f*b.y;return $c(((f*(a.x-b.x*((3.*a.y-6.*a.x)-1.))+((12.*b.y)*c)*(a.y-2."
-"*a.x))-(16.*e)*(a.y-2.*a.x))-g*a.x,f);}else return((b.x*((a.y-2.*a.x)+1.)+a"
-".x)-sqrt(b.y*b.x)*(a.y-2.*a.x))-b.y*a.x;}$pure half4 blend_soft_light(half4"
-" a,half4 b){return b.w==0.?a:half4($f(a.xw,b.xw),$f(a.yw,b.yw),$f(a.zw,b.zw"
-"),a.w+(1.-a.w)*b.w);}$pure half4 blend_difference(half4 a,half4 b){return half4"
-"((a.xyz+b.xyz)-2.*min(a.xyz*b.w,b.xyz*a.w),a.w+(1.-a.w)*b.w);}$pure half4 blend_exclusion"
-"(half4 a,half4 b){return half4((b.xyz+a.xyz)-(2.*b.xyz)*a.xyz,a.w+(1.-a.w)*"
-"b.w);}$pure half4 blend_multiply(half4 a,half4 b){return half4(((1.-a.w)*b."
-"xyz+(1.-b.w)*a.xyz)+a.xyz*b.xyz,a.w+(1.-a.w)*b.w);}$pure half $g(half3 a){return"
-" dot(half3(.3,.59,.11),a);}$pure half3 $h(half3 a,half b,half3 c){half d=$g"
-"(c);half3 e=(d-$g(a))+a;half f=min(min(e.x,e.y),e.z);half g=max(max(e.x,e.y"
-"),e.z);if(f<0.&&d!=f)e=d+(e-d)*$c(d,d-f);if(g>b&&g!=d)e=d+$c((e-d)*(b-d),g-"
-"d);return e;}$pure half $i(half3 a){return max(max(a.x,a.y),a.z)-min(min(a."
-"x,a.y),a.z);}$pure half3 $j(half3 a,half3 b){half c=min(min(a.x,a.y),a.z);half"
-" d=max(max(a.x,a.y),a.z);return d>c?((a-c)*$i(b))/(d-c):half3(0.);}$pure half4"
-" blend_hslc(half2 a,half4 b,half4 c){half d=c.w*b.w;half3 e=b.xyz*c.w;half3"
-" f=c.xyz*b.w;half3 g=bool(a.x)?f:e;half3 h=bool(a.x)?e:f;if(bool(a.y)){g=$j"
-"(g,h);h=f;}return half4(((($h(g,d,h)+c.xyz)-f)+b.xyz)-e,(b.w+c.w)-d);}$pure"
-" half4 blend_hue(half4 a,half4 b){return blend_hslc(half2(0.,1.),a,b);}$pure"
-" half4 blend_saturation(half4 a,half4 b){return blend_hslc(half2(1.),a,b);}"
-"$pure half4 blend_color(half4 a,half4 b){return blend_hslc(half2(0.),a,b);}"
-"$pure half4 blend_luminosity(half4 a,half4 b){return blend_hslc(half2(1.,0."
-"),a,b);}$pure float2 proj(float3 a){return a.xy/a.z;}$pure float cross_length_2d"
-"(float2 c,float2 d){return determinant(float2x2(c,d));}$pure half cross_length_2d"
-"(half2 c,half2 d){return determinant(half2x2(c,d));}$pure float2 perp(float2"
-" a){return float2(-a.y,a.x);}$pure half2 perp(half2 a){return half2(-a.y,a."
-"x);}$pure float coverage_bias(float a){return 1.-.5*a;}";
+"(half4 a,half4 b){return(1.-b.w)*a+(1.-a.w)*b;}$pure half4 blend_porter_duff"
+"(half4 a,half4 b,half4 c){half2 d=a.xy+a.zw*(half2(c.w,b.w)+min(a.zw,0.));return"
+" b*d.x+c*d.y;}$pure half4 blend_plus(half4 a,half4 b){return min(a+b,1.);}$pure"
+" half4 blend_modulate(half4 a,half4 b){return a*b;}$pure half4 blend_screen"
+"(half4 a,half4 b){return a+(1.-a)*b;}$pure half $b(half2 a,half2 b){return 2."
+"*b.x<=b.y?(2.*a.x)*b.x:a.y*b.y-(2.*(b.y-b.x))*(a.y-a.x);}$pure half4 blend_overlay"
+"(half4 a,half4 b){half4 c=half4($b(a.xw,b.xw),$b(a.yw,b.yw),$b(a.zw,b.zw),a"
+".w+(1.-a.w)*b.w);c.xyz+=b.xyz*(1.-a.w)+a.xyz*(1.-b.w);return c;}$pure half4"
+" blend_overlay(half c,half4 d,half4 e){return blend_overlay(bool(c)?e:d,bool"
+"(c)?d:e);}$pure half4 blend_lighten(half4 a,half4 b){half4 c=blend_src_over"
+"(a,b);c.xyz=max(c.xyz,(1.-b.w)*a.xyz+b.xyz);return c;}$pure half4 blend_darken"
+"(half c,half4 d,half4 e){half4 f=blend_src_over(d,e);half3 g=(1.-e.w)*d.xyz"
+"+e.xyz;f.xyz=c*min(f.xyz*c,g*c);return f;}$pure half4 blend_darken(half4 a,"
+"half4 b){return blend_darken(1.,a,b);}const half $kGuardedDivideEpsilon=half"
+"(sk_Caps.mustGuardDivisionEvenAfterExplicitZeroCheck?1e-08:0.);$pure inline"
+" half $c(half a,half b){return a/(b+$kGuardedDivideEpsilon);}$pure inline half3"
+" $c(half3 a,half b){return a/(b+$kGuardedDivideEpsilon);}$pure half $d(half2"
+" a,half2 b){if(b.x==0.)return a.x*(1.-b.y);else{half c=a.y-a.x;if(c==0.)return"
+"(a.y*b.y+a.x*(1.-b.y))+b.x*(1.-a.y);else{c=min(b.y,$c(b.x*a.y,c));return(c*"
+"a.y+a.x*(1.-b.y))+b.x*(1.-a.y);}}}$pure half4 blend_color_dodge(half4 a,half4"
+" b){return half4($d(a.xw,b.xw),$d(a.yw,b.yw),$d(a.zw,b.zw),a.w+(1.-a.w)*b.w"
+");}$pure half $e(half2 a,half2 b){if(b.y==b.x)return(a.y*b.y+a.x*(1.-b.y))+"
+"b.x*(1.-a.y);else if(a.x==0.)return b.x*(1.-a.y);else{half c=max(0.,b.y-$c("
+"(b.y-b.x)*a.y,a.x));return(c*a.y+a.x*(1.-b.y))+b.x*(1.-a.y);}}$pure half4 blend_color_burn"
+"(half4 a,half4 b){return half4($e(a.xw,b.xw),$e(a.yw,b.yw),$e(a.zw,b.zw),a."
+"w+(1.-a.w)*b.w);}$pure half4 blend_hard_light(half4 a,half4 b){return blend_overlay"
+"(b,a);}$pure half $f(half2 a,half2 b){if(2.*a.x<=a.y)return($c((b.x*b.x)*(a"
+".y-2.*a.x),b.y)+(1.-b.y)*a.x)+b.x*((-a.y+2.*a.x)+1.);else if(4.*b.x<=b.y){half"
+" c=b.x*b.x;half e=c*b.x;half f=b.y*b.y;half g=f*b.y;return $c(((f*(a.x-b.x*"
+"((3.*a.y-6.*a.x)-1.))+((12.*b.y)*c)*(a.y-2.*a.x))-(16.*e)*(a.y-2.*a.x))-g*a"
+".x,f);}else return((b.x*((a.y-2.*a.x)+1.)+a.x)-sqrt(b.y*b.x)*(a.y-2.*a.x))-"
+"b.y*a.x;}$pure half4 blend_soft_light(half4 a,half4 b){return b.w==0.?a:half4"
+"($f(a.xw,b.xw),$f(a.yw,b.yw),$f(a.zw,b.zw),a.w+(1.-a.w)*b.w);}$pure half4 blend_difference"
+"(half4 a,half4 b){return half4((a.xyz+b.xyz)-2.*min(a.xyz*b.w,b.xyz*a.w),a."
+"w+(1.-a.w)*b.w);}$pure half4 blend_exclusion(half4 a,half4 b){return half4("
+"(b.xyz+a.xyz)-(2.*b.xyz)*a.xyz,a.w+(1.-a.w)*b.w);}$pure half4 blend_multiply"
+"(half4 a,half4 b){return half4(((1.-a.w)*b.xyz+(1.-b.w)*a.xyz)+a.xyz*b.xyz,"
+"a.w+(1.-a.w)*b.w);}$pure half $g(half3 a){return dot(half3(.3,.59,.11),a);}"
+"$pure half3 $h(half3 a,half b,half3 c){half d=$g(c);half3 e=(d-$g(a))+a;half"
+" f=min(min(e.x,e.y),e.z);half g=max(max(e.x,e.y),e.z);if(f<0.&&d!=f)e=d+(e-"
+"d)*$c(d,d-f);if(g>b&&g!=d)e=d+$c((e-d)*(b-d),g-d);return e;}$pure half $i(half3"
+" a){return max(max(a.x,a.y),a.z)-min(min(a.x,a.y),a.z);}$pure half3 $j(half3"
+" a,half3 b){half c=min(min(a.x,a.y),a.z);half d=max(max(a.x,a.y),a.z);return"
+" d>c?((a-c)*$i(b))/(d-c):half3(0.);}$pure half4 blend_hslc(half2 a,half4 b,"
+"half4 c){half d=c.w*b.w;half3 e=b.xyz*c.w;half3 f=c.xyz*b.w;half3 g=bool(a."
+"x)?f:e;half3 h=bool(a.x)?e:f;if(bool(a.y)){g=$j(g,h);h=f;}return half4(((($h"
+"(g,d,h)+c.xyz)-f)+b.xyz)-e,(b.w+c.w)-d);}$pure half4 blend_hue(half4 a,half4"
+" b){return blend_hslc(half2(0.,1.),a,b);}$pure half4 blend_saturation(half4"
+" a,half4 b){return blend_hslc(half2(1.),a,b);}$pure half4 blend_color(half4"
+" a,half4 b){return blend_hslc(half2(0.),a,b);}$pure half4 blend_luminosity("
+"half4 a,half4 b){return blend_hslc(half2(1.,0.),a,b);}$pure float2 proj(float3"
+" a){return a.xy/a.z;}$pure float cross_length_2d(float2 c,float2 d){return determinant"
+"(float2x2(c,d));}$pure half cross_length_2d(half2 c,half2 d){return determinant"
+"(half2x2(c,d));}$pure float2 perp(float2 a){return float2(-a.y,a.x);}$pure half2"
+" perp(half2 a){return half2(-a.y,a.x);}$pure float coverage_bias(float a){return"
+" 1.-.5*a;}";
diff --git a/src/sksl/generated/sksl_gpu.unoptimized.sksl b/src/sksl/generated/sksl_gpu.unoptimized.sksl
index 59bbfa12..d081c8b 100644
--- a/src/sksl/generated/sksl_gpu.unoptimized.sksl
+++ b/src/sksl/generated/sksl_gpu.unoptimized.sksl
@@ -31,26 +31,26 @@
 " blend_dst_out(half4 src,half4 dst){return(1.-src.w)*dst;}$pure half4 blend_src_atop"
 "(half4 src,half4 dst){return dst.w*src+(1.-src.w)*dst;}$pure half4 blend_dst_atop"
 "(half4 src,half4 dst){return(1.-dst.w)*src+src.w*dst;}$pure half4 blend_xor"
-"(half4 src,half4 dst){return(1.-dst.w)*src+(1.-src.w)*dst;}$pure half4 blend_plus"
-"(half4 src,half4 dst){return min(src+dst,1.);}$pure half4 blend_porter_duff"
+"(half4 src,half4 dst){return(1.-dst.w)*src+(1.-src.w)*dst;}$pure half4 blend_porter_duff"
 "(half4 blendOp,half4 src,half4 dst){half2 coeff=blendOp.xy+blendOp.zw*(half2"
-"(dst.w,src.w)+min(blendOp.zw,0.));return min(half4(1.),src*coeff.x+dst*coeff"
-".y);}$pure half4 blend_modulate(half4 src,half4 dst){return src*dst;}$pure half4"
-" blend_screen(half4 src,half4 dst){return src+(1.-src)*dst;}$pure half $blend_overlay_component"
-"(half2 s,half2 d){return 2.*d.x<=d.y?(2.*s.x)*d.x:s.y*d.y-(2.*(d.y-d.x))*(s"
-".y-s.x);}$pure half4 blend_overlay(half4 src,half4 dst){half4 result=half4("
-"$blend_overlay_component(src.xw,dst.xw),$blend_overlay_component(src.yw,dst"
-".yw),$blend_overlay_component(src.zw,dst.zw),src.w+(1.-src.w)*dst.w);result"
-".xyz+=dst.xyz*(1.-src.w)+src.xyz*(1.-dst.w);return result;}$pure half4 blend_overlay"
-"(half flip,half4 a,half4 b){return blend_overlay(bool(flip)?b:a,bool(flip)?"
-"a:b);}$pure half4 blend_lighten(half4 src,half4 dst){half4 result=blend_src_over"
-"(src,dst);result.xyz=max(result.xyz,(1.-dst.w)*src.xyz+dst.xyz);return result"
-";}$pure half4 blend_darken(half mode,half4 src,half4 dst){half4 a=blend_src_over"
-"(src,dst);half3 b=(1.-dst.w)*src.xyz+dst.xyz;a.xyz=mode*min(a.xyz*mode,b*mode"
-");return a;}$pure half4 blend_darken(half4 src,half4 dst){return blend_darken"
-"(1.,src,dst);}const half $kGuardedDivideEpsilon=half(sk_Caps.mustGuardDivisionEvenAfterExplicitZeroCheck"
-"?1e-08:0.);$pure inline half $guarded_divide(half n,half d){return n/(d+$kGuardedDivideEpsilon"
-");}$pure inline half3 $guarded_divide(half3 n,half d){return n/(d+$kGuardedDivideEpsilon"
+"(dst.w,src.w)+min(blendOp.zw,0.));return src*coeff.x+dst*coeff.y;}$pure half4"
+" blend_plus(half4 src,half4 dst){return min(src+dst,1.);}$pure half4 blend_modulate"
+"(half4 src,half4 dst){return src*dst;}$pure half4 blend_screen(half4 src,half4"
+" dst){return src+(1.-src)*dst;}$pure half $blend_overlay_component(half2 s,"
+"half2 d){return 2.*d.x<=d.y?(2.*s.x)*d.x:s.y*d.y-(2.*(d.y-d.x))*(s.y-s.x);}"
+"$pure half4 blend_overlay(half4 src,half4 dst){half4 result=half4($blend_overlay_component"
+"(src.xw,dst.xw),$blend_overlay_component(src.yw,dst.yw),$blend_overlay_component"
+"(src.zw,dst.zw),src.w+(1.-src.w)*dst.w);result.xyz+=dst.xyz*(1.-src.w)+src."
+"xyz*(1.-dst.w);return result;}$pure half4 blend_overlay(half flip,half4 a,half4"
+" b){return blend_overlay(bool(flip)?b:a,bool(flip)?a:b);}$pure half4 blend_lighten"
+"(half4 src,half4 dst){half4 result=blend_src_over(src,dst);result.xyz=max(result"
+".xyz,(1.-dst.w)*src.xyz+dst.xyz);return result;}$pure half4 blend_darken(half"
+" mode,half4 src,half4 dst){half4 a=blend_src_over(src,dst);half3 b=(1.-dst."
+"w)*src.xyz+dst.xyz;a.xyz=mode*min(a.xyz*mode,b*mode);return a;}$pure half4 blend_darken"
+"(half4 src,half4 dst){return blend_darken(1.,src,dst);}const half $kGuardedDivideEpsilon"
+"=half(sk_Caps.mustGuardDivisionEvenAfterExplicitZeroCheck?1e-08:0.);$pure inline"
+" half $guarded_divide(half n,half d){return n/(d+$kGuardedDivideEpsilon);}$pure"
+" inline half3 $guarded_divide(half3 n,half d){return n/(d+$kGuardedDivideEpsilon"
 ");}$pure half $color_dodge_component(half2 s,half2 d){if(d.x==0.)return s.x"
 "*(1.-d.y);else{half delta=s.y-s.x;if(delta==0.)return(s.y*d.y+s.x*(1.-d.y))"
 "+d.x*(1.-s.y);else{delta=min(d.y,$guarded_divide(d.x*s.y,delta));return(delta"
diff --git a/src/sksl/generated/sksl_graphite_frag.minified.sksl b/src/sksl/generated/sksl_graphite_frag.minified.sksl
index b13dec6..7357e8d 100644
--- a/src/sksl/generated/sksl_graphite_frag.minified.sksl
+++ b/src/sksl/generated/sksl_graphite_frag.minified.sksl
@@ -176,64 +176,64 @@
 " blend_porter_duff(half4(0.,0.,0.,-1.),a,b);case 9:return blend_porter_duff"
 "(half4(0.,0.,1.,-1.),a,b);case 10:return blend_porter_duff(half4(0.,0.,-1.,"
 "1.),a,b);case 11:return blend_porter_duff(half4(0.,0.,-1.,-1.),a,b);case 12"
-":return blend_porter_duff(half4(1.,1.,0.,0.),a,b);case 13:return blend_modulate"
-"(a,b);case 14:return blend_screen(a,b);case 15:return blend_overlay(0.,a,b)"
-";case 16:return blend_darken(1.,a,b);case 17:return blend_darken(-1.,a,b);case"
-" 18:return blend_color_dodge(a,b);case 19:return blend_color_burn(a,b);case"
-" 20:return blend_overlay(1.,a,b);case 21:return blend_soft_light(a,b);case 22"
-":return blend_difference(a,b);case 23:return blend_exclusion(a,b);case 24:return"
-" blend_multiply(a,b);case 25:return blend_hslc(half2(0.,1.),a,b);case 26:return"
-" blend_hslc(half2(1.),a,b);case 27:return blend_hslc(half2(0.),a,b);case 28"
-":return blend_hslc(half2(1.,0.),a,b);default:return half4(0.);}}$pure half4"
-" sk_coeff_blend(half4 a,half4 b,half4 c){return blend_porter_duff(c,a,b);}$pure"
-" half4 sk_table_colorfilter(half4 a,sampler2D b){half4 c=unpremul(a)*.99609375"
-"+.001953125;half4 d=half4(sample(b,float2(half2(c.x,.375))).x,sample(b,float2"
-"(half2(c.y,.625))).x,sample(b,float2(half2(c.z,.875))).x,1.);return d*sample"
-"(b,float2(half2(c.w,.125))).x;}$pure half4 sk_gaussian_colorfilter(half4 a)"
-"{half b=1.-a.w;b=exp((-b*b)*4.)-.018;return half4(b);}$pure half4 sample_indexed_atlas"
-"(float2 a,int b,sampler2D c,sampler2D d,sampler2D e,sampler2D f){switch(b){"
-"case 1:return sample(d,a);case 2:return sample(e,a);case 3:return sample(f,"
-"a);default:return sample(c,a);}}$pure half3 $C(float2 a,int b,half2 c,sampler2D"
-" d,sampler2D e,sampler2D f,sampler2D g){half3 h=half3(1.);switch(b){case 1:"
-"h.x=sample(e,float2(half2(a)-c)).x;h.y=sample(e,a).x;h.z=sample(e,float2(half2"
-"(a)+c)).x;case 2:h.x=sample(f,float2(half2(a)-c)).x;h.y=sample(f,a).x;h.z=sample"
-"(f,float2(half2(a)+c)).x;case 3:h.x=sample(g,float2(half2(a)-c)).x;h.y=sample"
-"(g,a).x;h.z=sample(g,float2(half2(a)+c)).x;default:h.x=sample(d,float2(half2"
-"(a)-c)).x;h.y=sample(d,a).x;h.z=sample(d,float2(half2(a)+c)).x;}return h;}$pure"
-" half4 bitmap_text_coverage_fn(half4 a,int b){return b==0?a.xxxx:a;}$pure half4"
-" sdf_text_coverage_fn(half a,half2 b,float2 c){half d=7.96875*(a-.5019608);"
-"d-=b.x;half2 e=half2(dFdx(d),dFdy(d));half f=dot(e,e);e=f>=.0001?e*inversesqrt"
-"(f):half2(.7071);float2x2 g=float2x2(dFdx(c),dFdy(c));half2 h=half2(g*float2"
-"(e));half i=.65*length(h);if(b.y>0.)return half4(saturate((d+i)/(2.*i)));else"
-" return half4(smoothstep(-i,i,d));}$pure half4 sdf_text_lcd_coverage_fn(float2"
-" a,half2 b,half4 c,float2 d,float e,sampler2D f,sampler2D g,sampler2D h,sampler2D"
-" i){float2x2 j=float2x2(dFdx(d),dFdy(d));half2 k=half2(j*float2(b));half3 l"
-"=$C(a,int(e),k,f,g,h,i);half3 m=half3(7.96875)*(l-half3(.5019608));m-=c.xyz"
-";half2 n=half2(dFdx(m.y),dFdy(m.y));half o=dot(n,n);n=o>=.0001?n*inversesqrt"
-"(o):half2(.7071);half2 p=half2(j*float2(n));half3 q=half3(.65*length(p));if"
-"(c.w>0.)return half4(saturate(m+q/(2.*q)),1.);else return half4(smoothstep("
-"-q,q,m),1.);}$pure float $D(float2 a,float2x2 b){float2 c=a*b;return inversesqrt"
-"(dot(c,c));}$pure float2 $E(float2 a,float2 b,float c,float2x2 d){float2 e="
-"1./(b*b+c*c);float2 g=e*a;float h=$D(g,d);float i=(.5*h)*(dot(a,g)-1.);float"
-" j=((b.x*c)*e.x)*h;return float2(j-i,j+i);}void $F(inout float2 a,float2x2 b"
-",float2 c,float2 d,float2 e,float2 f){float2 g=f-d;if(all(greaterThan(g,float2"
-"(0.))))if(all(greaterThan(f,float2(0.)))||c.x>0.&&c.y<0.){float2 h=$E(g*e,f"
-",c.x,b);h.y=f.x-c.x<=0.?1.:-h.y;a=min(a,h);}else if(c.y==0.){float h=((c.x-"
-"g.x)-g.y)*$D(e,b);a.x=min(a.x,h);}}void $G(inout float2 a,float2x2 b,float2"
-" c,float4 e,float4 f,float4 g){$F(a,b,c,e.xy,float2(-1.),float2(f.x,g.x));$F"
-"(a,b,c,e.zy,float2(1.,-1.),float2(f.y,g.y));$F(a,b,c,e.zw,float2(1.),float2"
-"(f.z,g.z));$F(a,b,c,e.xw,float2(-1.,1.),float2(f.w,g.w));}$pure half4 analytic_rrect_coverage_fn"
-"(float4 a,float4 b,float4 c,float4 d,float4 e,float2 f,float2 g){if(g.x>0.)"
-"return half4(1.);else if(g.y>1.){float2 h=min(c.xy,c.zw);float i=min(h.x,h."
-"y)*a.w;float j=(g.y-1.)*a.w;float k=coverage_bias(j);return half4(half(saturate"
-"(j*(i+k))));}else{float2x2 h=float2x2(b)*(1./a.w);float2 i=float2($D(float2"
-"(1.,0.),h),$D(float2(0.,1.),h));float2 j=i*(f.x+min(c.xy,c.zw));float2 k=float2"
-"(min(j.x,j.y),-1.);float l;float m;if(g.x>-.95){float2 n=i*((c.xy+c.zw)+2.*"
-"f.xx);l=min(min(n.x,n.y),1.);m=coverage_bias(l);}else{float2 n=(2.*f.x)*i;float2"
-" o=n-j;k.y=-max(o.x,o.y);if(f.x>0.){float p=min(n.x,n.y);float2 q=mix(float2"
-"(p),n,greaterThanEqual(o,float2(-.5)));l=saturate(max(q.x,q.y));m=coverage_bias"
-"(l);}else l=(m=1.);}$G(k,h,f,c,d,e);float n=min(g.y,0.)*a.w;float o=l*(min("
-"k.x+n,-k.y)+m);return half4(half(saturate(o)));}}$pure half4 per_edge_aa_quad_coverage_fn"
+":return blend_plus(a,b);case 13:return blend_modulate(a,b);case 14:return blend_screen"
+"(a,b);case 15:return blend_overlay(0.,a,b);case 16:return blend_darken(1.,a"
+",b);case 17:return blend_darken(-1.,a,b);case 18:return blend_color_dodge(a"
+",b);case 19:return blend_color_burn(a,b);case 20:return blend_overlay(1.,a,"
+"b);case 21:return blend_soft_light(a,b);case 22:return blend_difference(a,b"
+");case 23:return blend_exclusion(a,b);case 24:return blend_multiply(a,b);case"
+" 25:return blend_hslc(half2(0.,1.),a,b);case 26:return blend_hslc(half2(1.)"
+",a,b);case 27:return blend_hslc(half2(0.),a,b);case 28:return blend_hslc(half2"
+"(1.,0.),a,b);default:return half4(0.);}}$pure half4 sk_coeff_blend(half4 a,"
+"half4 b,half4 c){return blend_porter_duff(c,a,b);}$pure half4 sk_table_colorfilter"
+"(half4 a,sampler2D b){half4 c=unpremul(a)*.99609375+.001953125;half4 d=half4"
+"(sample(b,float2(half2(c.x,.375))).x,sample(b,float2(half2(c.y,.625))).x,sample"
+"(b,float2(half2(c.z,.875))).x,1.);return d*sample(b,float2(half2(c.w,.125))"
+").x;}$pure half4 sk_gaussian_colorfilter(half4 a){half b=1.-a.w;b=exp((-b*b"
+")*4.)-.018;return half4(b);}$pure half4 sample_indexed_atlas(float2 a,int b"
+",sampler2D c,sampler2D d,sampler2D e,sampler2D f){switch(b){case 1:return sample"
+"(d,a);case 2:return sample(e,a);case 3:return sample(f,a);default:return sample"
+"(c,a);}}$pure half3 $C(float2 a,int b,half2 c,sampler2D d,sampler2D e,sampler2D"
+" f,sampler2D g){half3 h=half3(1.);switch(b){case 1:h.x=sample(e,float2(half2"
+"(a)-c)).x;h.y=sample(e,a).x;h.z=sample(e,float2(half2(a)+c)).x;case 2:h.x=sample"
+"(f,float2(half2(a)-c)).x;h.y=sample(f,a).x;h.z=sample(f,float2(half2(a)+c))"
+".x;case 3:h.x=sample(g,float2(half2(a)-c)).x;h.y=sample(g,a).x;h.z=sample(g"
+",float2(half2(a)+c)).x;default:h.x=sample(d,float2(half2(a)-c)).x;h.y=sample"
+"(d,a).x;h.z=sample(d,float2(half2(a)+c)).x;}return h;}$pure half4 bitmap_text_coverage_fn"
+"(half4 a,int b){return b==0?a.xxxx:a;}$pure half4 sdf_text_coverage_fn(half"
+" a,half2 b,float2 c){half d=7.96875*(a-.5019608);d-=b.x;half2 e=half2(dFdx("
+"d),dFdy(d));half f=dot(e,e);e=f>=.0001?e*inversesqrt(f):half2(.7071);float2x2"
+" g=float2x2(dFdx(c),dFdy(c));half2 h=half2(g*float2(e));half i=.65*length(h"
+");if(b.y>0.)return half4(saturate((d+i)/(2.*i)));else return half4(smoothstep"
+"(-i,i,d));}$pure half4 sdf_text_lcd_coverage_fn(float2 a,half2 b,half4 c,float2"
+" d,float e,sampler2D f,sampler2D g,sampler2D h,sampler2D i){float2x2 j=float2x2"
+"(dFdx(d),dFdy(d));half2 k=half2(j*float2(b));half3 l=$C(a,int(e),k,f,g,h,i)"
+";half3 m=half3(7.96875)*(l-half3(.5019608));m-=c.xyz;half2 n=half2(dFdx(m.y"
+"),dFdy(m.y));half o=dot(n,n);n=o>=.0001?n*inversesqrt(o):half2(.7071);half2"
+" p=half2(j*float2(n));half3 q=half3(.65*length(p));if(c.w>0.)return half4(saturate"
+"(m+q/(2.*q)),1.);else return half4(smoothstep(-q,q,m),1.);}$pure float $D(float2"
+" a,float2x2 b){float2 c=a*b;return inversesqrt(dot(c,c));}$pure float2 $E(float2"
+" a,float2 b,float c,float2x2 d){float2 e=1./(b*b+c*c);float2 g=e*a;float h="
+"$D(g,d);float i=(.5*h)*(dot(a,g)-1.);float j=((b.x*c)*e.x)*h;return float2("
+"j-i,j+i);}void $F(inout float2 a,float2x2 b,float2 c,float2 d,float2 e,float2"
+" f){float2 g=f-d;if(all(greaterThan(g,float2(0.))))if(all(greaterThan(f,float2"
+"(0.)))||c.x>0.&&c.y<0.){float2 h=$E(g*e,f,c.x,b);h.y=f.x-c.x<=0.?1.:-h.y;a="
+"min(a,h);}else if(c.y==0.){float h=((c.x-g.x)-g.y)*$D(e,b);a.x=min(a.x,h);}"
+"}void $G(inout float2 a,float2x2 b,float2 c,float4 e,float4 f,float4 g){$F("
+"a,b,c,e.xy,float2(-1.),float2(f.x,g.x));$F(a,b,c,e.zy,float2(1.,-1.),float2"
+"(f.y,g.y));$F(a,b,c,e.zw,float2(1.),float2(f.z,g.z));$F(a,b,c,e.xw,float2(-"
+"1.,1.),float2(f.w,g.w));}$pure half4 analytic_rrect_coverage_fn(float4 a,float4"
+" b,float4 c,float4 d,float4 e,float2 f,float2 g){if(g.x>0.)return half4(1.)"
+";else if(g.y>1.){float2 h=min(c.xy,c.zw);float i=min(h.x,h.y)*a.w;float j=("
+"g.y-1.)*a.w;float k=coverage_bias(j);return half4(half(saturate(j*(i+k))));"
+"}else{float2x2 h=float2x2(b)*(1./a.w);float2 i=float2($D(float2(1.,0.),h),$D"
+"(float2(0.,1.),h));float2 j=i*(f.x+min(c.xy,c.zw));float2 k=float2(min(j.x,"
+"j.y),-1.);float l;float m;if(g.x>-.95){float2 n=i*((c.xy+c.zw)+2.*f.xx);l=min"
+"(min(n.x,n.y),1.);m=coverage_bias(l);}else{float2 n=(2.*f.x)*i;float2 o=n-j"
+";k.y=-max(o.x,o.y);if(f.x>0.){float p=min(n.x,n.y);float2 q=mix(float2(p),n"
+",greaterThanEqual(o,float2(-.5)));l=saturate(max(q.x,q.y));m=coverage_bias("
+"l);}else l=(m=1.);}$G(k,h,f,c,d,e);float n=min(g.y,0.)*a.w;float o=l*(min(k"
+".x+n,-k.y)+m);return half4(half(saturate(o)));}}$pure half4 per_edge_aa_quad_coverage_fn"
 "(float4 a,float4 b){float2 d=min(b.xy,b.zw);float e=min(d.x,d.y)*a.w;return"
 " half4(half(saturate(e)));}$pure half4 $H(float2 a,float4 b,half c,half d,sampler2D"
 " e){half f;half g;if(c!=0.){half2 h=max(half2(b.xy-a),half2(a-b.zw));f=sample"
diff --git a/src/sksl/generated/sksl_graphite_frag.unoptimized.sksl b/src/sksl/generated/sksl_graphite_frag.unoptimized.sksl
index 42cebed..3c65d82 100644
--- a/src/sksl/generated/sksl_graphite_frag.unoptimized.sksl
+++ b/src/sksl/generated/sksl_graphite_frag.unoptimized.sksl
@@ -321,12 +321,12 @@
 ",0.),src,dst);case 8:return blend_porter_duff(half4(0.,0.,0.,-1.),src,dst);"
 "case 9:return blend_porter_duff(half4(0.,0.,1.,-1.),src,dst);case 10:return"
 " blend_porter_duff(half4(0.,0.,-1.,1.),src,dst);case 11:return blend_porter_duff"
-"(half4(0.,0.,-1.,-1.),src,dst);case 12:return blend_porter_duff(half4(1.,1."
-",0.,0.),src,dst);case 13:return blend_modulate(src,dst);case 14:return blend_screen"
-"(src,dst);case 15:return blend_overlay(0.,src,dst);case 16:return blend_darken"
-"(1.,src,dst);case 17:return blend_darken(-1.,src,dst);case 18:return blend_color_dodge"
-"(src,dst);case 19:return blend_color_burn(src,dst);case 20:return blend_overlay"
-"(1.,src,dst);case 21:return blend_soft_light(src,dst);case 22:return blend_difference"
+"(half4(0.,0.,-1.,-1.),src,dst);case 12:return blend_plus(src,dst);case 13:return"
+" blend_modulate(src,dst);case 14:return blend_screen(src,dst);case 15:return"
+" blend_overlay(0.,src,dst);case 16:return blend_darken(1.,src,dst);case 17:"
+"return blend_darken(-1.,src,dst);case 18:return blend_color_dodge(src,dst);"
+"case 19:return blend_color_burn(src,dst);case 20:return blend_overlay(1.,src"
+",dst);case 21:return blend_soft_light(src,dst);case 22:return blend_difference"
 "(src,dst);case 23:return blend_exclusion(src,dst);case 24:return blend_multiply"
 "(src,dst);case 25:return blend_hslc(half2(0.,1.),src,dst);case 26:return blend_hslc"
 "(half2(1.),src,dst);case 27:return blend_hslc(half2(0.),src,dst);case 28:return"
diff --git a/src/sksl/sksl_gpu.sksl b/src/sksl/sksl_gpu.sksl
index 4c4e09d..6621627 100644
--- a/src/sksl/sksl_gpu.sksl
+++ b/src/sksl/sksl_gpu.sksl
@@ -85,9 +85,7 @@
 
 $pure half4 blend_xor(half4 src, half4 dst) { return (1 - dst.a)*src + (1 - src.a)*dst; }
 
-$pure half4 blend_plus(half4 src, half4 dst) { return min(src + dst, 1); }
-
-// This multi-purpose Porter-Duff blend function can perform any of the thirteen blends above,
+// This multi-purpose Porter-Duff blend function can perform any of the twelve blends above,
 // when passed one of the following values for BlendOp:
 // - Clear:   half4(0, 0,  0,  0)
 // - Src:     half4(1, 0,  0,  0)
@@ -101,12 +99,13 @@
 // - SrcATop: half4(0, 0,  1, -1)
 // - DstATop: half4(0, 0, -1,  1)
 // - Xor:     half4(0, 0, -1, -1)
-// - Plus:    half4(1, 1,  0,  0)
 $pure half4 blend_porter_duff(half4 blendOp, half4 src, half4 dst) {
     half2 coeff = blendOp.xy + (blendOp.zw * (half2(dst.a, src.a) + min(blendOp.zw, 0)));
-    return min(half4(1), src * coeff.x + dst * coeff.y);
+    return src * coeff.x + dst * coeff.y;
 }
 
+$pure half4 blend_plus(half4 src, half4 dst) { return min(src + dst, 1); }
+
 $pure half4 blend_modulate(half4 src, half4 dst) { return src*dst; }
 
 $pure half4 blend_screen(half4 src, half4 dst) { return src + (1 - src)*dst; }
diff --git a/src/sksl/sksl_graphite_frag.sksl b/src/sksl/sksl_graphite_frag.sksl
index 328dae2..2e93bdb 100644
--- a/src/sksl/sksl_graphite_frag.sksl
+++ b/src/sksl/sksl_graphite_frag.sksl
@@ -1199,7 +1199,7 @@
         case kSrcATop:    return blend_porter_duff(half4(0, 0,  1, -1), src, dst);
         case kDstATop:    return blend_porter_duff(half4(0, 0, -1,  1), src, dst);
         case kXor:        return blend_porter_duff(half4(0, 0, -1, -1), src, dst);
-        case kPlus:       return blend_porter_duff(half4(1, 1,  0,  0), src, dst);
+        case kPlus:       return blend_plus(src, dst);
         case kModulate:   return blend_modulate(src, dst);
         case kScreen:     return blend_screen(src, dst);
         case kOverlay:    return blend_overlay(/*flip=*/0, src, dst);