<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[287310] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/287310">287310</a></dd>
<dt>Author</dt> <dd>weinig@apple.com</dd>
<dt>Date</dt> <dd>2021-12-21 04:42:19 -0800 (Tue, 21 Dec 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add support for premultiplied alpha interpolated gradients and defaulted off option to use them for CSS Gradients
https://bugs.webkit.org/show_bug.cgi?id=234492

Reviewed by Simon Fraser.

Source/WebCore:

Tests: fast/gradients/alpha-premultiplied.html
       fast/gradients/conic-gradient-alpha-unpremultiplied.html

Extracts use of CGGradientRef out of Gradient and into the new GradientRendererCG which also implements
a CGShadingRef based gradient drawing path. The GradientRendererCG picks which strategy, CGGradientRef
or CGShadingRef, based on the intepolation mode and capabilities of the underlying CoreGraphics. For
new enough CoreGraphics, both premultiplied and non-premultiplied alpha interpolation for sRGB output
are supported in the more optimizable CGGradientRef path, but on older systems we will fallback to a
a newly implemented CGShadingRef based implementation.

In addition to the platform level work in Gradient, this adds a new setting, CSSGradientPremultipliedAlphaInterpolationEnabled,
which defaults to off for now and switches what type of interpolation we use for CSS gradients. It
does not effect other gradient uses such as by canvas or SVG. Those will be enabled separately.

* Headers.cmake:
* PlatformAppleWin.cmake:
* PlatformMac.cmake:
* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
Add new files.

* css/CSSGradientValue.cpp:
(WebCore::LinearGradientAdapter::normalizeStopsAndEndpointsOutsideRange):
(WebCore::RadialGradientAdapter::normalizeStopsAndEndpointsOutsideRange):
(WebCore::ConicGradientAdapter::normalizeStopsAndEndpointsOutsideRange):
(WebCore::CSSGradientValue::computeStops):
Switch to using the new interpolateColors() function from ColorInterpolation.h
which accurately takes into account the current interpolation mode. These
blends now match what the created gradient does.

* css/parser/CSSParserContext.cpp:
* css/parser/CSSParserContext.h:
Add support for querying CSSGradientPremultipliedAlphaInterpolationEnabled from the CSS parser.

* css/parser/CSSPropertyParserHelpers.cpp:
(WebCore::CSSPropertyParserHelpers::gradientAlphaPremultiplication):
(WebCore::CSSPropertyParserHelpers::consumeDeprecatedGradient):
(WebCore::CSSPropertyParserHelpers::consumeDeprecatedRadialGradient):
(WebCore::CSSPropertyParserHelpers::consumeRadialGradient):
(WebCore::CSSPropertyParserHelpers::consumeLinearGradient):
(WebCore::CSSPropertyParserHelpers::consumeConicGradient):
Depending on how CSSGradientPremultipliedAlphaInterpolationEnabled is set, use either premultiplied
or non-premultiplied interpolation for CSS gradients.

* platform/graphics/ColorComponents.h:
(WebCore::ColorComponents::size const):
Add size() function for use by the shading strategy.

* platform/graphics/ColorInterpolation.h:
(WebCore::preInterpolationNormalizationForComponent):
(WebCore::preInterpolationNormalization):
(WebCore::postInterpolationNormalizationForComponent):
(WebCore::postInterpolationNormalization):
(WebCore::interpolateColorComponents):
Update to use the name InterpolationMethodColorSpace consistenly for the color space part of the
interpolation method.

(WebCore::interpolateColors):
Add helper which takes and returns Color objects rather than the strongly typed color types,
automatically converting to the appropriate interpolation color space based on the provided
ColorInterpolationMethod object.

* platform/graphics/Gradient.h:
* platform/graphics/GradientColorStop.h: Added.
Move ColorStop and ColorStopVector defintions to new GradientColorStop file, but keep the
old nested names via using directives. This is needed to make using the ColorStopVector
from GradientRendererCG (which we also want to use in Gradient.h) possible without redeclaration.
Replace CGGradientRef member with GradientRendererCG which allows choosing between either
a CGGradientRef based implementation or CGShadingRef based one.

* platform/graphics/cg/GradientCG.cpp:
Update to use the GradientRendererCG rathern than a CGGradientRef directly, calling into it
to do the actual draw calls.

* platform/graphics/cg/GradientRendererCG.h: Added.
* platform/graphics/cg/GradientRendererCG.cpp: Added.
(WebCore::GradientRendererCG::pickStrategy const):
Central function to choose which strategy to use based on system capabilities and interpolation needs.

(WebCore::GradientRendererCG::makeGradient const):
Moved from GradientCG.cpp. Removed the CGGradientCreateWithColors() path, as we can always use the
more efficient CGGradientCreateWithColorComponents() by doing the conversion to extended sRGB ourselves.
Also adds use of the kCGGradientInterpolatesPremultiplied option on supported systems to tell CoreGraphics
to use premulitplied interpolation.

(WebCore::shadingFunction):
Core function used by CGShadingRef to interpolate between color stops. Templatized to allow for optimized
versions for every ColorInterpolationColorSpace / AlphaPremultiplication pair.

(WebCore::GradientRendererCG::makeShading const):
Builds shading strategy by converting all color stops to the interpolation color space, adding stops at
0 and 1 if necessary, and creating the CGFunctionRef that the shading will own. To avoid a circular
reference, the GradientRendererCG itself is not what the CGFunctionRef retains, but rather a subobject
Data, which is a peer to the CGFunctionRef.

(WebCore::GradientRendererCG::drawLinearGradient):
(WebCore::GradientRendererCG::drawRadialGradient):
(WebCore::GradientRendererCG::drawConicGradient):
Draw the gradient or shading based on the strategy selected at construction.

Source/WebCore/PAL:

* pal/spi/cg/CoreGraphicsSPI.h:
Add forwards for creating conic shadings and enabling premultiplied alpha interpolation for gradients.

Source/WebKitLegacy/win:

Add support for tests enabling the CSSGradientPremultipliedAlphaInterpolationEnabled preference.

* WebPreferences.cpp:
(WebPreferences::cssGradientPremultipliedAlphaInterpolationEnabled):
* WebPreferences.h:
* WebView.cpp:
(WebView::notifyPreferencesChanged):

Source/WTF:

* Scripts/Preferences/WebPreferencesExperimental.yaml:
Add a new experimental setting to enable premultiplied alpha CSS gradients.

Tools:

* DumpRenderTree/TestOptions.cpp:
(WTR::TestOptions::defaults):
Add default for Windows WebKitLegacy testing which still requires it.

LayoutTests:

Add and update tests for gradients with alpha now that we have support for premultiplied interpolation.
By default, the tests now enable premultiplied interpolation (since it is an experimental feature) so
to continue testing the old path, the setting must be explicitly disabled.

* fast/gradients/alpha-premultiplied-expected.html: Added.
* fast/gradients/alpha-premultiplied.html: Added.
* fast/gradients/conic-gradient-alpha-expected.html:
* fast/gradients/conic-gradient-alpha-unpremultiplied-expected.html: Added.
* fast/gradients/conic-gradient-alpha-unpremultiplied.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfastgradientsconicgradientalphaexpectedhtml">trunk/LayoutTests/fast/gradients/conic-gradient-alpha-expected.html</a></li>
<li><a href="#trunkLayoutTestsplatformglibTestExpectations">trunk/LayoutTests/platform/glib/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformwinTestExpectations">trunk/LayoutTests/platform/win/TestExpectations</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFScriptsPreferencesWebPreferencesExperimentalyaml">trunk/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreHeaderscmake">trunk/Source/WebCore/Headers.cmake</a></li>
<li><a href="#trunkSourceWebCorePALChangeLog">trunk/Source/WebCore/PAL/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorePALpalspicgCoreGraphicsSPIh">trunk/Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h</a></li>
<li><a href="#trunkSourceWebCorePlatformAppleWincmake">trunk/Source/WebCore/PlatformAppleWin.cmake</a></li>
<li><a href="#trunkSourceWebCorePlatformMaccmake">trunk/Source/WebCore/PlatformMac.cmake</a></li>
<li><a href="#trunkSourceWebCoreSourcesCocoatxt">trunk/Source/WebCore/SourcesCocoa.txt</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCorecssCSSGradientValuecpp">trunk/Source/WebCore/css/CSSGradientValue.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserContextcpp">trunk/Source/WebCore/css/parser/CSSParserContext.cpp</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSParserContexth">trunk/Source/WebCore/css/parser/CSSParserContext.h</a></li>
<li><a href="#trunkSourceWebCorecssparserCSSPropertyParserHelperscpp">trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsColorComponentsh">trunk/Source/WebCore/platform/graphics/ColorComponents.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsColorInterpolationh">trunk/Source/WebCore/platform/graphics/ColorInterpolation.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsColorNormalizationh">trunk/Source/WebCore/platform/graphics/ColorNormalization.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsGradienth">trunk/Source/WebCore/platform/graphics/Gradient.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgGradientCGcpp">trunk/Source/WebCore/platform/graphics/cg/GradientCG.cpp</a></li>
<li><a href="#trunkSourceWebKitLegacywinChangeLog">trunk/Source/WebKitLegacy/win/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitLegacywinWebPreferencescpp">trunk/Source/WebKitLegacy/win/WebPreferences.cpp</a></li>
<li><a href="#trunkSourceWebKitLegacywinWebPreferencesh">trunk/Source/WebKitLegacy/win/WebPreferences.h</a></li>
<li><a href="#trunkSourceWebKitLegacywinWebViewcpp">trunk/Source/WebKitLegacy/win/WebView.cpp</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsDumpRenderTreeTestOptionscpp">trunk/Tools/DumpRenderTree/TestOptions.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastgradientsalphapremultipliedexpectedhtml">trunk/LayoutTests/fast/gradients/alpha-premultiplied-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastgradientsalphapremultipliedhtml">trunk/LayoutTests/fast/gradients/alpha-premultiplied.html</a></li>
<li><a href="#trunkLayoutTestsfastgradientsconicgradientalphaunpremultipliedexpectedhtml">trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied-expected.html</a></li>
<li><a href="#trunkLayoutTestsfastgradientsconicgradientalphaunpremultipliedhtml">trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied.html</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsGradientColorStoph">trunk/Source/WebCore/platform/graphics/GradientColorStop.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgGradientRendererCGcpp">trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicscgGradientRendererCGh">trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/LayoutTests/ChangeLog 2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2021-12-21  Sam Weinig  <weinig@apple.com>
+
+        Add support for premultiplied alpha interpolated gradients and defaulted off option to use them for CSS Gradients
+        https://bugs.webkit.org/show_bug.cgi?id=234492
+
+        Reviewed by Simon Fraser.
+
+        Add and update tests for gradients with alpha now that we have support for premultiplied interpolation.
+        By default, the tests now enable premultiplied interpolation (since it is an experimental feature) so
+        to continue testing the old path, the setting must be explicitly disabled.
+
+        * fast/gradients/alpha-premultiplied-expected.html: Added.
+        * fast/gradients/alpha-premultiplied.html: Added.
+        * fast/gradients/conic-gradient-alpha-expected.html:
+        * fast/gradients/conic-gradient-alpha-unpremultiplied-expected.html: Added.
+        * fast/gradients/conic-gradient-alpha-unpremultiplied.html: Added.
+
</ins><span class="cx"> 2021-12-20  Jon Lee  <jonlee@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, garden GPU Process test expectations
</span></span></pre></div>
<a id="trunkLayoutTestsfastgradientsalphapremultipliedexpectedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/gradients/alpha-premultiplied-expected.html (0 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/gradients/alpha-premultiplied-expected.html                               (rev 0)
+++ trunk/LayoutTests/fast/gradients/alpha-premultiplied-expected.html  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    div { 
+        width: 100px;
+        height: 100px;
+    }
+
+    #linear {
+        background-image: linear-gradient(transparent, rgb(0, 0, 255));
+    }
+
+    #linear-repeating {
+        background-image: repeating-linear-gradient(transparent, rgb(0, 0, 255) 25px);
+    }
+
+    #radial {
+        background-image: radial-gradient(transparent, rgb(0, 0, 255));
+    }
+
+    #radial-repeating {
+        background-image: repeating-radial-gradient(transparent, rgb(0, 0, 255) 25px);
+    }
+
+    #conic {
+        background-image: conic-gradient(transparent, rgb(0, 0, 255));
+    }
+
+    #conic-repeating {
+        background-image: repeating-conic-gradient(transparent, rgb(0, 0, 255) 30deg);
+    }
+    
+</style>
+</head>
+<body>
+<div id="linear"></div>
+<div id="linear-repeating"></div>
+<div id="radial"></div>
+<div id="radial-repeating"></div>
+<div id="conic"></div>
+<div id="conic-repeating"></div>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastgradientsalphapremultipliedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/gradients/alpha-premultiplied.html (0 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/gradients/alpha-premultiplied.html                                (rev 0)
+++ trunk/LayoutTests/fast/gradients/alpha-premultiplied.html   2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    div { 
+        width: 100px;
+        height: 100px;
+    }
+
+    #linear {
+        background-image: linear-gradient(rgba(255, 0, 255, 0), rgb(0, 0, 255));
+    }
+
+    #linear-repeating {
+        background-image: repeating-linear-gradient(rgba(255, 0, 255, 0), rgb(0, 0, 255) 25px);
+    }
+
+    #radial {
+        background-image: radial-gradient(rgba(255, 0, 255, 0), rgb(0, 0, 255));
+    }
+
+    #radial-repeating {
+        background-image: repeating-radial-gradient(rgba(255, 0, 255, 0), rgb(0, 0, 255) 25px);
+    }
+
+    #conic {
+        background-image: conic-gradient(rgba(255, 0, 255, 0), rgb(0, 0, 255));
+    }
+
+    #conic-repeating {
+        background-image: repeating-conic-gradient(rgba(255, 0, 255, 0), rgb(0, 0, 255) 30deg);
+    }
+    
+</style>
+</head>
+<body>
+<div id="linear"></div>
+<div id="linear-repeating"></div>
+<div id="radial"></div>
+<div id="radial-repeating"></div>
+<div id="conic"></div>
+<div id="conic-repeating"></div>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastgradientsconicgradientalphaexpectedhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/gradients/conic-gradient-alpha-expected.html (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/gradients/conic-gradient-alpha-expected.html      2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/LayoutTests/fast/gradients/conic-gradient-alpha-expected.html 2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -10,27 +10,27 @@
</span><span class="cx">         #topleft {
</span><span class="cx">             width: 0; 
</span><span class="cx">             height: 0; 
</span><del>-            border-left: 100px solid rgb(64,87,64);
</del><ins>+            border-left: 100px solid rgb(64,64,64);
</ins><span class="cx">             border-top: 100px solid rgb(32,32,32);
</span><span class="cx">         }
</span><span class="cx">         #topright {
</span><span class="cx">             width: 0; 
</span><span class="cx">             height: 0; 
</span><del>-            border-right: 100px solid rgb(225,246,225);
-            border-top: 100px solid rgb(254,254,254);
</del><ins>+            border-right: 100px solid rgb(224,224,224);
+            border-top: 100px solid rgb(255,255,255);
</ins><span class="cx">         }
</span><span class="cx">         #bottomleft {
</span><span class="cx">             clear: left;
</span><span class="cx">             width: 0; 
</span><span class="cx">             height: 0; 
</span><del>-            border-left: 100px solid rgb(96,135,96);
-            border-bottom: 100px solid rgb(128,175,128);
</del><ins>+            border-left: 100px solid rgb(96,96,96);
+            border-bottom: 100px solid rgb(128,128,128);
</ins><span class="cx">         }
</span><span class="cx">         #bottomright {
</span><span class="cx">             width: 0; 
</span><span class="cx">             height: 0; 
</span><del>-            border-right: 100px solid rgb(193,231,193);
-            border-bottom: 100px solid rgb(160,207,160);
</del><ins>+            border-right: 100px solid rgb(192,192,192);
+            border-bottom: 100px solid rgb(160,160,160);
</ins><span class="cx">         }
</span><span class="cx">         .box {
</span><span class="cx">             position: absolute;
</span></span></pre></div>
<a id="trunkLayoutTestsfastgradientsconicgradientalphaunpremultipliedexpectedhtmlfromrev287309trunkLayoutTestsfastgradientsconicgradientalphaexpectedhtml"></a>
<div class="copfile"><h4>Copied: trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied-expected.html (from rev 287309, trunk/LayoutTests/fast/gradients/conic-gradient-alpha-expected.html) (0 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied-expected.html                              (rev 0)
+++ trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied-expected.html 2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+<html><!-- webkit-test-runner [ CSSGradientPremultipliedAlphaInterpolationEnabled=false ] -->
+<head>
+    <style>
+        div {
+            width: 200px;
+            height: 200px;
+            float: left;
+        }
+        /*tweak this until it's actually right... */
+        #topleft {
+            width: 0; 
+            height: 0; 
+            border-left: 100px solid rgb(64,87,64);
+            border-top: 100px solid rgb(32,32,32);
+        }
+        #topright {
+            width: 0; 
+            height: 0; 
+            border-right: 100px solid rgb(225,246,225);
+            border-top: 100px solid rgb(254,254,254);
+        }
+        #bottomleft {
+            clear: left;
+            width: 0; 
+            height: 0; 
+            border-left: 100px solid rgb(96,135,96);
+            border-bottom: 100px solid rgb(128,175,128);
+        }
+        #bottomright {
+            width: 0; 
+            height: 0; 
+            border-right: 100px solid rgb(193,231,193);
+            border-bottom: 100px solid rgb(160,207,160);
+        }
+        .box {
+            position: absolute;
+        }
+        .x {
+            position: absolute;
+            -webkit-clip-path: polygon(0% 0%, 0% 10%, 40% 50%, 0% 90%, 0% 100%, 10% 100%, 50% 60%, 90% 100%, 100% 100%, 100% 90%, 60% 50%, 100% 10%, 100% 0%, 90% 0%, 50% 40%, 10% 0%);
+        }
+        #x {
+            background-color:white;
+        }
+        .plus {
+            position: absolute;
+            -webkit-clip-path: polygon(45% 0%, 55% 0%, 55% 45%, 100% 45%, 100% 55%, 55% 55%, 55% 100%, 45% 100%, 45% 55%, 0% 55%, 0% 45%, 45% 45%);
+        }
+        #plus {
+            background-color:white;
+        }
+        
+    </style>
+</head>
+<body>
+    <div>
+        <div class="box">
+            <div id="topleft"></div>
+            <div id="topright"></div>
+            <div id="bottomleft"></div>
+            <div id="bottomright"></div>
+        </div>
+        <div id="x" class="x"></div>
+        <div id="plus" class="plus"></div>
+    </div>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsfastgradientsconicgradientalphaunpremultipliedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied.html (0 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied.html                               (rev 0)
+++ trunk/LayoutTests/fast/gradients/conic-gradient-alpha-unpremultiplied.html  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+<html><!-- webkit-test-runner [ CSSGradientPremultipliedAlphaInterpolationEnabled=false ] -->
+<head>
+<style>
+    svg {
+        width: 800px;
+        display: none;
+    }
+    div {
+        width: 200px;
+        height: 200px;
+    }
+    #gradient {
+        position: absolute;
+        width: 200px;
+        height: 200px;
+        background-image: conic-gradient(rgba(0,255,0,0), black);
+        filter: url(#posterize);
+    }
+
+    .x {
+        position: absolute;
+        -webkit-clip-path: polygon(0% 0%, 0% 10%, 40% 50%, 0% 90%, 0% 100%, 10% 100%, 50% 60%, 90% 100%, 100% 100%, 100% 90%, 60% 50%, 100% 10%, 100% 0%, 90% 0%, 50% 40%, 10% 0%);
+    }
+    #x {
+        background-color:white;
+    }
+    .plus {
+        position: absolute;
+        -webkit-clip-path: polygon(45% 0%, 55% 0%, 55% 45%, 100% 45%, 100% 55%, 55% 55%, 55% 100%, 45% 100%, 45% 55%, 0% 55%, 0% 45%, 45% 45%);
+    }
+    #plus {
+        background-color:white;
+    }
+</style>
+</head>
+
+<body>
+<svg viewBox="0 0 700 100">
+<defs>
+    <filter id="posterize" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox">
+        <feComponentTransfer>
+            <feFuncR type="discrete" tableValues="0 0.125 0.25 0.375 0.5 0.625 0.75 0.875"/>
+            <feFuncG type="discrete" tableValues="0 0.125 0.25 0.375 0.5 0.625 0.75 0.875"/>
+            <feFuncB type="discrete" tableValues="0 0.125 0.25 0.375 0.5 0.625 0.75 0.875"/>
+            <feFuncA type="discrete" tableValues="0 0.125 0.25 0.375 0.5 0.625 0.75 0.875"/>
+        </feComponentTransfer>
+    </filter>
+</defs>
+</svg>
+
+<div>
+    <div id="gradient"></div>
+    <div id="x" class="x"></div>
+    <div id="plus" class="plus"></div>
+</div>
+</html>
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformglibTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/glib/TestExpectations (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/glib/TestExpectations 2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/LayoutTests/platform/glib/TestExpectations    2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -489,7 +489,9 @@
</span><span class="cx"> 
</span><span class="cx"> # fast/gradients are Skip in the top level Expectation. When fixing, change this to
</span><span class="cx"> # Pass instead of removing this line.
</span><ins>+webkit.org/b/214259 fast/gradients/conic-gradient-alpha-unpremultiplied.html [ ImageOnlyFailure ]
</ins><span class="cx"> webkit.org/b/214259 fast/gradients/conic-gradient-alpha.html [ ImageOnlyFailure ]
</span><ins>+webkit.org/b/234492 fast/gradients/alpha-premultiplied.html [ ImageOnlyFailure ]
</ins><span class="cx"> 
</span><span class="cx"> webkit.org/b/169988 css3/filters/backdrop/backdrop-filter-with-border-radius-and-reflection-add.html [ ImageOnlyFailure ]
</span><span class="cx"> webkit.org/b/169988 css3/filters/backdrop/backdrop-filter-with-border-radius-and-reflection.html [ ImageOnlyFailure ]
</span></span></pre></div>
<a id="trunkLayoutTestsplatformwinTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/win/TestExpectations (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/win/TestExpectations  2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/LayoutTests/platform/win/TestExpectations     2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -295,6 +295,7 @@
</span><span class="cx"> fast/gradients/conic-extended-stops.html [ Skip ]
</span><span class="cx"> fast/gradients/conic-from-angle.html [ Skip ]
</span><span class="cx"> fast/gradients/conic-repeating-last-stop.html [ Skip ]
</span><ins>+fast/gradients/conic-gradient-alpha-unpremultiplied.html [ Skip ]
</ins><span class="cx"> fast/gradients/conic-gradient-alpha.html [ Skip ]
</span><span class="cx"> fast/gradients/conic-gradient-extended-stops.html [ Skip ]
</span><span class="cx"> fast/gradients/conic-gradient.html [ Skip ]
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog       2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WTF/ChangeLog  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2021-12-21  Sam Weinig  <weinig@apple.com>
+
+        Add support for premultiplied alpha interpolated gradients and defaulted off option to use them for CSS Gradients
+        https://bugs.webkit.org/show_bug.cgi?id=234492
+
+        Reviewed by Simon Fraser.
+
+        * Scripts/Preferences/WebPreferencesExperimental.yaml:
+        Add a new experimental setting to enable premultiplied alpha CSS gradients. 
+
</ins><span class="cx"> 2021-12-21  Yusuke Suzuki  <ysuzuki@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [WTF] Remove RefCountedArray and use RefCountedFixedVector
</span></span></pre></div>
<a id="trunkSourceWTFScriptsPreferencesWebPreferencesExperimentalyaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml     2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml        2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -284,6 +284,18 @@
</span><span class="cx">     WebCore:
</span><span class="cx">       default: false
</span><span class="cx"> 
</span><ins>+CSSGradientPremultipliedAlphaInterpolationEnabled:
+  type: bool
+  humanReadableName: "CSS Gradient Premultiplied Alpha Interpolation"
+  humanReadableDescription: "Enable premultiplied alpha interpolated CSS gradients"
+  defaultValue:
+    WebKitLegacy:
+      default: false
+    WebKit:
+      default: false
+    WebCore:
+      default: false
+
</ins><span class="cx"> # FIXME: This is enabled when ENABLE(EXPERIMENTAL_FEATURES) is true in WebKit2. Perhaps we should consider using that for WebKitLegacy as well.
</span><span class="cx"> CSSIndividualTransformPropertiesEnabled:
</span><span class="cx">   type: bool
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/ChangeLog      2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -1,3 +1,110 @@
</span><ins>+2021-12-21  Sam Weinig  <weinig@apple.com>
+
+        Add support for premultiplied alpha interpolated gradients and defaulted off option to use them for CSS Gradients
+        https://bugs.webkit.org/show_bug.cgi?id=234492
+
+        Reviewed by Simon Fraser.
+
+        Tests: fast/gradients/alpha-premultiplied.html
+               fast/gradients/conic-gradient-alpha-unpremultiplied.html
+
+        Extracts use of CGGradientRef out of Gradient and into the new GradientRendererCG which also implements
+        a CGShadingRef based gradient drawing path. The GradientRendererCG picks which strategy, CGGradientRef
+        or CGShadingRef, based on the intepolation mode and capabilities of the underlying CoreGraphics. For 
+        new enough CoreGraphics, both premultiplied and non-premultiplied alpha interpolation for sRGB output
+        are supported in the more optimizable CGGradientRef path, but on older systems we will fallback to a 
+        a newly implemented CGShadingRef based implementation.
+
+        In addition to the platform level work in Gradient, this adds a new setting, CSSGradientPremultipliedAlphaInterpolationEnabled,
+        which defaults to off for now and switches what type of interpolation we use for CSS gradients. It
+        does not effect other gradient uses such as by canvas or SVG. Those will be enabled separately.
+
+        * Headers.cmake:
+        * PlatformAppleWin.cmake:
+        * PlatformMac.cmake:
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        Add new files.
+
+        * css/CSSGradientValue.cpp:
+        (WebCore::LinearGradientAdapter::normalizeStopsAndEndpointsOutsideRange):
+        (WebCore::RadialGradientAdapter::normalizeStopsAndEndpointsOutsideRange):
+        (WebCore::ConicGradientAdapter::normalizeStopsAndEndpointsOutsideRange):
+        (WebCore::CSSGradientValue::computeStops):
+        Switch to using the new interpolateColors() function from ColorInterpolation.h
+        which accurately takes into account the current interpolation mode. These
+        blends now match what the created gradient does.
+
+        * css/parser/CSSParserContext.cpp:
+        * css/parser/CSSParserContext.h:
+        Add support for querying CSSGradientPremultipliedAlphaInterpolationEnabled from the CSS parser.
+
+        * css/parser/CSSPropertyParserHelpers.cpp:
+        (WebCore::CSSPropertyParserHelpers::gradientAlphaPremultiplication):
+        (WebCore::CSSPropertyParserHelpers::consumeDeprecatedGradient):
+        (WebCore::CSSPropertyParserHelpers::consumeDeprecatedRadialGradient):
+        (WebCore::CSSPropertyParserHelpers::consumeRadialGradient):
+        (WebCore::CSSPropertyParserHelpers::consumeLinearGradient):
+        (WebCore::CSSPropertyParserHelpers::consumeConicGradient):
+        Depending on how CSSGradientPremultipliedAlphaInterpolationEnabled is set, use either premultiplied
+        or non-premultiplied interpolation for CSS gradients.
+
+        * platform/graphics/ColorComponents.h:
+        (WebCore::ColorComponents::size const):
+        Add size() function for use by the shading strategy.
+
+        * platform/graphics/ColorInterpolation.h:
+        (WebCore::preInterpolationNormalizationForComponent):
+        (WebCore::preInterpolationNormalization):
+        (WebCore::postInterpolationNormalizationForComponent):
+        (WebCore::postInterpolationNormalization):
+        (WebCore::interpolateColorComponents):
+        Update to use the name InterpolationMethodColorSpace consistenly for the color space part of the
+        interpolation method.
+  
+        (WebCore::interpolateColors):
+        Add helper which takes and returns Color objects rather than the strongly typed color types, 
+        automatically converting to the appropriate interpolation color space based on the provided
+        ColorInterpolationMethod object.
+
+        * platform/graphics/Gradient.h:
+        * platform/graphics/GradientColorStop.h: Added.
+        Move ColorStop and ColorStopVector defintions to new GradientColorStop file, but keep the
+        old nested names via using directives. This is needed to make using the ColorStopVector
+        from GradientRendererCG (which we also want to use in Gradient.h) possible without redeclaration.
+        Replace CGGradientRef member with GradientRendererCG which allows choosing between either
+        a CGGradientRef based implementation or CGShadingRef based one.
+
+        * platform/graphics/cg/GradientCG.cpp:
+        Update to use the GradientRendererCG rathern than a CGGradientRef directly, calling into it
+        to do the actual draw calls.
+
+        * platform/graphics/cg/GradientRendererCG.h: Added.
+        * platform/graphics/cg/GradientRendererCG.cpp: Added.
+        (WebCore::GradientRendererCG::pickStrategy const):
+        Central function to choose which strategy to use based on system capabilities and interpolation needs.
+
+        (WebCore::GradientRendererCG::makeGradient const):
+        Moved from GradientCG.cpp. Removed the CGGradientCreateWithColors() path, as we can always use the
+        more efficient CGGradientCreateWithColorComponents() by doing the conversion to extended sRGB ourselves.
+        Also adds use of the kCGGradientInterpolatesPremultiplied option on supported systems to tell CoreGraphics
+        to use premulitplied interpolation.
+
+        (WebCore::shadingFunction):
+        Core function used by CGShadingRef to interpolate between color stops. Templatized to allow for optimized
+        versions for every ColorInterpolationColorSpace / AlphaPremultiplication pair. 
+
+        (WebCore::GradientRendererCG::makeShading const):
+        Builds shading strategy by converting all color stops to the interpolation color space, adding stops at
+        0 and 1 if necessary, and creating the CGFunctionRef that the shading will own. To avoid a circular 
+        reference, the GradientRendererCG itself is not what the CGFunctionRef retains, but rather a subobject
+        Data, which is a peer to the CGFunctionRef.
+
+        (WebCore::GradientRendererCG::drawLinearGradient):
+        (WebCore::GradientRendererCG::drawRadialGradient):
+        (WebCore::GradientRendererCG::drawConicGradient):
+        Draw the gradient or shading based on the strategy selected at construction.
+
</ins><span class="cx"> 2021-12-21  Tim Nguyen  <ntim@apple.com>
</span><span class="cx"> 
</span><span class="cx">         <dialog> should generate implied end tags
</span></span></pre></div>
<a id="trunkSourceWebCoreHeaderscmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Headers.cmake (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Headers.cmake       2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/Headers.cmake  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -1462,6 +1462,7 @@
</span><span class="cx">     platform/graphics/GlyphMetricsMap.h
</span><span class="cx">     platform/graphics/GlyphPage.h
</span><span class="cx">     platform/graphics/Gradient.h
</span><ins>+    platform/graphics/GradientColorStop.h
</ins><span class="cx">     platform/graphics/GraphicsContext.h
</span><span class="cx">     platform/graphics/GraphicsContextFlushIdentifier.h
</span><span class="cx">     platform/graphics/GraphicsContextGL.h
</span></span></pre></div>
<a id="trunkSourceWebCorePALChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PAL/ChangeLog (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PAL/ChangeLog       2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/PAL/ChangeLog  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2021-12-21  Sam Weinig  <weinig@apple.com>
+
+        Add support for premultiplied alpha interpolated gradients and defaulted off option to use them for CSS Gradients
+        https://bugs.webkit.org/show_bug.cgi?id=234492
+
+        Reviewed by Simon Fraser.
+
+        * pal/spi/cg/CoreGraphicsSPI.h:
+        Add forwards for creating conic shadings and enabling premultiplied alpha interpolation for gradients.
+
</ins><span class="cx"> 2021-12-20  Wenson Hsieh  <wenson_hsieh@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Add PAL soft linking headers for CoreML and NaturalLanguage frameworks
</span></span></pre></div>
<a id="trunkSourceWebCorePALpalspicgCoreGraphicsSPIh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h    2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h       2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -41,8 +41,9 @@
</span><span class="cx"> #include <CoreGraphics/CGContextDelegatePrivate.h>
</span><span class="cx"> #include <CoreGraphics/CGFontCache.h>
</span><span class="cx"> #include <CoreGraphics/CGPathPrivate.h>
</span><ins>+#include <CoreGraphics/CGShadingPrivate.h>
+#include <CoreGraphics/CGStylePrivate.h>
</ins><span class="cx"> #include <CoreGraphics/CoreGraphicsPrivate.h>
</span><del>-#include <CoreGraphics/CGStylePrivate.h>
</del><span class="cx"> 
</span><span class="cx"> #if PLATFORM(MAC)
</span><span class="cx"> #include <CoreGraphics/CGAccessibility.h>
</span><span class="lines">@@ -323,7 +324,17 @@
</span><span class="cx"> void CGContextDrawConicGradient(CGContextRef, CGGradientRef, CGPoint center, CGFloat angle);
</span><span class="cx"> void CGPathAddUnevenCornersRoundedRect(CGMutablePathRef, const CGAffineTransform *, CGRect, const CGSize corners[4]);
</span><span class="cx"> bool CGFontRenderingGetFontSmoothingDisabled(void);
</span><ins>+CGShadingRef CGShadingCreateConic(CGColorSpaceRef, CGPoint center, CGFloat angle, CGFunctionRef);
</ins><span class="cx"> 
</span><ins>+#if HAVE(CORE_GRAPHICS_GRADIENT_CREATE_WITH_OPTIONS)
+CGGradientRef CGGradientCreateWithColorComponentsAndOptions(CGColorSpaceRef, const CGFloat*, const CGFloat*, size_t, CFDictionaryRef);
+CGGradientRef CGGradientCreateWithColorsAndOptions(CGColorSpaceRef, CFArrayRef, const CGFloat*, CFDictionaryRef);
+#endif
+
+#if HAVE(CORE_GRAPHICS_PREMULTIPLIED_INTERPOLATION_GRADIENT)
+extern const CFStringRef kCGGradientInterpolatesPremultiplied;
+#endif
+
</ins><span class="cx"> #endif // PLATFORM(COCOA)
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(WIN)
</span></span></pre></div>
<a id="trunkSourceWebCorePlatformAppleWincmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PlatformAppleWin.cmake (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PlatformAppleWin.cmake      2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/PlatformAppleWin.cmake 2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -131,6 +131,7 @@
</span><span class="cx">         platform/graphics/cg/FloatRectCG.cpp
</span><span class="cx">         platform/graphics/cg/FloatSizeCG.cpp
</span><span class="cx">         platform/graphics/cg/GradientCG.cpp
</span><ins>+        platform/graphics/cg/GradientRendererCG.cpp
</ins><span class="cx">         platform/graphics/cg/GraphicsContextGLCG.cpp
</span><span class="cx">         platform/graphics/cg/GraphicsContextCG.cpp
</span><span class="cx">         platform/graphics/cg/IOSurfacePool.cpp
</span><span class="lines">@@ -182,6 +183,7 @@
</span><span class="cx">         platform/graphics/ca/win/PlatformCALayerWin.h
</span><span class="cx"> 
</span><span class="cx">         platform/graphics/cg/ColorSpaceCG.h
</span><ins>+        platform/graphics/cg/GradientRendererCG.h
</ins><span class="cx">         platform/graphics/cg/GraphicsContextCG.h
</span><span class="cx">         platform/graphics/cg/IOSurfacePool.h
</span><span class="cx">         platform/graphics/cg/ImageBufferCGBackend.h
</span></span></pre></div>
<a id="trunkSourceWebCorePlatformMaccmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/PlatformMac.cmake (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/PlatformMac.cmake   2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/PlatformMac.cmake      2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -291,6 +291,7 @@
</span><span class="cx">     platform/graphics/cg/FloatRectCG.cpp
</span><span class="cx">     platform/graphics/cg/FloatSizeCG.cpp
</span><span class="cx">     platform/graphics/cg/GradientCG.cpp
</span><ins>+    platform/graphics/cg/GradientRendererCG.cpp
</ins><span class="cx">     platform/graphics/cg/GraphicsContextGLCG.cpp
</span><span class="cx">     platform/graphics/cg/GraphicsContextCG.cpp
</span><span class="cx">     platform/graphics/cg/IOSurfacePool.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreSourcesCocoatxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/SourcesCocoa.txt (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/SourcesCocoa.txt    2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/SourcesCocoa.txt       2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -348,6 +348,7 @@
</span><span class="cx"> platform/graphics/cg/FloatRectCG.cpp
</span><span class="cx"> platform/graphics/cg/FloatSizeCG.cpp
</span><span class="cx"> platform/graphics/cg/GradientCG.cpp
</span><ins>+platform/graphics/cg/GradientRendererCG.cpp
</ins><span class="cx"> platform/graphics/cg/GraphicsContextCG.cpp
</span><span class="cx"> platform/graphics/cg/GraphicsContextGLCG.cpp
</span><span class="cx"> platform/graphics/cg/IOSurfacePool.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj   2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj      2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -4087,6 +4087,8 @@
</span><span class="cx">          BC124F000C26447A009E2349 /* JSBarProp.h in Headers */ = {isa = PBXBuildFile; fileRef = BC124EFE0C26447A009E2349 /* JSBarProp.h */; };
</span><span class="cx">          BC128A73137C867C00CAC845 /* RenderGrid.h in Headers */ = {isa = PBXBuildFile; fileRef = BC128A72137C867C00CAC845 /* RenderGrid.h */; };
</span><span class="cx">          BC14028B0E83680800319717 /* ScrollbarThemeComposite.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1402890E83680800319717 /* ScrollbarThemeComposite.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+               BC19CDF2276FFC6D0053F734 /* GradientRendererCG.h in Headers */ = {isa = PBXBuildFile; fileRef = BC19CDF0276FFB260053F734 /* GradientRendererCG.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               BC19CDF4277106390053F734 /* GradientColorStop.h in Headers */ = {isa = PBXBuildFile; fileRef = BC19CDF3277106390053F734 /* GradientColorStop.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">           BC1A7D9818FCB5B000421879 /* RenderMultiColumnSpannerPlaceholder.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1A7D9618FCB5B000421879 /* RenderMultiColumnSpannerPlaceholder.h */; };
</span><span class="cx">          BC2272870E82E70700E7F975 /* StyleReflection.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2272860E82E70700E7F975 /* StyleReflection.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          BC2272A20E82E87C00E7F975 /* CursorData.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2272A10E82E87C00E7F975 /* CursorData.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -15134,6 +15136,9 @@
</span><span class="cx">          BC128B00137C8D4600CAC845 /* RenderGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderGrid.cpp; sourceTree = "<group>"; };
</span><span class="cx">          BC1402880E83680800319717 /* ScrollbarThemeComposite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollbarThemeComposite.cpp; sourceTree = "<group>"; };
</span><span class="cx">          BC1402890E83680800319717 /* ScrollbarThemeComposite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollbarThemeComposite.h; sourceTree = "<group>"; };
</span><ins>+               BC19CDEF276FFB260053F734 /* GradientRendererCG.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GradientRendererCG.cpp; sourceTree = "<group>"; };
+               BC19CDF0276FFB260053F734 /* GradientRendererCG.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GradientRendererCG.h; sourceTree = "<group>"; };
+               BC19CDF3277106390053F734 /* GradientColorStop.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GradientColorStop.h; sourceTree = "<group>"; };
</ins><span class="cx">           BC1A7D9518FCB5B000421879 /* RenderMultiColumnSpannerPlaceholder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMultiColumnSpannerPlaceholder.cpp; sourceTree = "<group>"; };
</span><span class="cx">          BC1A7D9618FCB5B000421879 /* RenderMultiColumnSpannerPlaceholder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderMultiColumnSpannerPlaceholder.h; sourceTree = "<group>"; };
</span><span class="cx">          BC20FB7E0C0E8E6C00D1447F /* JSDeprecatedCSSOMValueCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSDeprecatedCSSOMValueCustom.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -28571,6 +28576,8 @@
</span><span class="cx">                          B275352C0B053814002CE64F /* FloatRectCG.cpp */,
</span><span class="cx">                          B275352D0B053814002CE64F /* FloatSizeCG.cpp */,
</span><span class="cx">                          BC53C60A0DA56CF10021EB5D /* GradientCG.cpp */,
</span><ins>+                               BC19CDEF276FFB260053F734 /* GradientRendererCG.cpp */,
+                               BC19CDF0276FFB260053F734 /* GradientRendererCG.h */,
</ins><span class="cx">                           B2ED97700B1F55CE00257D0F /* GraphicsContextCG.cpp */,
</span><span class="cx">                          934907E3125BBBC8007F23A0 /* GraphicsContextCG.h */,
</span><span class="cx">                          6E21C6C11126339900A7BE02 /* GraphicsContextGLCG.cpp */,
</span><span class="lines">@@ -28780,6 +28787,7 @@
</span><span class="cx">                          0873B86A136064EA00A522C2 /* GlyphPage.h */,
</span><span class="cx">                          BC53C6070DA56C570021EB5D /* Gradient.cpp */,
</span><span class="cx">                          BC53C5F40DA56B920021EB5D /* Gradient.h */,
</span><ins>+                               BC19CDF3277106390053F734 /* GradientColorStop.h */,
</ins><span class="cx">                           2D2FC0561460CD6F00263633 /* GradientImage.cpp */,
</span><span class="cx">                          2D2FC0571460CD6F00263633 /* GradientImage.h */,
</span><span class="cx">                          B2A015920AF6CD53006BCE0E /* GraphicsContext.cpp */,
</span><span class="lines">@@ -33341,6 +33349,7 @@
</span><span class="cx">                          8378878224D8A609000D4A5B /* AudioBufferSourceOptions.h in Headers */,
</span><span class="cx">                          FD31607C12B026F700C1A359 /* AudioBus.h in Headers */,
</span><span class="cx">                          FD31607E12B026F700C1A359 /* AudioChannel.h in Headers */,
</span><ins>+                               BC19CDF2276FFC6D0053F734 /* GradientRendererCG.h in Headers */,
</ins><span class="cx">                           CD3EEF3A25799F88006563BB /* AudioConfiguration.h in Headers */,
</span><span class="cx">                          FD31600512B0267600C1A359 /* AudioContext.h in Headers */,
</span><span class="cx">                          E785D96224B7F7350014DB21 /* AudioContextLatencyCategory.h in Headers */,
</span><span class="lines">@@ -34897,6 +34906,7 @@
</span><span class="cx">                          A5B81CAD1FAA44620037D1E6 /* InspectorDOMStorageAgent.h in Headers */,
</span><span class="cx">                          994C603A253A277300BDF060 /* InspectorFrontendAPIDispatcher.h in Headers */,
</span><span class="cx">                          F344C7141125B82C00F26EEE /* InspectorFrontendClient.h in Headers */,
</span><ins>+                               BC19CDF4277106390053F734 /* GradientColorStop.h in Headers */,
</ins><span class="cx">                           F344C75311294D9D00F26EEE /* InspectorFrontendClientLocal.h in Headers */,
</span><span class="cx">                          7A0E770F10C00A8800A0276E /* InspectorFrontendHost.h in Headers */,
</span><span class="cx">                          7A54858014E02D51006AE05A /* InspectorHistory.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebCorecssCSSGradientValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/CSSGradientValue.cpp (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/CSSGradientValue.cpp    2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/css/CSSGradientValue.cpp       2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -26,11 +26,10 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "CSSGradientValue.h"
</span><span class="cx"> 
</span><del>-#include "AnimationUtilities.h"
</del><span class="cx"> #include "CSSCalcValue.h"
</span><span class="cx"> #include "CSSToLengthConversionData.h"
</span><span class="cx"> #include "CSSValueKeywords.h"
</span><del>-#include "ColorBlending.h"
</del><ins>+#include "ColorInterpolation.h"
</ins><span class="cx"> #include "GradientImage.h"
</span><span class="cx"> #include "NodeRenderStyle.h"
</span><span class="cx"> #include "Pair.h"
</span><span class="lines">@@ -138,7 +137,7 @@
</span><span class="cx">     }
</span><span class="cx">     float maxExtent(float, float) const { return 1; }
</span><span class="cx"> 
</span><del>-    void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops)
</del><ins>+    void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops, ColorInterpolationMethod)
</ins><span class="cx">     {
</span><span class="cx">         float firstOffset = *stops.first().offset;
</span><span class="cx">         float lastOffset = *stops.last().offset;
</span><span class="lines">@@ -181,7 +180,7 @@
</span><span class="cx">         return 1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops)
</del><ins>+    void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops, ColorInterpolationMethod colorInterpolationMethod)
</ins><span class="cx">     {
</span><span class="cx">         auto numStops = stops.size();
</span><span class="cx"> 
</span><span class="lines">@@ -205,8 +204,7 @@
</span><span class="cx">                 float nextOffset = *stops[firstZeroOrGreaterIndex].offset;
</span><span class="cx"> 
</span><span class="cx">                 float interStopProportion = -prevOffset / (nextOffset - prevOffset);
</span><del>-                // FIXME: when we interpolate gradients using premultiplied colors, this should do premultiplication.
-                Color blendedColor = blend(stops[firstZeroOrGreaterIndex - 1].color, stops[firstZeroOrGreaterIndex].color, { interStopProportion });
</del><ins>+                auto blendedColor = interpolateColors(colorInterpolationMethod, stops[firstZeroOrGreaterIndex - 1].color, 1.0f - interStopProportion, stops[firstZeroOrGreaterIndex].color, interStopProportion);
</ins><span class="cx"> 
</span><span class="cx">                 // Clamp the positions to 0 and set the color.
</span><span class="cx">                 for (size_t i = 0; i < firstZeroOrGreaterIndex; ++i) {
</span><span class="lines">@@ -236,7 +234,7 @@
</span><span class="cx">     float gradientLength() const { return 1; }
</span><span class="cx">     float maxExtent(float, float) const { return 1; }
</span><span class="cx"> 
</span><del>-    void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops)
</del><ins>+    void normalizeStopsAndEndpointsOutsideRange(Vector<GradientStop>& stops, ColorInterpolationMethod colorInterpolationMethod)
</ins><span class="cx">     {
</span><span class="cx">         size_t numStops = stops.size();
</span><span class="cx">         size_t lastStopIndex = numStops - 1;
</span><span class="lines">@@ -256,8 +254,7 @@
</span><span class="cx">                 float nextOffset = *stops[index].offset;
</span><span class="cx"> 
</span><span class="cx">                 float interStopProportion = -previousOffset / (nextOffset - previousOffset);
</span><del>-                // FIXME: when we interpolate gradients using premultiplied colors, this should do premultiplication.
-                Color blendedColor = blend(stops[index - 1].color, stops[index].color, { interStopProportion });
</del><ins>+                auto blendedColor = interpolateColors(colorInterpolationMethod, stops[index - 1].color, 1.0f - interStopProportion, stops[index].color, interStopProportion);
</ins><span class="cx"> 
</span><span class="cx">                 // Clamp the positions to 0 and set the color.
</span><span class="cx">                 for (size_t i = 0; i < index; ++i) {
</span><span class="lines">@@ -286,8 +283,7 @@
</span><span class="cx">                 float nextOffset = *stops[index + 1].offset;
</span><span class="cx"> 
</span><span class="cx">                 float interStopProportion = (1 - previousOffset) / (nextOffset - previousOffset);
</span><del>-                // FIXME: when we interpolate gradients using premultiplied colors, this should do premultiplication.
-                Color blendedColor = blend(stops[index].color, stops[index + 1].color, { interStopProportion });
</del><ins>+                auto blendedColor = interpolateColors(colorInterpolationMethod, stops[index].color, 1.0f - interStopProportion, stops[index + 1].color, interStopProportion);
</ins><span class="cx"> 
</span><span class="cx">                 // Clamp the positions to 1 and set the color.
</span><span class="cx">                 for (size_t i = index + 1; i < numStops; ++i) {
</span><span class="lines">@@ -485,8 +481,7 @@
</span><span class="cx">         for (size_t y = 0; y < 9; ++y) {
</span><span class="cx">             float relativeOffset = (*newStops[y].offset - offset1) / (offset2 - offset1);
</span><span class="cx">             float multiplier = std::pow(relativeOffset, std::log(.5f) / std::log(midpoint));
</span><del>-            // FIXME: Why not premultiply here?
-            newStops[y].color = blendWithoutPremultiply(color1, color2, { multiplier });
</del><ins>+            newStops[y].color = interpolateColors(m_colorInterpolationMethod, color1, 1.0f - multiplier, color2, multiplier);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         stops.remove(x);
</span><span class="lines">@@ -557,7 +552,7 @@
</span><span class="cx"> 
</span><span class="cx">     // If the gradient goes outside the 0-1 range, normalize it by moving the endpoints, and adjusting the stops.
</span><span class="cx">     if (stops.size() > 1 && (*stops.first().offset < 0 || *stops.last().offset > 1))
</span><del>-        gradientAdapter.normalizeStopsAndEndpointsOutsideRange(stops);
</del><ins>+        gradientAdapter.normalizeStopsAndEndpointsOutsideRange(stops, m_colorInterpolationMethod);
</ins><span class="cx">     
</span><span class="cx">     Gradient::ColorStopVector result;
</span><span class="cx">     result.reserveInitialCapacity(stops.size());
</span></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserContextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/parser/CSSParserContext.cpp (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserContext.cpp     2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/css/parser/CSSParserContext.cpp        2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -106,10 +106,11 @@
</span><span class="cx">     , hasPseudoClassEnabled { document.settings().hasPseudoClassEnabled() }
</span><span class="cx">     , cascadeLayersEnabled { document.settings().cssCascadeLayersEnabled() }
</span><span class="cx">     , containerQueriesEnabled { document.settings().cssContainerQueriesEnabled() }
</span><ins>+    , overflowClipEnabled { document.settings().overflowClipEnabled() }
+    , gradientPremultipliedAlphaInterpolationEnabled { document.settings().cssGradientPremultipliedAlphaInterpolationEnabled() }
</ins><span class="cx"> #if ENABLE(ATTACHMENT_ELEMENT)
</span><span class="cx">     , attachmentEnabled { RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled() }
</span><span class="cx"> #endif
</span><del>-    , overflowClipEnabled { document.settings().overflowClipEnabled() }
</del><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -153,10 +154,11 @@
</span><span class="cx">         && a.hasPseudoClassEnabled == b.hasPseudoClassEnabled
</span><span class="cx">         && a.cascadeLayersEnabled == b.cascadeLayersEnabled
</span><span class="cx">         && a.containerQueriesEnabled == b.containerQueriesEnabled
</span><ins>+        && a.overflowClipEnabled == b.overflowClipEnabled
+        && a.gradientPremultipliedAlphaInterpolationEnabled == b.gradientPremultipliedAlphaInterpolationEnabled
</ins><span class="cx"> #if ENABLE(ATTACHMENT_ELEMENT)
</span><span class="cx">         && a.attachmentEnabled == b.attachmentEnabled
</span><span class="cx"> #endif
</span><del>-        && a.overflowClipEnabled == b.overflowClipEnabled
</del><span class="cx">     ;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -193,12 +195,13 @@
</span><span class="cx">         | context.hasPseudoClassEnabled                     << 22
</span><span class="cx">         | context.cascadeLayersEnabled                      << 23
</span><span class="cx">         | context.containerQueriesEnabled                   << 24
</span><ins>+        | context.overflowClipEnabled                       << 25
+        | context.gradientPremultipliedAlphaInterpolationEnabled << 26
</ins><span class="cx"> #if ENABLE(ATTACHMENT_ELEMENT)
</span><del>-        | context.attachmentEnabled                         << 25
</del><ins>+        | context.attachmentEnabled                         << 27
</ins><span class="cx"> #endif
</span><del>-        | context.overflowClipEnabled                       << 26
-        | context.accentColorEnabled                        << 27
-        | context.mode                                      << 28; // This is multiple bits, so keep it last.
</del><ins>+        | context.accentColorEnabled                        << 28
+        | context.mode                                      << 29; // This is multiple bits, so keep it last.
</ins><span class="cx">     add(hasher, context.baseURL, context.charset, bits);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSParserContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/parser/CSSParserContext.h (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSParserContext.h       2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/css/parser/CSSParserContext.h  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -85,6 +85,8 @@
</span><span class="cx">     bool hasPseudoClassEnabled { false };
</span><span class="cx">     bool cascadeLayersEnabled { false };
</span><span class="cx">     bool containerQueriesEnabled { false };
</span><ins>+    bool overflowClipEnabled { false };
+    bool gradientPremultipliedAlphaInterpolationEnabled { false };
</ins><span class="cx"> 
</span><span class="cx">     // RuntimeEnabledFeatures.
</span><span class="cx"> #if ENABLE(ATTACHMENT_ELEMENT)
</span><span class="lines">@@ -91,8 +93,6 @@
</span><span class="cx">     bool attachmentEnabled { false };
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    bool overflowClipEnabled { false };
-
</del><span class="cx">     CSSParserContext(CSSParserMode, const URL& baseURL = URL());
</span><span class="cx">     WEBCORE_EXPORT CSSParserContext(const Document&, const URL& baseURL = URL(), const String& charset = emptyString());
</span><span class="cx">     bool isPropertyRuntimeDisabled(CSSPropertyID) const;
</span></span></pre></div>
<a id="trunkSourceWebCorecssparserCSSPropertyParserHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp     2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp        2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -2439,24 +2439,6 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// After interpolation, if the color is in the HWB or HSL color space, it needs to be canonicalized back to sRGB as
-// is done at parse time.
-
-template<typename ColorType> Color makeCanonicalColor(ColorType color)
-{
-    return color;
-}
-
-template<> Color makeCanonicalColor<HWBA<float>>(HWBA<float> color)
-{
-    return convertColor<SRGBA<uint8_t>>(color);
-}
-
-template<> Color makeCanonicalColor<HSLA<float>>(HSLA<float> color)
-{
-    return convertColor<SRGBA<uint8_t>>(color);
-}
-
</del><span class="cx"> template<typename InterpolationMethod> static Color mixColorComponentsUsingColorInterpolationMethod(InterpolationMethod interpolationMethod, ColorMixPercentages mixPercentages, const Color& color1, const Color& color2)
</span><span class="cx"> {
</span><span class="cx">     using ColorType = typename InterpolationMethod::ColorType;
</span><span class="lines">@@ -2946,6 +2928,11 @@
</span><span class="cx">     return stop.color && args.atEnd();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static AlphaPremultiplication gradientAlphaPremultiplication(const CSSParserContext& context)
+{
+    return context.gradientPremultipliedAlphaInterpolationEnabled ? AlphaPremultiplication::Premultiplied : AlphaPremultiplication::Unpremultiplied;
+}
+
</ins><span class="cx"> static RefPtr<CSSValue> consumeDeprecatedGradient(CSSParserTokenRange& args, const CSSParserContext& context)
</span><span class="cx"> {
</span><span class="cx">     RefPtr<CSSGradientValue> result;
</span><span class="lines">@@ -2952,9 +2939,9 @@
</span><span class="cx">     CSSValueID id = args.consumeIncludingWhitespace().id();
</span><span class="cx">     bool isDeprecatedRadialGradient = (id == CSSValueRadial);
</span><span class="cx">     if (isDeprecatedRadialGradient)
</span><del>-        result = CSSRadialGradientValue::create(NonRepeating, CSSDeprecatedRadialGradient, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
</del><ins>+        result = CSSRadialGradientValue::create(NonRepeating, CSSDeprecatedRadialGradient, { ColorInterpolationMethod::SRGB { }, gradientAlphaPremultiplication(context) });
</ins><span class="cx">     else if (id == CSSValueLinear)
</span><del>-        result = CSSLinearGradientValue::create(NonRepeating, CSSDeprecatedLinearGradient, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
</del><ins>+        result = CSSLinearGradientValue::create(NonRepeating, CSSDeprecatedLinearGradient, { ColorInterpolationMethod::SRGB { }, gradientAlphaPremultiplication(context) });
</ins><span class="cx">     if (!result || !consumeCommaIncludingWhitespace(args))
</span><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="lines">@@ -3054,7 +3041,7 @@
</span><span class="cx"> 
</span><span class="cx"> static RefPtr<CSSValue> consumeDeprecatedRadialGradient(CSSParserTokenRange& args, const CSSParserContext& context, CSSGradientRepeat repeating)
</span><span class="cx"> {
</span><del>-    auto result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
</del><ins>+    auto result = CSSRadialGradientValue::create(repeating, CSSPrefixedRadialGradient, { ColorInterpolationMethod::SRGB { }, gradientAlphaPremultiplication(context) });
</ins><span class="cx"> 
</span><span class="cx">     auto centerCoordinate = consumeOneOrTwoValuedPositionCoordinates(args, context.mode, UnitlessQuirk::Forbid);
</span><span class="cx">     if (centerCoordinate && !consumeCommaIncludingWhitespace(args))
</span><span class="lines">@@ -3098,7 +3085,7 @@
</span><span class="cx"> 
</span><span class="cx"> static RefPtr<CSSValue> consumeRadialGradient(CSSParserTokenRange& args, const CSSParserContext& context, CSSGradientRepeat repeating)
</span><span class="cx"> {
</span><del>-    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
</del><ins>+    RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create(repeating, CSSRadialGradient, { ColorInterpolationMethod::SRGB { }, gradientAlphaPremultiplication(context) });
</ins><span class="cx"> 
</span><span class="cx">     RefPtr<CSSPrimitiveValue> shape;
</span><span class="cx">     RefPtr<CSSPrimitiveValue> sizeKeyword;
</span><span class="lines">@@ -3186,7 +3173,7 @@
</span><span class="cx"> 
</span><span class="cx"> static RefPtr<CSSValue> consumeLinearGradient(CSSParserTokenRange& args, const CSSParserContext& context, CSSGradientRepeat repeating, CSSGradientType gradientType)
</span><span class="cx"> {
</span><del>-    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, gradientType, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
</del><ins>+    RefPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, gradientType, { ColorInterpolationMethod::SRGB { }, gradientAlphaPremultiplication(context) });
</ins><span class="cx"> 
</span><span class="cx">     bool expectComma = true;
</span><span class="cx">     RefPtr<CSSPrimitiveValue> angle = consumeAngle(args, context.mode, UnitlessQuirk::Forbid, UnitlessZeroQuirk::Allow);
</span><span class="lines">@@ -3220,7 +3207,7 @@
</span><span class="cx"> static RefPtr<CSSValue> consumeConicGradient(CSSParserTokenRange& args, const CSSParserContext& context, CSSGradientRepeat repeating)
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(CSS_CONIC_GRADIENTS)
</span><del>-    RefPtr<CSSConicGradientValue> result = CSSConicGradientValue::create(repeating, { ColorInterpolationMethod::SRGB { }, AlphaPremultiplication::Unpremultiplied });
</del><ins>+    RefPtr<CSSConicGradientValue> result = CSSConicGradientValue::create(repeating, { ColorInterpolationMethod::SRGB { }, gradientAlphaPremultiplication(context) });
</ins><span class="cx"> 
</span><span class="cx">     bool expectComma = false;
</span><span class="cx">     if (args.peek().type() == IdentToken) {
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsColorComponentsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ColorComponents.h (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ColorComponents.h 2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/platform/graphics/ColorComponents.h    2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -68,6 +68,8 @@
</span><span class="cx">     template<size_t Start, size_t End>
</span><span class="cx">     constexpr ColorComponents<T, End - Start> subset() const;
</span><span class="cx"> 
</span><ins>+    constexpr size_t size() const { return Size; }
+
</ins><span class="cx">     std::array<T, N> components;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsColorInterpolationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ColorInterpolation.h (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ColorInterpolation.h      2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/platform/graphics/ColorInterpolation.h 2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><span class="cx"> #include "AlphaPremultiplication.h"
</span><ins>+#include "Color.h"
</ins><span class="cx"> #include "ColorInterpolationMethod.h"
</span><span class="cx"> #include "ColorNormalization.h"
</span><span class="cx"> #include "ColorTypes.h"
</span><span class="lines">@@ -36,14 +37,14 @@
</span><span class="cx"> 
</span><span class="cx"> std::pair<float, float> fixupHueComponentsPriorToInterpolation(HueInterpolationMethod, float, float);
</span><span class="cx"> 
</span><del>-template<size_t I, AlphaPremultiplication alphaPremultiplication, typename InterpolationMethod>
-std::pair<float, float> preInterpolationNormalizationForComponent(InterpolationMethod interpolationMethod, ColorComponents<float, 4> colorComponents1, ColorComponents<float, 4> colorComponents2)
</del><ins>+template<size_t I, AlphaPremultiplication alphaPremultiplication, typename InterpolationMethodColorSpace>
+std::pair<float, float> preInterpolationNormalizationForComponent(InterpolationMethodColorSpace interpolationMethodColorSpace, ColorComponents<float, 4> colorComponents1, ColorComponents<float, 4> colorComponents2)
</ins><span class="cx"> {
</span><del>-    using ColorType = typename InterpolationMethod::ColorType;
</del><ins>+    using ColorType = typename InterpolationMethodColorSpace::ColorType;
</ins><span class="cx">     constexpr auto componentInfo = ColorType::Model::componentInfo;
</span><span class="cx"> 
</span><span class="cx">     if constexpr (componentInfo[I].type == ColorComponentType::Angle)
</span><del>-        return fixupHueComponentsPriorToInterpolation(interpolationMethod.hueInterpolationMethod, colorComponents1[I], colorComponents2[I]);
</del><ins>+        return fixupHueComponentsPriorToInterpolation(interpolationMethodColorSpace.hueInterpolationMethod, colorComponents1[I], colorComponents2[I]);
</ins><span class="cx">     else {
</span><span class="cx">         if constexpr (alphaPremultiplication == AlphaPremultiplication::Premultiplied)
</span><span class="cx">             return { colorComponents1[I] * colorComponents1[3], colorComponents2[I] * colorComponents2[3] };
</span><span class="lines">@@ -52,12 +53,12 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template<AlphaPremultiplication alphaPremultiplication, typename InterpolationMethod>
-std::pair<ColorComponents<float, 4>, ColorComponents<float, 4>> preInterpolationNormalization(InterpolationMethod interpolationMethod, ColorComponents<float, 4> colorComponents1, ColorComponents<float, 4> colorComponents2)
</del><ins>+template<AlphaPremultiplication alphaPremultiplication, typename InterpolationMethodColorSpace>
+std::pair<ColorComponents<float, 4>, ColorComponents<float, 4>> preInterpolationNormalization(InterpolationMethodColorSpace interpolationMethodColorSpace, ColorComponents<float, 4> colorComponents1, ColorComponents<float, 4> colorComponents2)
</ins><span class="cx"> {
</span><del>-    auto [colorA0, colorB0] = preInterpolationNormalizationForComponent<0, alphaPremultiplication>(interpolationMethod, colorComponents1, colorComponents2);
-    auto [colorA1, colorB1] = preInterpolationNormalizationForComponent<1, alphaPremultiplication>(interpolationMethod, colorComponents1, colorComponents2);
-    auto [colorA2, colorB2] = preInterpolationNormalizationForComponent<2, alphaPremultiplication>(interpolationMethod, colorComponents1, colorComponents2);
</del><ins>+    auto [colorA0, colorB0] = preInterpolationNormalizationForComponent<0, alphaPremultiplication>(interpolationMethodColorSpace, colorComponents1, colorComponents2);
+    auto [colorA1, colorB1] = preInterpolationNormalizationForComponent<1, alphaPremultiplication>(interpolationMethodColorSpace, colorComponents1, colorComponents2);
+    auto [colorA2, colorB2] = preInterpolationNormalizationForComponent<2, alphaPremultiplication>(interpolationMethodColorSpace, colorComponents1, colorComponents2);
</ins><span class="cx"> 
</span><span class="cx">     return {
</span><span class="cx">         { colorA0, colorA1, colorA2, colorComponents1[3] },
</span><span class="lines">@@ -68,10 +69,10 @@
</span><span class="cx"> 
</span><span class="cx"> // MARK: - Post-interpolation normalization/fixup
</span><span class="cx"> 
</span><del>-template<size_t I, AlphaPremultiplication alphaPremultiplication, typename InterpolationMethod>
-float postInterpolationNormalizationForComponent(InterpolationMethod, ColorComponents<float, 4> colorComponents)
</del><ins>+template<size_t I, AlphaPremultiplication alphaPremultiplication, typename InterpolationMethodColorSpace>
+float postInterpolationNormalizationForComponent(InterpolationMethodColorSpace, ColorComponents<float, 4> colorComponents)
</ins><span class="cx"> {
</span><del>-    using ColorType = typename InterpolationMethod::ColorType;
</del><ins>+    using ColorType = typename InterpolationMethodColorSpace::ColorType;
</ins><span class="cx">     constexpr auto componentInfo = ColorType::Model::componentInfo;
</span><span class="cx"> 
</span><span class="cx">     if constexpr (componentInfo[I].type != ColorComponentType::Angle && alphaPremultiplication == AlphaPremultiplication::Premultiplied) {
</span><span class="lines">@@ -82,13 +83,13 @@
</span><span class="cx">         return colorComponents[I];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template<AlphaPremultiplication alphaPremultiplication, typename InterpolationMethod>
-ColorComponents<float, 4> postInterpolationNormalization(InterpolationMethod interpolationMethod, ColorComponents<float, 4> colorComponents)
</del><ins>+template<AlphaPremultiplication alphaPremultiplication, typename InterpolationMethodColorSpace>
+ColorComponents<float, 4> postInterpolationNormalization(InterpolationMethodColorSpace interpolationMethodColorSpace, ColorComponents<float, 4> colorComponents)
</ins><span class="cx"> {
</span><span class="cx">     return {
</span><del>-        postInterpolationNormalizationForComponent<0, alphaPremultiplication>(interpolationMethod, colorComponents),
-        postInterpolationNormalizationForComponent<1, alphaPremultiplication>(interpolationMethod, colorComponents),
-        postInterpolationNormalizationForComponent<2, alphaPremultiplication>(interpolationMethod, colorComponents),
</del><ins>+        postInterpolationNormalizationForComponent<0, alphaPremultiplication>(interpolationMethodColorSpace, colorComponents),
+        postInterpolationNormalizationForComponent<1, alphaPremultiplication>(interpolationMethodColorSpace, colorComponents),
+        postInterpolationNormalizationForComponent<2, alphaPremultiplication>(interpolationMethodColorSpace, colorComponents),
</ins><span class="cx">         colorComponents[3]
</span><span class="cx">     };
</span><span class="cx">  }
</span><span class="lines">@@ -96,11 +97,11 @@
</span><span class="cx"> 
</span><span class="cx"> // MARK: - Interpolation
</span><span class="cx"> 
</span><del>-template<AlphaPremultiplication alphaPremultiplication, typename InterpolationMethod>
-typename InterpolationMethod::ColorType interpolateColorComponents(InterpolationMethod interpolationMethod, typename InterpolationMethod::ColorType color1, double color1Multiplier, typename InterpolationMethod::ColorType color2, double color2Multiplier)
</del><ins>+template<AlphaPremultiplication alphaPremultiplication, typename InterpolationMethodColorSpace>
+typename InterpolationMethodColorSpace::ColorType interpolateColorComponents(InterpolationMethodColorSpace interpolationMethodColorSpace, typename InterpolationMethodColorSpace::ColorType color1, double color1Multiplier, typename InterpolationMethodColorSpace::ColorType color2, double color2Multiplier)
</ins><span class="cx"> {
</span><span class="cx">     // 1. Apply pre-interpolation transforms (hue fixup for polar color spaces, alpha premultiplication if required).
</span><del>-    auto [normalizedColorComponents1, normalizedColorComponents2] = preInterpolationNormalization<alphaPremultiplication>(interpolationMethod, asColorComponents(color1), asColorComponents(color2));
</del><ins>+    auto [normalizedColorComponents1, normalizedColorComponents2] = preInterpolationNormalization<alphaPremultiplication>(interpolationMethodColorSpace, asColorComponents(color1), asColorComponents(color2));
</ins><span class="cx"> 
</span><span class="cx">     // 2. Interpolate using the normalized components.
</span><span class="cx">     auto interpolatedColorComponents = mapColorComponents([&] (auto componentFromColor1, auto componentFromColor2) -> float {
</span><span class="lines">@@ -108,10 +109,25 @@
</span><span class="cx">     }, normalizedColorComponents1, normalizedColorComponents2);
</span><span class="cx"> 
</span><span class="cx">     // 3. Apply post-interpolation trasforms (alpha un-premultiplication if required).
</span><del>-    auto normalizedInterpolatedColorComponents = postInterpolationNormalization<alphaPremultiplication>(interpolationMethod, interpolatedColorComponents);
</del><ins>+    auto normalizedInterpolatedColorComponents = postInterpolationNormalization<alphaPremultiplication>(interpolationMethodColorSpace, interpolatedColorComponents);
</ins><span class="cx"> 
</span><span class="cx">     // 4. Create color type from components, normalizing any components that may be out of range.
</span><del>-    return makeColorTypeByNormalizingComponents<typename InterpolationMethod::ColorType>(normalizedInterpolatedColorComponents);
</del><ins>+    return makeColorTypeByNormalizingComponents<typename InterpolationMethodColorSpace::ColorType>(normalizedInterpolatedColorComponents);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline Color interpolateColors(ColorInterpolationMethod colorInterpolationMethod, Color color1, double color1Multiplier, Color color2, double color2Multiplier)
+{
+    return WTF::switchOn(colorInterpolationMethod.colorSpace,
+        [&] (auto& colorSpace) {
+            using ColorType = typename std::remove_reference_t<decltype(colorSpace)>::ColorType;
+            switch (colorInterpolationMethod.alphaPremultiplication) {
+            case AlphaPremultiplication::Premultiplied:
+                return makeCanonicalColor(interpolateColorComponents<AlphaPremultiplication::Premultiplied>(colorSpace, color1.toColorTypeLossy<ColorType>(), color1Multiplier, color2.toColorTypeLossy<ColorType>(), color2Multiplier));
+            case AlphaPremultiplication::Unpremultiplied:
+                return makeCanonicalColor(interpolateColorComponents<AlphaPremultiplication::Unpremultiplied>(colorSpace, color1.toColorTypeLossy<ColorType>(), color1Multiplier, color2.toColorTypeLossy<ColorType>(), color2Multiplier));
+            }
+        }
+    );
</ins><span class="cx"> }
</span><ins>+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsColorNormalizationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/ColorNormalization.h (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/ColorNormalization.h      2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/platform/graphics/ColorNormalization.h 2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -25,6 +25,8 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><ins>+#include "Color.h"
+#include "ColorConversion.h"
</ins><span class="cx"> #include "ColorTypes.h"
</span><span class="cx"> #include <wtf/MathExtras.h>
</span><span class="cx"> 
</span><span class="lines">@@ -31,8 +33,11 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> template<typename ColorType> ColorType makeColorTypeByNormalizingComponents(const ColorComponents<float, 4>&);
</span><ins>+template<typename ColorType> Color makeCanonicalColor(ColorType);
</ins><span class="cx"> 
</span><span class="cx"> 
</span><ins>+// MARK: - Normalization
+
</ins><span class="cx"> template<typename ComponentType> struct WhitenessBlackness {
</span><span class="cx">     ComponentType whiteness;
</span><span class="cx">     ComponentType blackness;
</span><span class="lines">@@ -101,4 +106,21 @@
</span><span class="cx">     return { lightness, chroma, normalizedHue, alpha };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// MARK: - Canonicalization
+
+template<typename ColorType> inline Color makeCanonicalColor(ColorType color)
+{
+    return color;
</ins><span class="cx"> }
</span><ins>+
+template<> inline Color makeCanonicalColor<HWBA<float>>(HWBA<float> color)
+{
+    return convertColor<SRGBA<uint8_t>>(color);
+}
+
+template<> inline Color makeCanonicalColor<HSLA<float>>(HSLA<float> color)
+{
+    return convertColor<SRGBA<uint8_t>>(color);
+}
+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsGradienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/Gradient.h (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/Gradient.h        2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/platform/graphics/Gradient.h   2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -27,16 +27,16 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><del>-#include "AffineTransform.h"
</del><span class="cx"> #include "Color.h"
</span><span class="cx"> #include "ColorInterpolationMethod.h"
</span><span class="cx"> #include "FloatPoint.h"
</span><ins>+#include "GradientColorStop.h"
</ins><span class="cx"> #include "GraphicsTypes.h"
</span><span class="cx"> #include <variant>
</span><span class="cx"> #include <wtf/Vector.h>
</span><span class="cx"> 
</span><span class="cx"> #if USE(CG)
</span><del>-#include <wtf/RetainPtr.h>
</del><ins>+#include "GradientRendererCG.h"
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if USE(DIRECT2D)
</span><span class="lines">@@ -45,7 +45,6 @@
</span><span class="cx"> 
</span><span class="cx"> #if USE(CG)
</span><span class="cx"> typedef struct CGContext* CGContextRef;
</span><del>-typedef struct CGGradient* CGGradientRef;
</del><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if USE(DIRECT2D)
</span><span class="lines">@@ -59,21 +58,15 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+class AffineTransform;
</ins><span class="cx"> class FloatRect;
</span><span class="cx"> class GraphicsContext;
</span><span class="cx"> 
</span><span class="cx"> class Gradient : public RefCounted<Gradient> {
</span><span class="cx"> public:
</span><del>-    struct ColorStop {
-        float offset { 0 };
-        Color color;
</del><ins>+    using ColorStop = GradientColorStop;
+    using ColorStopVector = GradientColorStopVector;
</ins><span class="cx"> 
</span><del>-        template<typename Encoder> void encode(Encoder&) const;
-        template<typename Decoder> static std::optional<ColorStop> decode(Decoder&);
-    };
-
-    using ColorStopVector = Vector<ColorStop, 2>;
-
</del><span class="cx">     struct LinearData {
</span><span class="cx">         FloatPoint point0;
</span><span class="cx">         FloatPoint point1;
</span><span class="lines">@@ -144,11 +137,6 @@
</span><span class="cx">     void sortStops() const;
</span><span class="cx">     void stopsChanged();
</span><span class="cx"> 
</span><del>-#if USE(CG)
-    void createCGGradient();
-    bool hasOnlyBoundedSRGBColorStops() const;
-#endif
-
</del><span class="cx">     Data m_data;
</span><span class="cx">     ColorInterpolationMethod m_colorInterpolationMethod;
</span><span class="cx">     mutable ColorStopVector m_stops;
</span><span class="lines">@@ -157,7 +145,7 @@
</span><span class="cx">     mutable unsigned m_cachedHash { 0 };
</span><span class="cx"> 
</span><span class="cx"> #if USE(CG)
</span><del>-    RetainPtr<CGGradientRef> m_gradient;
</del><ins>+    std::optional<GradientRendererCG> m_platformRenderer;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if USE(DIRECT2D)
</span><span class="lines">@@ -165,27 +153,6 @@
</span><span class="cx"> #endif
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-template<typename Encoder> void Gradient::ColorStop::encode(Encoder& encoder) const
-{
-    encoder << offset;
-    encoder << color;
-}
-
-template<typename Decoder> std::optional<Gradient::ColorStop> Gradient::ColorStop::decode(Decoder& decoder)
-{
-    std::optional<float> offset;
-    decoder >> offset;
-    if (!offset)
-        return std::nullopt;
-
-    std::optional<Color> color;
-    decoder >> color;
-    if (!color)
-        return std::nullopt;
-
-    return {{ *offset, *color }};
-}
-
</del><span class="cx"> template<typename Encoder> void Gradient::LinearData::encode(Encoder& encoder) const
</span><span class="cx"> {
</span><span class="cx">     encoder << point0;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsGradientColorStoph"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/platform/graphics/GradientColorStop.h (0 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/GradientColorStop.h                               (rev 0)
+++ trunk/Source/WebCore/platform/graphics/GradientColorStop.h  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -0,0 +1,65 @@
</span><ins>+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Color.h"
+#include <optional>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+struct GradientColorStop {
+    float offset { 0 };
+    Color color;
+
+    template<typename Encoder> void encode(Encoder&) const;
+    template<typename Decoder> static std::optional<GradientColorStop> decode(Decoder&);
+};
+
+using GradientColorStopVector = Vector<GradientColorStop, 2>;
+
+template<typename Encoder> void GradientColorStop::encode(Encoder& encoder) const
+{
+    encoder << offset;
+    encoder << color;
+}
+
+template<typename Decoder> std::optional<GradientColorStop> GradientColorStop::decode(Decoder& decoder)
+{
+    std::optional<float> offset;
+    decoder >> offset;
+    if (!offset)
+        return std::nullopt;
+
+    std::optional<Color> color;
+    decoder >> color;
+    if (!color)
+        return std::nullopt;
+
+    return {{ *offset, *color }};
+}
+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgGradientCGcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/cg/GradientCG.cpp (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/GradientCG.cpp 2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebCore/platform/graphics/cg/GradientCG.cpp    2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -29,72 +29,17 @@
</span><span class="cx"> 
</span><span class="cx"> #if USE(CG)
</span><span class="cx"> 
</span><ins>+#include "GradientRendererCG.h"
</ins><span class="cx"> #include "GraphicsContextCG.h"
</span><span class="cx"> #include <pal/spi/cg/CoreGraphicsSPI.h>
</span><del>-#include <wtf/RetainPtr.h>
</del><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> void Gradient::stopsChanged()
</span><span class="cx"> {
</span><del>-    m_gradient = nullptr;
</del><ins>+    m_platformRenderer = { };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool Gradient::hasOnlyBoundedSRGBColorStops() const
-{
-    for (const auto& stop : m_stops) {
-        if (stop.color.colorSpace() != ColorSpace::SRGB)
-            return false;
-    }
-    return true;
-}
-
-void Gradient::createCGGradient()
-{
-    sortStops();
-
-    unsigned numStops = m_stops.size();
-
-    const int reservedStops = 3;
-    Vector<CGFloat, reservedStops> locations;
-    locations.reserveInitialCapacity(numStops);
-
-    // If all the stops are bounded sRGB (as represented by the color having the color space
-    // ColorSpace::SRGB), it is faster to create a gradient using components than CGColors.
-    if (hasOnlyBoundedSRGBColorStops()) {
-        Vector<CGFloat, 4 * reservedStops> colorComponents;
-        colorComponents.reserveInitialCapacity(numStops * 4);
-
-        for (const auto& stop : m_stops) {
-            auto [colorSpace, components] = stop.color.colorSpaceAndComponents();
-            auto [r, g, b, a] = components;
-            colorComponents.uncheckedAppend(r);
-            colorComponents.uncheckedAppend(g);
-            colorComponents.uncheckedAppend(b);
-            colorComponents.uncheckedAppend(a);
-
-            locations.uncheckedAppend(stop.offset);
-        }
-
-        m_gradient = adoptCF(CGGradientCreateWithColorComponents(sRGBColorSpaceRef(), colorComponents.data(), locations.data(), numStops));
-        return;
-    }
-
-    auto colorsArray = adoptCF(CFArrayCreateMutable(0, m_stops.size(), &kCFTypeArrayCallBacks));
-    for (const auto& stop : m_stops) {
-        CFArrayAppendValue(colorsArray.get(), cachedCGColor(stop.color).get());
-        locations.uncheckedAppend(stop.offset);
-    }
-
-#if HAVE(CORE_GRAPHICS_EXTENDED_SRGB_COLOR_SPACE)
-    auto extendedColorsGradientColorSpace = extendedSRGBColorSpaceRef();
-#else
-    auto extendedColorsGradientColorSpace = sRGBColorSpaceRef();
-#endif
-
-    m_gradient = adoptCF(CGGradientCreateWithColors(extendedColorsGradientColorSpace, colorsArray.get(), locations.data()));
-}
-
</del><span class="cx"> void Gradient::fill(GraphicsContext& context, const FloatRect& rect)
</span><span class="cx"> {
</span><span class="cx">     context.clip(rect);
</span><span class="lines">@@ -108,11 +53,11 @@
</span><span class="cx"> 
</span><span class="cx"> void Gradient::paint(CGContextRef platformContext)
</span><span class="cx"> {
</span><del>-    CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
</del><ins>+    if (!m_platformRenderer) {
+        sortStops();
+        m_platformRenderer = GradientRendererCG { m_colorInterpolationMethod, m_stops };
+    }
</ins><span class="cx"> 
</span><del>-    if (!m_gradient)
-        createCGGradient();
-
</del><span class="cx">     WTF::switchOn(m_data,
</span><span class="cx">         [&] (const LinearData& data) {
</span><span class="cx">             switch (m_spreadMethod) {
</span><span class="lines">@@ -119,7 +64,7 @@
</span><span class="cx">             case GradientSpreadMethod::Repeat:
</span><span class="cx">             case GradientSpreadMethod::Reflect: {
</span><span class="cx">                 CGContextStateSaver saveState(platformContext);
</span><del>-                extendOptions = 0;
</del><ins>+                CGGradientDrawingOptions extendOptions = 0;
</ins><span class="cx"> 
</span><span class="cx">                 FloatPoint gradientVectorNorm(data.point1 - data.point0);
</span><span class="cx">                 gradientVectorNorm.normalize();
</span><span class="lines">@@ -143,7 +88,7 @@
</span><span class="cx">                     CGPoint left = CGPointMake(flip ? end : start, 0);
</span><span class="cx">                     CGPoint right = CGPointMake(flip ? start : end, 0);
</span><span class="cx"> 
</span><del>-                    CGContextDrawLinearGradient(platformContext, m_gradient.get(), left, right, extendOptions);
</del><ins>+                    m_platformRenderer->drawLinearGradient(platformContext, left, right, extendOptions);
</ins><span class="cx">                 };
</span><span class="cx"> 
</span><span class="cx">                 auto isLeftOf = [](CGFloat start, CGFloat end, CGRect boundingBox) -> bool {
</span><span class="lines">@@ -189,12 +134,14 @@
</span><span class="cx">                     drawLinearGradient(end - dx, end, flip);
</span><span class="cx">                     flip = !flip && m_spreadMethod == GradientSpreadMethod::Reflect;
</span><span class="cx">                 }
</span><del>-
</del><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            case GradientSpreadMethod::Pad:
-                CGContextDrawLinearGradient(platformContext, m_gradient.get(), data.point0, data.point1, extendOptions);
</del><ins>+            case GradientSpreadMethod::Pad: {
+                CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
+                m_platformRenderer->drawLinearGradient(platformContext, data.point0, data.point1, extendOptions);
+                break;
</ins><span class="cx">             }
</span><ins>+            }
</ins><span class="cx">         },
</span><span class="cx">         [&] (const RadialData& data) {
</span><span class="cx">             bool needScaling = data.aspectRatio != 1;
</span><span class="lines">@@ -208,7 +155,8 @@
</span><span class="cx">                 CGContextTranslateCTM(platformContext, -data.point0.x(), -data.point0.y());
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            CGContextDrawRadialGradient(platformContext, m_gradient.get(), data.point0, data.startRadius, data.point1, data.endRadius, extendOptions);
</del><ins>+            CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
+            m_platformRenderer->drawRadialGradient(platformContext, data.point0, data.startRadius, data.point1, data.endRadius, extendOptions);
</ins><span class="cx"> 
</span><span class="cx">             if (needScaling)
</span><span class="cx">                 CGContextRestoreGState(platformContext);
</span><span class="lines">@@ -221,7 +169,7 @@
</span><span class="cx">             CGContextTranslateCTM(platformContext, data.point0.x(), data.point0.y());
</span><span class="cx">             CGContextRotateCTM(platformContext, (CGFloat)-M_PI_2);
</span><span class="cx">             CGContextTranslateCTM(platformContext, -data.point0.x(), -data.point0.y());
</span><del>-            CGContextDrawConicGradient(platformContext, m_gradient.get(), data.point0, data.angleRadians);
</del><ins>+            m_platformRenderer->drawConicGradient(platformContext, data.point0, data.angleRadians);
</ins><span class="cx">             CGContextRestoreGState(platformContext);
</span><span class="cx"> #else
</span><span class="cx">             UNUSED_PARAM(data);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgGradientRendererCGcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp (0 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp                         (rev 0)
+++ trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp    2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -0,0 +1,354 @@
</span><ins>+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GradientRendererCG.h"
+
+#include "ColorInterpolation.h"
+#include "ColorSpaceCG.h"
+#include <pal/spi/cg/CoreGraphicsSPI.h>
+
+namespace WebCore {
+
+GradientRendererCG::GradientRendererCG(ColorInterpolationMethod colorInterpolationMethod, const GradientColorStopVector& stops)
+    : m_strategy { pickStrategy(colorInterpolationMethod, stops) }
+{
+}
+
+// MARK: - Strategy selection.
+
+GradientRendererCG::Strategy GradientRendererCG::pickStrategy(ColorInterpolationMethod colorInterpolationMethod, const GradientColorStopVector& stops) const
+{
+    return WTF::switchOn(colorInterpolationMethod.colorSpace,
+        [&] (const ColorInterpolationMethod::SRGB&) -> Strategy {
+            switch (colorInterpolationMethod.alphaPremultiplication) {
+            case AlphaPremultiplication::Unpremultiplied:
+                return makeGradient(colorInterpolationMethod, stops);
+            case AlphaPremultiplication::Premultiplied:
+#if HAVE(CORE_GRAPHICS_PREMULTIPLIED_INTERPOLATION_GRADIENT)
+                return makeGradient(colorInterpolationMethod, stops);
+#else
+                // FIXME: Use gradient strategy if none of the stops have alpha.
+                return makeShading(colorInterpolationMethod, stops);
+#endif
+            }
+        },
+        [&] (const auto&) -> Strategy {
+            // FIXME: Add support for the other interpolation color spaces.
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    );
+}
+
+// MARK: - Gradient strategy.
+
+GradientRendererCG::Strategy GradientRendererCG::makeGradient(ColorInterpolationMethod colorInterpolationMethod, const GradientColorStopVector& stops) const
+{
+    ASSERT_UNUSED(colorInterpolationMethod, std::holds_alternative<ColorInterpolationMethod::SRGB>(colorInterpolationMethod.colorSpace));
+#if !HAVE(CORE_GRAPHICS_PREMULTIPLIED_INTERPOLATION_GRADIENT)
+    ASSERT_UNUSED(colorInterpolationMethod, colorInterpolationMethod.alphaPremultiplication == AlphaPremultiplication::Unpremultiplied);
+#endif
+
+#if HAVE(CORE_GRAPHICS_GRADIENT_CREATE_WITH_OPTIONS)
+#if HAVE(CORE_GRAPHICS_PREMULTIPLIED_INTERPOLATION_GRADIENT)
+    auto gradientInterpolatesPremultipliedOptionsDictionary = [] () -> CFDictionaryRef {
+        static CFTypeRef keys[] = { kCGGradientInterpolatesPremultiplied };
+        static CFTypeRef values[] = { kCFBooleanTrue };
+        static CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+        return options;
+    };
+
+   auto gradientOptionsDictionary = [&] (auto colorInterpolationMethod) -> CFDictionaryRef {
+        switch (colorInterpolationMethod.alphaPremultiplication) {
+        case AlphaPremultiplication::Unpremultiplied:
+            return nullptr;
+        case AlphaPremultiplication::Premultiplied:
+            return gradientInterpolatesPremultipliedOptionsDictionary();
+        }
+   };
+#else
+   auto gradientOptionsDictionary = [] (auto) -> CFDictionaryRef {
+        return nullptr;
+   };
+#endif
+#endif
+
+    auto hasOnlyBoundedSRGBColorStops = [] (const auto& stops) {
+        for (const auto& stop : stops) {
+            if (stop.color.colorSpace() != ColorSpace::SRGB)
+                return false;
+        }
+        return true;
+    };
+
+    auto numberOfStops = stops.size();
+
+    static constexpr auto reservedStops = 3;
+    Vector<CGFloat, reservedStops> locations;
+    locations.reserveInitialCapacity(numberOfStops);
+
+    Vector<CGFloat, 4 * reservedStops> colorComponents;
+    colorComponents.reserveInitialCapacity(numberOfStops * 4);
+
+    auto gradientColorSpace = sRGBColorSpaceRef();
+
+    // FIXME: Now that we only ever use CGGradientCreateWithColorComponents, we should investigate
+    // if there is any real benefit to using sRGB when all the stops are bounded vs just using
+    // extended sRGB for all gradients.
+    if (hasOnlyBoundedSRGBColorStops(stops)) {
+        for (const auto& stop : stops) {
+            auto [colorSpace, components] = stop.color.colorSpaceAndComponents();
+            auto [r, g, b, a] = components;
+            colorComponents.uncheckedAppend(r);
+            colorComponents.uncheckedAppend(g);
+            colorComponents.uncheckedAppend(b);
+            colorComponents.uncheckedAppend(a);
+
+            locations.uncheckedAppend(stop.offset);
+        }
+    } else {
+#if HAVE(CORE_GRAPHICS_EXTENDED_SRGB_COLOR_SPACE)
+        gradientColorSpace = extendedSRGBColorSpaceRef();
+#endif
+
+        for (const auto& stop : stops) {
+#if HAVE(CORE_GRAPHICS_EXTENDED_SRGB_COLOR_SPACE)
+            auto [r, g, b, a] = stop.color.toColorTypeLossy<ExtendedSRGBA<float>>();
+#else
+            auto [r, g, b, a] = stop.color.toColorTypeLossy<SRGBA<float>>();
+#endif
+            colorComponents.uncheckedAppend(r);
+            colorComponents.uncheckedAppend(g);
+            colorComponents.uncheckedAppend(b);
+            colorComponents.uncheckedAppend(a);
+
+            locations.uncheckedAppend(stop.offset);
+        }
+    }
+
+#if HAVE(CORE_GRAPHICS_GRADIENT_CREATE_WITH_OPTIONS)
+    return Gradient { adoptCF(CGGradientCreateWithColorComponentsAndOptions(gradientColorSpace, colorComponents.data(), locations.data(), numberOfStops, gradientOptionsDictionary(colorInterpolationMethod))) };
+#else
+    return Gradient { adoptCF(CGGradientCreateWithColorComponents(gradientColorSpace, colorComponents.data(), locations.data(), numberOfStops)) };
+#endif
+}
+
+// MARK: - Shading strategy.
+
+template<typename InterpolationSpace, AlphaPremultiplication alphaPremultiplication>
+void GradientRendererCG::Shading::shadingFunction(void* info, const CGFloat* in, CGFloat* out)
+{
+    using InterpolationSpaceColorType = typename InterpolationSpace::ColorType;
+#if HAVE(CORE_GRAPHICS_EXTENDED_SRGB_COLOR_SPACE)
+    using OutputSpaceColorType = ExtendedSRGBA<float>;
+#else
+    using OutputSpaceColorType = SRGBA<float>;
+#endif
+
+    auto* data = static_cast<GradientRendererCG::Shading::Data*>(info);
+
+    // Compute color at offset 'in[0]' and assign the components to out[0 -> 3].
+
+    float requestedOffset = in[0];
+
+    // 1. Find stops that bound the requested offset.
+    auto [stop0, stop1] = [&] {
+        for (size_t stop = 1; stop < data->stops().size(); ++stop) {
+            if (requestedOffset <= data->stops()[stop].offset)
+                return std::tie(data->stops()[stop - 1], data->stops()[stop]);
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+    }();
+
+    // 2. Compute percentage offset between the two stops.
+    float offset = (stop1.offset == stop0.offset) ? 0.0f : (requestedOffset - stop0.offset) / (stop1.offset - stop0.offset);
+
+    // 3. Interpolate the two stops' colors by the computed offset.
+    // FIXME: We don't want to due hue fixup for each call, so we should figure out how to precompute that.
+    auto interpolatedColor = interpolateColorComponents<alphaPremultiplication>(
+        std::get<InterpolationSpace>(data->colorInterpolationMethod().colorSpace),
+        makeFromComponents<InterpolationSpaceColorType>(stop0.colorComponents), 1.0f - offset,
+        makeFromComponents<InterpolationSpaceColorType>(stop1.colorComponents), offset);
+
+    // 4. Convert to the output color space.
+    auto interpolatedColorConvertedToOutputSpace = asColorComponents(convertColor<OutputSpaceColorType>(interpolatedColor));
+
+    // 5. Write color components to 'out' pointer.
+    for (size_t componentIndex = 0; componentIndex < interpolatedColorConvertedToOutputSpace.size(); ++componentIndex)
+        out[componentIndex] = interpolatedColorConvertedToOutputSpace[componentIndex];
+}
+
+GradientRendererCG::Strategy GradientRendererCG::makeShading(ColorInterpolationMethod colorInterpolationMethod, const GradientColorStopVector& stops) const
+{
+    auto makeData = [&] (auto colorInterpolationMethod, auto& stops) {
+        auto convertColorToColorInterpolationSpace = [&] (const Color& color, auto colorInterpolationMethod) -> ColorComponents<float, 4> {
+            return WTF::switchOn(colorInterpolationMethod.colorSpace,
+                [&] (auto& colorSpace) -> ColorComponents<float, 4> {
+                    using ColorType = typename std::remove_reference_t<decltype(colorSpace)>::ColorType;
+                    return asColorComponents(color.template toColorTypeLossy<ColorType>());
+                }
+            );
+        };
+
+        auto totalNumberOfStops = stops.size();
+        bool hasZero = false;
+        bool hasOne = false;
+
+        for (const auto& stop : stops) {
+            auto offset = stop.offset;
+            ASSERT(offset >= 0);
+            ASSERT(offset <= 1);
+            
+            if (offset == 0)
+                hasZero = true;
+            else if (offset == 1)
+                hasOne = true;
+        }
+
+        if (!hasZero)
+            totalNumberOfStops++;
+        if (!hasOne)
+            totalNumberOfStops++;
+
+        Vector<ColorConvertedToInterpolationColorSpaceStop> convertedStops;
+        convertedStops.reserveInitialCapacity(totalNumberOfStops);
+
+        if (!hasZero)
+            convertedStops.uncheckedAppend({ 0.0f, { 0.0f, 0.0f, 0.0f, 0.0f } });
+
+        for (const auto& stop : stops)
+            convertedStops.uncheckedAppend({ stop.offset, convertColorToColorInterpolationSpace(stop.color, colorInterpolationMethod) });
+
+        if (!hasOne)
+            convertedStops.uncheckedAppend({ 1.0f, convertedStops.last().colorComponents });
+
+        if (!hasZero)
+            convertedStops[0].colorComponents = convertedStops[1].colorComponents;
+
+        return Shading::Data::create(colorInterpolationMethod, WTFMove(convertedStops));
+    };
+
+    auto makeFunction = [&] (auto colorInterpolationMethod, auto& data) {
+        auto makeEvaluateCallback = [&] (auto colorInterpolationMethod) -> CGFunctionEvaluateCallback {
+            return WTF::switchOn(colorInterpolationMethod.colorSpace,
+                [&] (auto& colorSpace) -> CGFunctionEvaluateCallback {
+                    using InterpolationMethodColorSpace = typename std::remove_reference_t<decltype(colorSpace)>;
+                    
+                    switch (colorInterpolationMethod.alphaPremultiplication) {
+                    case AlphaPremultiplication::Unpremultiplied:
+                        return &Shading::shadingFunction<InterpolationMethodColorSpace, AlphaPremultiplication::Unpremultiplied>;
+                    case AlphaPremultiplication::Premultiplied:
+                        return &Shading::shadingFunction<InterpolationMethodColorSpace, AlphaPremultiplication::Premultiplied>;
+                    }
+                }
+            );
+        };
+
+        const CGFunctionCallbacks callbacks = {
+            0,
+            makeEvaluateCallback(colorInterpolationMethod),
+            [] (void* info) {
+                static_cast<GradientRendererCG::Shading::Data*>(info)->deref();
+            }
+        };
+
+        static const CGFloat domain[2] = { 0, 1 };
+#if HAVE(CORE_GRAPHICS_EXTENDED_SRGB_COLOR_SPACE)
+        static const CGFloat range[8] = { -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), 0, 1 };
+#else
+        static const CGFloat range[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
+#endif
+
+        Ref dataRefCopy = data;
+        return adoptCF(CGFunctionCreate(&dataRefCopy.leakRef(), 1, domain, 4, range, &callbacks));
+    };
+
+    auto data = makeData(colorInterpolationMethod, stops);
+    auto function = makeFunction(colorInterpolationMethod, data);
+
+    // FIXME: Investigate using bounded sRGB when the input stops are all bounded sRGB.
+#if HAVE(CORE_GRAPHICS_EXTENDED_SRGB_COLOR_SPACE)
+    auto colorSpace = extendedSRGBColorSpaceRef();
+#else
+    auto colorSpace = sRGBColorSpaceRef();
+#endif
+
+    return Shading { WTFMove(data), WTFMove(function), colorSpace };
+}
+
+// MARK: - Drawing functions.
+
+void GradientRendererCG::drawLinearGradient(CGContextRef platformContext, CGPoint startPoint, CGPoint endPoint, CGGradientDrawingOptions options)
+{
+    WTF::switchOn(m_strategy,
+        [&] (Gradient& gradient) {
+            CGContextDrawLinearGradient(platformContext, gradient.gradient.get(), startPoint, endPoint, options);
+        },
+        [&] (Shading& shading) {
+            bool startExtend = (options & kCGGradientDrawsBeforeStartLocation) != 0;
+            bool endExtend = (options & kCGGradientDrawsAfterEndLocation) != 0;
+
+            CGContextDrawShading(platformContext, adoptCF(CGShadingCreateAxial(shading.colorSpace.get(), startPoint, endPoint, shading.function.get(), startExtend, endExtend)).get());
+        }
+    );
+}
+
+void GradientRendererCG::drawRadialGradient(CGContextRef platformContext, CGPoint startCenter, CGFloat startRadius, CGPoint endCenter, CGFloat endRadius, CGGradientDrawingOptions options)
+{
+    WTF::switchOn(m_strategy,
+        [&] (Gradient& gradient) {
+            CGContextDrawRadialGradient(platformContext, gradient.gradient.get(), startCenter, startRadius, endCenter, endRadius, options);
+        },
+        [&] (Shading& shading) {
+            bool startExtend = (options & kCGGradientDrawsBeforeStartLocation) != 0;
+            bool endExtend = (options & kCGGradientDrawsAfterEndLocation) != 0;
+
+            CGContextDrawShading(platformContext, adoptCF(CGShadingCreateRadial(shading.colorSpace.get(), startCenter, startRadius, endCenter, endRadius, shading.function.get(), startExtend, endExtend)).get());
+        }
+    );
+}
+
+void GradientRendererCG::drawConicGradient(CGContextRef platformContext, CGPoint center, CGFloat angle)
+{
+// FIXME: Seems like this should be HAVE(CG_CONTEXT_DRAW_CONIC_GRADIENT).
+// FIXME: Can we change tvOS to be like the other Cocoa platforms?
+#if PLATFORM(COCOA) && !PLATFORM(APPLETV)
+    WTF::switchOn(m_strategy,
+        [&] (Gradient& gradient) {
+            CGContextDrawConicGradient(platformContext, gradient.gradient.get(), center, angle);
+        },
+        [&] (Shading& shading) {
+            CGContextDrawShading(platformContext, adoptCF(CGShadingCreateConic(shading.colorSpace.get(), center, angle, shading.function.get())).get());
+        }
+    );
+#else
+    UNUSED_PARAM(platformContext);
+    UNUSED_PARAM(center);
+    UNUSED_PARAM(angle);
+#endif
+}
+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicscgGradientRendererCGh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.h (0 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.h                           (rev 0)
+++ trunk/Source/WebCore/platform/graphics/cg/GradientRendererCG.h      2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -0,0 +1,94 @@
</span><ins>+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ColorComponents.h"
+#include "ColorInterpolationMethod.h"
+#include "GradientColorStop.h"
+#include <CoreGraphics/CoreGraphics.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+struct ColorConvertedToInterpolationColorSpaceStop {
+    float offset;
+    ColorComponents<float, 4> colorComponents;
+};
+
+class GradientRendererCG {
+public:
+    GradientRendererCG(ColorInterpolationMethod, const GradientColorStopVector&);
+
+    void drawLinearGradient(CGContextRef, CGPoint startPoint, CGPoint endPoint, CGGradientDrawingOptions);
+    void drawRadialGradient(CGContextRef, CGPoint startCenter, CGFloat startRadius, CGPoint endCenter, CGFloat endRadius, CGGradientDrawingOptions);
+    void drawConicGradient(CGContextRef, CGPoint center, CGFloat angle);
+
+private:
+    struct Gradient {
+        RetainPtr<CGGradientRef> gradient;
+    };
+
+    struct Shading {
+        template<typename InterpolationSpace, AlphaPremultiplication> static void shadingFunction(void*, const CGFloat*, CGFloat*);
+
+        class Data : public ThreadSafeRefCounted<Data> {
+        public:
+            static Ref<Data> create(ColorInterpolationMethod colorInterpolationMethod, Vector<ColorConvertedToInterpolationColorSpaceStop> stops)
+            {
+                return adoptRef(*new Data(colorInterpolationMethod, WTFMove(stops)));
+            }
+
+            ColorInterpolationMethod colorInterpolationMethod() const { return m_colorInterpolationMethod; }
+            const Vector<ColorConvertedToInterpolationColorSpaceStop>& stops() const { return m_stops; }
+
+        private:
+            Data(ColorInterpolationMethod colorInterpolationMethod, Vector<ColorConvertedToInterpolationColorSpaceStop> stops)
+                : m_colorInterpolationMethod { colorInterpolationMethod }
+                , m_stops { WTFMove(stops) }
+            {
+            }
+
+            ColorInterpolationMethod m_colorInterpolationMethod;
+            Vector<ColorConvertedToInterpolationColorSpaceStop> m_stops;
+        };
+
+        Ref<Data> data;
+        RetainPtr<CGFunctionRef> function;
+        RetainPtr<CGColorSpaceRef> colorSpace;
+    };
+
+    using Strategy = std::variant<Gradient, Shading>;
+
+    Strategy pickStrategy(ColorInterpolationMethod, const GradientColorStopVector&) const;
+    Strategy makeGradient(ColorInterpolationMethod, const GradientColorStopVector&) const;
+    Strategy makeShading(ColorInterpolationMethod, const GradientColorStopVector&) const;
+
+    Strategy m_strategy;
+};
+
+}
</ins></span></pre></div>
<a id="trunkSourceWebKitLegacywinChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKitLegacy/win/ChangeLog (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKitLegacy/win/ChangeLog  2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebKitLegacy/win/ChangeLog     2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2021-12-21  Sam Weinig  <weinig@apple.com>
+
+        Add support for premultiplied alpha interpolated gradients and defaulted off option to use them for CSS Gradients
+        https://bugs.webkit.org/show_bug.cgi?id=234492
+
+        Reviewed by Simon Fraser.
+
+        Add support for tests enabling the CSSGradientPremultipliedAlphaInterpolationEnabled preference.
+
+        * WebPreferences.cpp:
+        (WebPreferences::cssGradientPremultipliedAlphaInterpolationEnabled):
+        * WebPreferences.h:
+        * WebView.cpp:
+        (WebView::notifyPreferencesChanged):
+
</ins><span class="cx"> 2021-12-20  Fujii Hironori  <Hironori.Fujii@sony.com>
</span><span class="cx"> 
</span><span class="cx">         [Win] MSVC reports "COMPropertyBag.h(233): error C2385: ambiguous access of 'IUnknown'" with /std:c++20
</span></span></pre></div>
<a id="trunkSourceWebKitLegacywinWebPreferencescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKitLegacy/win/WebPreferences.cpp (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKitLegacy/win/WebPreferences.cpp 2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebKitLegacy/win/WebPreferences.cpp    2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -2637,6 +2637,11 @@
</span><span class="cx">     return boolValueForKey("WebKitCanvasColorSpaceEnabled");
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool WebPreferences::cssGradientPremultipliedAlphaInterpolationEnabled()
+{
+    return boolValueForKey("WebKitCSSGradientPremultipliedAlphaInterpolationEnabled");
+}
+
</ins><span class="cx"> bool WebPreferences::mockScrollbarsControllerEnabled()
</span><span class="cx"> {
</span><span class="cx">     return boolValueForKey("WebKitMockScrollbarsControllerEnabled");
</span></span></pre></div>
<a id="trunkSourceWebKitLegacywinWebPreferencesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKitLegacy/win/WebPreferences.h (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKitLegacy/win/WebPreferences.h   2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebKitLegacy/win/WebPreferences.h      2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -346,6 +346,7 @@
</span><span class="cx">     // The following preference accessors are not exposed via IWebPreferences* as they are only
</span><span class="cx">     // needed for testing purposes and can be toggled via the set*PreferenceForTesting functions.
</span><span class="cx">     bool canvasColorSpaceEnabled();
</span><ins>+    bool cssGradientPremultipliedAlphaInterpolationEnabled();
</ins><span class="cx">     bool mockScrollbarsControllerEnabled();
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceWebKitLegacywinWebViewcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKitLegacy/win/WebView.cpp (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKitLegacy/win/WebView.cpp        2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Source/WebKitLegacy/win/WebView.cpp   2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -5600,6 +5600,7 @@
</span><span class="cx">     settings.setOverscrollBehaviorEnabled(!!enabled);
</span><span class="cx"> 
</span><span class="cx">     settings.setCanvasColorSpaceEnabled(m_preferences->canvasColorSpaceEnabled());
</span><ins>+    settings.setCSSGradientPremultipliedAlphaInterpolationEnabled(m_preferences->cssGradientPremultipliedAlphaInterpolationEnabled());
</ins><span class="cx">     settings.setMockScrollbarsControllerEnabled(m_preferences->mockScrollbarsControllerEnabled());
</span><span class="cx"> 
</span><span class="cx">     return S_OK;
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Tools/ChangeLog       2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2021-12-21  Sam Weinig  <weinig@apple.com>
+
+        Add support for premultiplied alpha interpolated gradients and defaulted off option to use them for CSS Gradients
+        https://bugs.webkit.org/show_bug.cgi?id=234492
+
+        Reviewed by Simon Fraser.
+
+        * DumpRenderTree/TestOptions.cpp:
+        (WTR::TestOptions::defaults):
+        Add default for Windows WebKitLegacy testing which still requires it.
+
</ins><span class="cx"> 2021-12-21  Carlos Garcia Campos  <cgarcia@igalia.com>
</span><span class="cx"> 
</span><span class="cx">         [GTK][a11y] Implement list markers when building with ATSPI
</span></span></pre></div>
<a id="trunkToolsDumpRenderTreeTestOptionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/DumpRenderTree/TestOptions.cpp (287309 => 287310)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/DumpRenderTree/TestOptions.cpp       2021-12-21 12:38:52 UTC (rev 287309)
+++ trunk/Tools/DumpRenderTree/TestOptions.cpp  2021-12-21 12:42:19 UTC (rev 287310)
</span><span class="lines">@@ -135,6 +135,7 @@
</span><span class="cx">             { "CSSContainmentEnabled", false },
</span><span class="cx">             { "CSSCounterStyleAtRuleImageSymbolsEnabled", false },
</span><span class="cx">             { "CSSCounterStyleAtRulesEnabled", false },
</span><ins>+            { "CSSGradientPremultipliedAlphaInterpolationEnabled", true },
</ins><span class="cx">             { "CSSLogicalEnabled", false },
</span><span class="cx">             { "CSSOMViewSmoothScrollingEnabled", false },
</span><span class="cx">             { "CanvasColorSpaceEnabled", true },
</span></span></pre>
</div>
</div>

</body>
</html>