Title: [278364] trunk
Revision
278364
Author
wei...@apple.com
Date
2021-06-02 10:38:56 -0700 (Wed, 02 Jun 2021)

Log Message

Add support for "relative color syntax" for color()
https://bugs.webkit.org/show_bug.cgi?id=226513

Reviewed by Darin Adler.

Source/WebCore:

CSS Color 5 has recently been update to support relative color syntax for
the color() function in addition to the existing rgb(), hsl(), hwb(), lab()
and lch().

Took the opertunity to refactor other relative color syntax parsing to share
more code between relative and non-relative parsers using a shared function
with lambdas to differentiate the component consumers. This was done for all
the color types except rgb() and hsl(), which have notable differences in
parsing between the relative and non-relative version.

* css/parser/CSSPropertyParserHelpers.cpp:
(WebCore::CSSPropertyParserHelpers::parseNonRelativeRGBParameters):
(WebCore::CSSPropertyParserHelpers::parseRGBParameters):
(WebCore::CSSPropertyParserHelpers::colorByNormalizingHSLComponents):
(WebCore::CSSPropertyParserHelpers::parseRelativeHSLParameters):
(WebCore::CSSPropertyParserHelpers::parseNonRelativeHSLParameters):
(WebCore::CSSPropertyParserHelpers::parseHSLParameters):
(WebCore::CSSPropertyParserHelpers::parseHWBParameters):
(WebCore::CSSPropertyParserHelpers::parseRelativeHWBParameters):
(WebCore::CSSPropertyParserHelpers::parseNonRelativeHWBParameters):
(WebCore::CSSPropertyParserHelpers::parseLabParameters):
(WebCore::CSSPropertyParserHelpers::parseRelativeLabParameters):
(WebCore::CSSPropertyParserHelpers::parseNonRelativeLabParameters):
(WebCore::CSSPropertyParserHelpers::parseLCHParameters):
(WebCore::CSSPropertyParserHelpers::parseRelativeLCHParameters):
(WebCore::CSSPropertyParserHelpers::parseNonRelativeLCHParameters):
(WebCore::CSSPropertyParserHelpers::parseColorFunctionForRGBTypes):
(WebCore::CSSPropertyParserHelpers::parseRelativeColorFunctionForRGBTypes):
(WebCore::CSSPropertyParserHelpers::parseColorFunctionForXYZParameters):
(WebCore::CSSPropertyParserHelpers::parseRelativeColorFunctionForXYZParameters):
(WebCore::CSSPropertyParserHelpers::parseRelativeColorFunctionParameters):
(WebCore::CSSPropertyParserHelpers::parseNonRelativeColorFunctionParameters):
(WebCore::CSSPropertyParserHelpers::parseColorFunctionParameters):

LayoutTests:

Updated test and results now that we support relative color syntax
for color(srgb ...), color(a98-rgb ...), color(rec2020 ...),
color(prophoto-rgb ...) and color(xyz ...).

* fast/css/parsing-relative-color-syntax-expected.txt:
* fast/css/parsing-relative-color-syntax.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (278363 => 278364)


--- trunk/LayoutTests/ChangeLog	2021-06-02 17:07:03 UTC (rev 278363)
+++ trunk/LayoutTests/ChangeLog	2021-06-02 17:38:56 UTC (rev 278364)
@@ -1,3 +1,17 @@
+2021-06-02  Sam Weinig  <wei...@apple.com>
+
+        Add support for "relative color syntax" for color()
+        https://bugs.webkit.org/show_bug.cgi?id=226513
+
+        Reviewed by Darin Adler.
+
+        Updated test and results now that we support relative color syntax
+        for color(srgb ...), color(a98-rgb ...), color(rec2020 ...),
+        color(prophoto-rgb ...) and color(xyz ...).
+
+        * fast/css/parsing-relative-color-syntax-expected.txt:
+        * fast/css/parsing-relative-color-syntax.html:
+
 2021-06-02  Kyle Piddington  <kpidding...@apple.com>
 
         Add 'mix' override with bool-vectors to MSL translator

Modified: trunk/LayoutTests/fast/css/parsing-relative-color-syntax-expected.txt (278363 => 278364)


--- trunk/LayoutTests/fast/css/parsing-relative-color-syntax-expected.txt	2021-06-02 17:07:03 UTC (rev 278363)
+++ trunk/LayoutTests/fast/css/parsing-relative-color-syntax-expected.txt	2021-06-02 17:38:56 UTC (rev 278364)
@@ -285,6 +285,261 @@
 PASS computedStyle("background-color", "lch(from lch(70% 45 30) lightness c h)") is "rgba(0, 0, 0, 0)"
 PASS computedStyle("background-color", "lch(from lch(70% 45 30) x c h)") is "rgba(0, 0, 0, 0)"
 PASS computedStyle("background-color", "lch(from lch(70% 45 30) l g b)") is "rgba(0, 0, 0, 0)"
+
+color(from ... ${color} ...)
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b)") is "color(srgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b / alpha)") is "color(srgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g b)") is "color(srgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g b / alpha)") is "color(srgb 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(from color(srgb 0.7 0.5 0.3) srgb r g b) srgb r g b)") is "color(srgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 0 0 0)") is "color(srgb 0 0 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 0 0 0)") is "color(srgb 0 0 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 0 0 0 / 0)") is "color(srgb 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 0 0 0 / 0)") is "color(srgb 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 0 g b / alpha)") is "color(srgb 0 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r 0 b / alpha)") is "color(srgb 0.7 0 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g 0 / alpha)") is "color(srgb 0.7 0.5 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b / 0)") is "color(srgb 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb 0 g b / alpha)") is "color(srgb 0 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r 0 b / alpha)") is "color(srgb 0.7 0 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g 0 / alpha)") is "color(srgb 0.7 0.5 0 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g b / 0)") is "color(srgb 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 0.2 g b / alpha)") is "color(srgb 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 20% g b / alpha)") is "color(srgb 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r 0.2 b / alpha)") is "color(srgb 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r 20% b / alpha)") is "color(srgb 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g 0.2 / alpha)") is "color(srgb 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g 20% / alpha)") is "color(srgb 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b / 0.2)") is "color(srgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b / 20%)") is "color(srgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb 0.2 g b / alpha)") is "color(srgb 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb 20% g b / alpha)") is "color(srgb 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r 0.2 b / alpha)") is "color(srgb 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r 20% b / alpha)") is "color(srgb 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g 0.2 / alpha)") is "color(srgb 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g 20% / alpha)") is "color(srgb 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g b / 0.2)") is "color(srgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r g b / 20%)") is "color(srgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb g b r)") is "color(srgb 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb b alpha r / g)") is "color(srgb 0.3 1 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r r r / r)") is "color(srgb 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb alpha alpha alpha / alpha)") is "color(srgb 1 1 1)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb g b r)") is "color(srgb 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb b alpha r / g)") is "color(srgb 0.3 0.4 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb r r r / r)") is "color(srgb 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb alpha alpha alpha / alpha)") is "color(srgb 0.4 0.4 0.4 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb calc(r) calc(g) calc(b))") is "color(srgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3 / 40%) srgb calc(r) calc(g) calc(b) / calc(alpha))") is "color(srgb 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb 10deg g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r 10deg b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb r g b / 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb red g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb x g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(srgb 0.7 0.5 0.3) srgb l g b)") is "rgba(0, 0, 0, 0)"
+
+color(from ... ${color} ...)
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b)") is "color(a98-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b / alpha)") is "color(a98-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g b)") is "color(a98-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g b / alpha)") is "color(a98-rgb 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b) a98-rgb r g b)") is "color(a98-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 0 0 0)") is "color(a98-rgb 0 0 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 0 0 0)") is "color(a98-rgb 0 0 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 0 0 0 / 0)") is "color(a98-rgb 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 0 0 0 / 0)") is "color(a98-rgb 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 0 g b / alpha)") is "color(a98-rgb 0 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r 0 b / alpha)") is "color(a98-rgb 0.7 0 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g 0 / alpha)") is "color(a98-rgb 0.7 0.5 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b / 0)") is "color(a98-rgb 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb 0 g b / alpha)") is "color(a98-rgb 0 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r 0 b / alpha)") is "color(a98-rgb 0.7 0 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g 0 / alpha)") is "color(a98-rgb 0.7 0.5 0 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g b / 0)") is "color(a98-rgb 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 0.2 g b / alpha)") is "color(a98-rgb 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 20% g b / alpha)") is "color(a98-rgb 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r 0.2 b / alpha)") is "color(a98-rgb 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r 20% b / alpha)") is "color(a98-rgb 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g 0.2 / alpha)") is "color(a98-rgb 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g 20% / alpha)") is "color(a98-rgb 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b / 0.2)") is "color(a98-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b / 20%)") is "color(a98-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb 0.2 g b / alpha)") is "color(a98-rgb 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb 20% g b / alpha)") is "color(a98-rgb 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r 0.2 b / alpha)") is "color(a98-rgb 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r 20% b / alpha)") is "color(a98-rgb 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g 0.2 / alpha)") is "color(a98-rgb 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g 20% / alpha)") is "color(a98-rgb 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g b / 0.2)") is "color(a98-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r g b / 20%)") is "color(a98-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb g b r)") is "color(a98-rgb 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb b alpha r / g)") is "color(a98-rgb 0.3 1 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r r r / r)") is "color(a98-rgb 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb alpha alpha alpha / alpha)") is "color(a98-rgb 1 1 1)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb g b r)") is "color(a98-rgb 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb b alpha r / g)") is "color(a98-rgb 0.3 0.4 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb r r r / r)") is "color(a98-rgb 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb alpha alpha alpha / alpha)") is "color(a98-rgb 0.4 0.4 0.4 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb calc(r) calc(g) calc(b))") is "color(a98-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3 / 40%) a98-rgb calc(r) calc(g) calc(b) / calc(alpha))") is "color(a98-rgb 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb 10deg g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r 10deg b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb r g b / 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb red g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb x g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(a98-rgb 0.7 0.5 0.3) a98-rgb l g b)") is "rgba(0, 0, 0, 0)"
+
+color(from ... ${color} ...)
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b)") is "color(rec2020 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b / alpha)") is "color(rec2020 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g b)") is "color(rec2020 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g b / alpha)") is "color(rec2020 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b) rec2020 r g b)") is "color(rec2020 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 0 0 0)") is "color(rec2020 0 0 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 0 0 0)") is "color(rec2020 0 0 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 0 0 0 / 0)") is "color(rec2020 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 0 0 0 / 0)") is "color(rec2020 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 0 g b / alpha)") is "color(rec2020 0 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r 0 b / alpha)") is "color(rec2020 0.7 0 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g 0 / alpha)") is "color(rec2020 0.7 0.5 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b / 0)") is "color(rec2020 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 0 g b / alpha)") is "color(rec2020 0 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r 0 b / alpha)") is "color(rec2020 0.7 0 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g 0 / alpha)") is "color(rec2020 0.7 0.5 0 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g b / 0)") is "color(rec2020 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 0.2 g b / alpha)") is "color(rec2020 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 20% g b / alpha)") is "color(rec2020 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r 0.2 b / alpha)") is "color(rec2020 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r 20% b / alpha)") is "color(rec2020 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g 0.2 / alpha)") is "color(rec2020 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g 20% / alpha)") is "color(rec2020 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b / 0.2)") is "color(rec2020 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b / 20%)") is "color(rec2020 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 0.2 g b / alpha)") is "color(rec2020 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 20% g b / alpha)") is "color(rec2020 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r 0.2 b / alpha)") is "color(rec2020 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r 20% b / alpha)") is "color(rec2020 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g 0.2 / alpha)") is "color(rec2020 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g 20% / alpha)") is "color(rec2020 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g b / 0.2)") is "color(rec2020 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r g b / 20%)") is "color(rec2020 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 g b r)") is "color(rec2020 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 b alpha r / g)") is "color(rec2020 0.3 1 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r r r / r)") is "color(rec2020 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 alpha alpha alpha / alpha)") is "color(rec2020 1 1 1)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 g b r)") is "color(rec2020 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 b alpha r / g)") is "color(rec2020 0.3 0.4 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 r r r / r)") is "color(rec2020 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 alpha alpha alpha / alpha)") is "color(rec2020 0.4 0.4 0.4 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 calc(r) calc(g) calc(b))") is "color(rec2020 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3 / 40%) rec2020 calc(r) calc(g) calc(b) / calc(alpha))") is "color(rec2020 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 10deg g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r 10deg b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 r g b / 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 red g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 x g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(rec2020 0.7 0.5 0.3) rec2020 l g b)") is "rgba(0, 0, 0, 0)"
+
+color(from ... ${color} ...)
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b)") is "color(prophoto-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b / alpha)") is "color(prophoto-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g b)") is "color(prophoto-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g b / alpha)") is "color(prophoto-rgb 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b) prophoto-rgb r g b)") is "color(prophoto-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 0 0 0)") is "color(prophoto-rgb 0 0 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 0 0 0)") is "color(prophoto-rgb 0 0 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 0 0 0 / 0)") is "color(prophoto-rgb 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 0 0 0 / 0)") is "color(prophoto-rgb 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 0 g b / alpha)") is "color(prophoto-rgb 0 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r 0 b / alpha)") is "color(prophoto-rgb 0.7 0 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g 0 / alpha)") is "color(prophoto-rgb 0.7 0.5 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b / 0)") is "color(prophoto-rgb 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb 0 g b / alpha)") is "color(prophoto-rgb 0 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r 0 b / alpha)") is "color(prophoto-rgb 0.7 0 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g 0 / alpha)") is "color(prophoto-rgb 0.7 0.5 0 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g b / 0)") is "color(prophoto-rgb 0.7 0.5 0.3 / 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 0.2 g b / alpha)") is "color(prophoto-rgb 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 20% g b / alpha)") is "color(prophoto-rgb 0.2 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r 0.2 b / alpha)") is "color(prophoto-rgb 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r 20% b / alpha)") is "color(prophoto-rgb 0.7 0.2 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g 0.2 / alpha)") is "color(prophoto-rgb 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g 20% / alpha)") is "color(prophoto-rgb 0.7 0.5 0.2)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b / 0.2)") is "color(prophoto-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b / 20%)") is "color(prophoto-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb 0.2 g b / alpha)") is "color(prophoto-rgb 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb 20% g b / alpha)") is "color(prophoto-rgb 0.2 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r 0.2 b / alpha)") is "color(prophoto-rgb 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r 20% b / alpha)") is "color(prophoto-rgb 0.7 0.2 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g 0.2 / alpha)") is "color(prophoto-rgb 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g 20% / alpha)") is "color(prophoto-rgb 0.7 0.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g b / 0.2)") is "color(prophoto-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r g b / 20%)") is "color(prophoto-rgb 0.7 0.5 0.3 / 0.2)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb g b r)") is "color(prophoto-rgb 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb b alpha r / g)") is "color(prophoto-rgb 0.3 1 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r r r / r)") is "color(prophoto-rgb 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb alpha alpha alpha / alpha)") is "color(prophoto-rgb 1 1 1)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb g b r)") is "color(prophoto-rgb 0.5 0.3 0.7)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb b alpha r / g)") is "color(prophoto-rgb 0.3 0.4 0.7 / 0.5)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb r r r / r)") is "color(prophoto-rgb 0.7 0.7 0.7 / 0.7)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb alpha alpha alpha / alpha)") is "color(prophoto-rgb 0.4 0.4 0.4 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb calc(r) calc(g) calc(b))") is "color(prophoto-rgb 0.7 0.5 0.3)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3 / 40%) prophoto-rgb calc(r) calc(g) calc(b) / calc(alpha))") is "color(prophoto-rgb 0.7 0.5 0.3 / 0.4)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb 10deg g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r 10deg b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb r g b / 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb red g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb x g b)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(prophoto-rgb 0.7 0.5 0.3) prophoto-rgb l g b)") is "rgba(0, 0, 0, 0)"
+
+color(from ... xyz ...)
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y z)") is "color(xyz 7 -20.5 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y z / alpha)") is "color(xyz 7 -20.5 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x y z)") is "color(xyz 7 -20.5 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x y z / alpha)") is "color(xyz 7 -20.5 100 / 0.4)"
+PASS computedStyle("background-color", "color(from color(from color(xyz 7 -20.5 100) xyz x y z) xyz x y z)") is "color(xyz 7 -20.5 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz 0 0 0)") is "color(xyz 0 0 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz 0 0 0)") is "color(xyz 0 0 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz 0 0 0 / 0)") is "color(xyz 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz 0 0 0 / 0)") is "color(xyz 0 0 0 / 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz 0 y z / alpha)") is "color(xyz 0 -20.5 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x 0 z / alpha)") is "color(xyz 7 0 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y 0 / alpha)") is "color(xyz 7 -20.5 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y z / 0)") is "color(xyz 7 -20.5 100 / 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz 0 y z / alpha)") is "color(xyz 0 -20.5 100 / 0.4)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x 0 z / alpha)") is "color(xyz 7 0 100 / 0.4)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x y 0 / alpha)") is "color(xyz 7 -20.5 0 / 0.4)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x y z / 0)") is "color(xyz 7 -20.5 100 / 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz 0.2 y z / alpha)") is "color(xyz 0.2 -20.5 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x 0.2 z / alpha)") is "color(xyz 7 0.2 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y 0.2 / alpha)") is "color(xyz 7 -20.5 0.2)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y z / 0.2)") is "color(xyz 7 -20.5 100 / 0.2)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y z / 20%)") is "color(xyz 7 -20.5 100 / 0.2)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz 0.2 y z / alpha)") is "color(xyz 0.2 -20.5 100 / 0.4)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x 0.2 z / alpha)") is "color(xyz 7 0.2 100 / 0.4)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x y 0.2 / alpha)") is "color(xyz 7 -20.5 0.2 / 0.4)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x y z / 0.2)") is "color(xyz 7 -20.5 100 / 0.2)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz y z x)") is "color(xyz -20.5 100 7)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x x x / x)") is "color(xyz 7 7 7)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz y z x)") is "color(xyz -20.5 100 7)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz x x x / x)") is "color(xyz 7 7 7)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz z alpha x / y)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz alpha alpha alpha / alpha)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz z alpha x / y)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz alpha alpha alpha / alpha)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz calc(x) calc(y) calc(z))") is "color(xyz 7 -20.5 100)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100 / 40%) xyz calc(x) calc(y) calc(z) / calc(alpha))") is "color(xyz 7 -20.5 100 / 0.4)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz 10deg y z)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x 10deg z)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz x y z / 10deg)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz red y)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz r y z)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color(from color(xyz 7 -20.5 100) xyz l y z)") is "rgba(0, 0, 0, 0)"
+
+Spec Examples
 PASS computedStyle("background-color", "rgb(from var(--bg-color) r g b / 80%)") is "rgba(0, 0, 255, 0.8)"
 PASS computedStyle("background-color", "lch(from var(--color) calc(l / 2) c h)") is "lch(23.138971% 67.989716 134.39125)"
 PASS computedStyle("background-color", "rgb(from var(--color) calc(r * .3 + g * .59 + b * .11) calc(r * .3 + g * .59 + b * .11) calc(r * .3 + g * .59 + b * .11))") is "rgb(76, 76, 76)"

Modified: trunk/LayoutTests/fast/css/parsing-relative-color-syntax.html (278363 => 278364)


--- trunk/LayoutTests/fast/css/parsing-relative-color-syntax.html	2021-06-02 17:07:03 UTC (rev 278363)
+++ trunk/LayoutTests/fast/css/parsing-relative-color-syntax.html	2021-06-02 17:38:56 UTC (rev 278364)
@@ -444,13 +444,151 @@
     testComputed(`lch(from lch(70% 45 30) l g b)`, `rgba(0, 0, 0, 0)`);
 
 
-    // Spec examples:
+    for (const color of [ "srgb", "a98-rgb", "rec2020", "prophoto-rgb" ]) {
+        debug('');
+        debug('color(from ... ${color} ...)');
+
+        // Testing no modifications.
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b)`,                              `color(${color} 0.7 0.5 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / alpha)`,                      `color(${color} 0.7 0.5 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b)`,                        `color(${color} 0.7 0.5 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / alpha)`,                `color(${color} 0.7 0.5 0.3 / 0.4)`);
+
+        // Test nesting relative colors.
+        testComputed(`color(from color(from color(${color} 0.7 0.5 0.3) ${color} r g b) ${color} r g b)`,   `color(${color} 0.7 0.5 0.3)`);
+
+        // Testing replacement with 0.
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0)`,                              `color(${color} 0 0 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0)`,                              `color(${color} 0 0 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0 / 0)`,                          `color(${color} 0 0 0 / 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 0 0 / 0)`,                          `color(${color} 0 0 0 / 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0 g b / alpha)`,                      `color(${color} 0 0.5 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 0 b / alpha)`,                      `color(${color} 0.7 0 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 0 / alpha)`,                      `color(${color} 0.7 0.5 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 0)`,                          `color(${color} 0.7 0.5 0.3 / 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} 0 g b / alpha)`,                `color(${color} 0 0.5 0.3 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r 0 b / alpha)`,                `color(${color} 0.7 0 0.3 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g 0 / alpha)`,                `color(${color} 0.7 0.5 0 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / 0)`,                    `color(${color} 0.7 0.5 0.3 / 0)`);
+
+        // Testing replacement with a constant.
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 0.2 g b / alpha)`,                    `color(${color} 0.2 0.5 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 20% g b / alpha)`,                    `color(${color} 0.2 0.5 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 0.2 b / alpha)`,                    `color(${color} 0.7 0.2 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 20% b / alpha)`,                    `color(${color} 0.7 0.2 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 0.2 / alpha)`,                    `color(${color} 0.7 0.5 0.2)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 20% / alpha)`,                    `color(${color} 0.7 0.5 0.2)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 0.2)`,                        `color(${color} 0.7 0.5 0.3 / 0.2)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 20%)`,                        `color(${color} 0.7 0.5 0.3 / 0.2)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} 0.2 g b / alpha)`,              `color(${color} 0.2 0.5 0.3 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} 20% g b / alpha)`,              `color(${color} 0.2 0.5 0.3 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r 0.2 b / alpha)`,              `color(${color} 0.7 0.2 0.3 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r 20% b / alpha)`,              `color(${color} 0.7 0.2 0.3 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g 0.2 / alpha)`,              `color(${color} 0.7 0.5 0.2 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g 20% / alpha)`,              `color(${color} 0.7 0.5 0.2 / 0.4)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / 0.2)`,                  `color(${color} 0.7 0.5 0.3 / 0.2)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r g b / 20%)`,                  `color(${color} 0.7 0.5 0.3 / 0.2)`);
+
+        // Testing valid permutation (types match).
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} g b r)`,                              `color(${color} 0.5 0.3 0.7)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} b alpha r / g)`,                      `color(${color} 0.3 1 0.7 / 0.5)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r r r / r)`,                          `color(${color} 0.7 0.7 0.7 / 0.7)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} alpha alpha alpha / alpha)`,          `color(${color} 1 1 1)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} g b r)`,                        `color(${color} 0.5 0.3 0.7)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} b alpha r / g)`,                `color(${color} 0.3 0.4 0.7 / 0.5)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} r r r / r)`,                    `color(${color} 0.7 0.7 0.7 / 0.7)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} alpha alpha alpha / alpha)`,    `color(${color} 0.4 0.4 0.4 / 0.4)`);
+
+        // Testing with calc().
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} calc(r) calc(g) calc(b))`,                        `color(${color} 0.7 0.5 0.3)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3 / 40%) ${color} calc(r) calc(g) calc(b) / calc(alpha))`,    `color(${color} 0.7 0.5 0.3 / 0.4)`);
+
+        // Testing invalid values.
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} 10deg g b)`,                          `rgba(0, 0, 0, 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r 10deg b)`,                          `rgba(0, 0, 0, 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g 10deg)`,                          `rgba(0, 0, 0, 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} r g b / 10deg)`,                      `rgba(0, 0, 0, 0)`);
+
+        // Testing invalid component names
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} red g b)`,                            `rgba(0, 0, 0, 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} x g b)`,                              `rgba(0, 0, 0, 0)`);
+        testComputed(`color(from color(${color} 0.7 0.5 0.3) ${color} l g b)`,                              `rgba(0, 0, 0, 0)`);
+    }
+
+    debug('');
+    debug('color(from ... xyz ...)');
+
+    // Testing no modifications.
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y z)`,                              `color(xyz 7 -20.5 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y z / alpha)`,                      `color(xyz 7 -20.5 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x y z)`,                        `color(xyz 7 -20.5 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x y z / alpha)`,                `color(xyz 7 -20.5 100 / 0.4)`);
+
+    // Test nesting relative colors.
+    testComputed(`color(from color(from color(xyz 7 -20.5 100) xyz x y z) xyz x y z)`,        `color(xyz 7 -20.5 100)`);
+
+    // Testing replacement with 0.
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz 0 0 0)`,                              `color(xyz 0 0 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz 0 0 0)`,                              `color(xyz 0 0 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz 0 0 0 / 0)`,                          `color(xyz 0 0 0 / 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz 0 0 0 / 0)`,                          `color(xyz 0 0 0 / 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz 0 y z / alpha)`,                      `color(xyz 0 -20.5 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x 0 z / alpha)`,                      `color(xyz 7 0 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y 0 / alpha)`,                      `color(xyz 7 -20.5 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y z / 0)`,                          `color(xyz 7 -20.5 100 / 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz 0 y z / alpha)`,                `color(xyz 0 -20.5 100 / 0.4)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x 0 z / alpha)`,                `color(xyz 7 0 100 / 0.4)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x y 0 / alpha)`,                `color(xyz 7 -20.5 0 / 0.4)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x y z / 0)`,                    `color(xyz 7 -20.5 100 / 0)`);
+
+    // Testing replacement with a constant.
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz 0.2 y z / alpha)`,                    `color(xyz 0.2 -20.5 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x 0.2 z / alpha)`,                    `color(xyz 7 0.2 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y 0.2 / alpha)`,                    `color(xyz 7 -20.5 0.2)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y z / 0.2)`,                        `color(xyz 7 -20.5 100 / 0.2)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y z / 20%)`,                        `color(xyz 7 -20.5 100 / 0.2)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz 0.2 y z / alpha)`,              `color(xyz 0.2 -20.5 100 / 0.4)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x 0.2 z / alpha)`,              `color(xyz 7 0.2 100 / 0.4)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x y 0.2 / alpha)`,              `color(xyz 7 -20.5 0.2 / 0.4)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x y z / 0.2)`,                  `color(xyz 7 -20.5 100 / 0.2)`);
+
+    // Testing valid permutation (types match).
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz y z x)`,                              `color(xyz -20.5 100 7)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x x x / x)`,                          `color(xyz 7 7 7)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz y z x)`,                        `color(xyz -20.5 100 7)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz x x x / x)`,                    `color(xyz 7 7 7)`);
+
+    // Testing invalid permutation (types don't match).
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz z alpha x / y)`,                      `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz alpha alpha alpha / alpha)`,          `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz z alpha x / y)`,                `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz alpha alpha alpha / alpha)`,    `rgba(0, 0, 0, 0)`);
+
+    // Testing with calc().
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz calc(x) calc(y) calc(z))`,                        `color(xyz 7 -20.5 100)`);
+    testComputed(`color(from color(xyz 7 -20.5 100 / 40%) xyz calc(x) calc(y) calc(z) / calc(alpha))`,    `color(xyz 7 -20.5 100 / 0.4)`);
+
+    // Testing invalid values.
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz 10deg y z)`,                          `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x 10deg z)`,                          `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y 10deg)`,                          `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz x y z / 10deg)`,                      `rgba(0, 0, 0, 0)`);
+
+    // Testing invalid component names
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz red y)`,                              `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz r y z)`,                              `rgba(0, 0, 0, 0)`);
+    testComputed(`color(from color(xyz 7 -20.5 100) xyz l y z)`,                              `rgba(0, 0, 0, 0)`);
+
+
+    debug('');
+    debug('Spec Examples');
+
     // Example 11.
     testComputed(`rgb(from var(--bg-color) r g b / 80%)`, `rgba(0, 0, 255, 0.8)`);
-    
+
     // Example 12.
     testComputed(`lch(from var(--color) calc(l / 2) c h)`, `lch(23.138971% 67.989716 134.39125)`);
-    
+
     // Example 13.
     testComputed(`rgb(from var(--color) calc(r * .3 + g * .59 + b * .11) calc(r * .3 + g * .59 + b * .11) calc(r * .3 + g * .59 + b * .11))`, `rgb(76, 76, 76)`)
     testComputed(`lch(from var(--color) l 0 h)`, `lch(46.277943% 0 134.39125)`)
@@ -465,7 +603,7 @@
     testComputed(`lab(from var(--mycolor) l a b / 100%)`, `lab(62.751923% 52.45802 -34.117283)`);
     testComputed(`lab(from var(--mycolor) l a b / calc(alpha * 0.8))`, `lab(62.751923% 52.45802 -34.117283 / 0.8)`);
     testComputed(`lab(from var(--mycolor) l a b / calc(alpha - 20%))`, `lab(62.751923% 52.45802 -34.117283 / 0.8)`);
-    
+
     // Example 17.
     testComputed(`lab(from var(--mycolor) l 0 0)`, `lab(62.751923% 0 0)`);
 

Modified: trunk/Source/WebCore/ChangeLog (278363 => 278364)


--- trunk/Source/WebCore/ChangeLog	2021-06-02 17:07:03 UTC (rev 278363)
+++ trunk/Source/WebCore/ChangeLog	2021-06-02 17:38:56 UTC (rev 278364)
@@ -1,3 +1,44 @@
+2021-06-02  Sam Weinig  <wei...@apple.com>
+
+        Add support for "relative color syntax" for color()
+        https://bugs.webkit.org/show_bug.cgi?id=226513
+
+        Reviewed by Darin Adler.
+
+        CSS Color 5 has recently been update to support relative color syntax for
+        the color() function in addition to the existing rgb(), hsl(), hwb(), lab()
+        and lch().
+
+        Took the opertunity to refactor other relative color syntax parsing to share
+        more code between relative and non-relative parsers using a shared function
+        with lambdas to differentiate the component consumers. This was done for all
+        the color types except rgb() and hsl(), which have notable differences in 
+        parsing between the relative and non-relative version.
+
+        * css/parser/CSSPropertyParserHelpers.cpp:
+        (WebCore::CSSPropertyParserHelpers::parseNonRelativeRGBParameters):
+        (WebCore::CSSPropertyParserHelpers::parseRGBParameters):
+        (WebCore::CSSPropertyParserHelpers::colorByNormalizingHSLComponents):
+        (WebCore::CSSPropertyParserHelpers::parseRelativeHSLParameters):
+        (WebCore::CSSPropertyParserHelpers::parseNonRelativeHSLParameters):
+        (WebCore::CSSPropertyParserHelpers::parseHSLParameters):
+        (WebCore::CSSPropertyParserHelpers::parseHWBParameters):
+        (WebCore::CSSPropertyParserHelpers::parseRelativeHWBParameters):
+        (WebCore::CSSPropertyParserHelpers::parseNonRelativeHWBParameters):
+        (WebCore::CSSPropertyParserHelpers::parseLabParameters):
+        (WebCore::CSSPropertyParserHelpers::parseRelativeLabParameters):
+        (WebCore::CSSPropertyParserHelpers::parseNonRelativeLabParameters):
+        (WebCore::CSSPropertyParserHelpers::parseLCHParameters):
+        (WebCore::CSSPropertyParserHelpers::parseRelativeLCHParameters):
+        (WebCore::CSSPropertyParserHelpers::parseNonRelativeLCHParameters):
+        (WebCore::CSSPropertyParserHelpers::parseColorFunctionForRGBTypes):
+        (WebCore::CSSPropertyParserHelpers::parseRelativeColorFunctionForRGBTypes):
+        (WebCore::CSSPropertyParserHelpers::parseColorFunctionForXYZParameters):
+        (WebCore::CSSPropertyParserHelpers::parseRelativeColorFunctionForXYZParameters):
+        (WebCore::CSSPropertyParserHelpers::parseRelativeColorFunctionParameters):
+        (WebCore::CSSPropertyParserHelpers::parseNonRelativeColorFunctionParameters):
+        (WebCore::CSSPropertyParserHelpers::parseColorFunctionParameters):
+
 2021-06-02  Youenn Fablet  <you...@apple.com>
 
         HTMLMediaElement::virtualHasPendingActivity may keep objects alive unnecessarily

Modified: trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp (278363 => 278364)


--- trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp	2021-06-02 17:07:03 UTC (rev 278363)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp	2021-06-02 17:38:56 UTC (rev 278364)
@@ -1499,18 +1499,8 @@
     return SRGBA<uint8_t> { *red, *green, *blue, normalizedAlpha };
 }
 
-enum class RGBFunctionMode { RGB, RGBA };
-
-template<RGBFunctionMode Mode> static Color parseRGBParameters(CSSParserTokenRange& range, const CSSParserContext& context)
+static Color parseNonRelativeRGBParameters(CSSParserTokenRange& args)
 {
-    ASSERT(range.peek().functionId() == CSSValueRgb || range.peek().functionId() == CSSValueRgba);
-    auto args = consumeFunction(range);
-
-    if constexpr (Mode == RGBFunctionMode::RGB) {
-        if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
-            return parseRelativeRGBParameters(args, context);
-    }
-
     struct InitialComponent {
         double value;
         RGBComponentType type;
@@ -1569,6 +1559,32 @@
     return SRGBA<uint8_t> { normalizedRed, normalizedGreen, normalizedBlue, normalizedAlpha };
 }
 
+enum class RGBFunctionMode { RGB, RGBA };
+
+template<RGBFunctionMode Mode> static Color parseRGBParameters(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    ASSERT(range.peek().functionId() == (Mode == RGBFunctionMode::RGB ? CSSValueRgb : CSSValueRgba));
+    auto args = consumeFunction(range);
+
+    if constexpr (Mode == RGBFunctionMode::RGB) {
+        if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
+            return parseRelativeRGBParameters(args, context);
+    }
+    return parseNonRelativeRGBParameters(args);
+}
+
+static Color colorByNormalizingHSLComponents(double hue, double saturation, double lightness, double alpha)
+{
+    auto normalizedHue = normalizeHue(hue);
+    auto normalizedSaturation = std::clamp(saturation, 0.0, 100.0);
+    auto normalizedLightness = std::clamp(lightness, 0.0, 100.0);
+    auto normalizedAlpha = std::clamp(alpha, 0.0, 1.0);
+
+    // NOTE: The explicit conversion to SRGBA<uint8_t> is intentional for performance (no extra allocation for
+    // the extended color) and compatability, forcing serialiazation to use the rgb()/rgba() form.
+    return convertColor<SRGBA<uint8_t>>(HSLA<float> { static_cast<float>(normalizedHue), static_cast<float>(normalizedSaturation), static_cast<float>(normalizedLightness), static_cast<float>(normalizedAlpha) });
+}
+
 static Color parseRelativeHSLParameters(CSSParserTokenRange& args, const CSSParserContext& context)
 {
     ASSERT(args.peek().id() == CSSValueFrom);
@@ -1606,26 +1622,11 @@
     if (!args.atEnd())
         return { };
 
-    auto normalizedHue = normalizeHue(*hue);
-    auto normalizedSaturation = std::clamp(*saturation, 0.0, 100.0);
-    auto normalizedLightness = std::clamp(*lightness, 0.0, 100.0);
-    auto normalizedAlpha = std::clamp(*alpha, 0.0, 1.0);
-
-    return convertColor<SRGBA<uint8_t>>(HSLA<float> { static_cast<float>(normalizedHue), static_cast<float>(normalizedSaturation), static_cast<float>(normalizedLightness), static_cast<float>(normalizedAlpha) });
+    return colorByNormalizingHSLComponents(*hue, *saturation, *lightness, *alpha);
 }
 
-enum class HSLFunctionMode { HSL, HSLA };
-
-template<HSLFunctionMode Mode> static Color parseHSLParameters(CSSParserTokenRange& range, const CSSParserContext& context)
+static Color parseNonRelativeHSLParameters(CSSParserTokenRange& args, const CSSParserContext& context)
 {
-    ASSERT(range.peek().functionId() == CSSValueHsl || range.peek().functionId() == CSSValueHsla);
-    auto args = consumeFunction(range);
-
-    if constexpr (Mode == HSLFunctionMode::HSL) {
-        if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
-            return parseRelativeHSLParameters(args, context);
-    }
-
     auto hue = consumeAngleRawOrNumberRaw(args, context.mode);
     if (!hue)
         return { };
@@ -1650,12 +1651,22 @@
     if (!args.atEnd())
         return { };
 
-    auto normalizedHue = normalizeHue(*hue);
-    auto normalizedSaturation = std::clamp(*saturation, 0.0, 100.0);
-    auto normalizedLightness = std::clamp(*lightness, 0.0, 100.0);
-    auto normalizedAlpha = std::clamp(*alpha, 0.0, 1.0);
+    return colorByNormalizingHSLComponents(*hue, *saturation, *lightness, *alpha);
+}
 
-    return convertColor<SRGBA<uint8_t>>(HSLA<float> { static_cast<float>(normalizedHue), static_cast<float>(normalizedSaturation), static_cast<float>(normalizedLightness), static_cast<float>(normalizedAlpha) });
+enum class HSLFunctionMode { HSL, HSLA };
+
+template<HSLFunctionMode Mode> static Color parseHSLParameters(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    ASSERT(range.peek().functionId() == (Mode == HSLFunctionMode::HSL ? CSSValueHsl : CSSValueHsla));
+    auto args = consumeFunction(range);
+
+    if constexpr (Mode == HSLFunctionMode::HSL) {
+        if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
+            return parseRelativeHSLParameters(args, context);
+    }
+
+    return parseNonRelativeHSLParameters(args, context);
 }
 
 template<typename ComponentType> struct WhitenessBlackness {
@@ -1683,6 +1694,36 @@
     return result;
 }
 
+template<typename ConsumerForHue, typename ConsumerForWhitenessAndBlackness, typename ConsumerForAlpha>
+static Color parseHWBParameters(CSSParserTokenRange& args, ConsumerForHue&& hueConsumer, ConsumerForWhitenessAndBlackness&& whitenessAndBlacknessConsumer, ConsumerForAlpha&& alphaConsumer)
+{
+    auto hue = hueConsumer(args);
+    if (!hue)
+        return { };
+
+    auto whiteness = whitenessAndBlacknessConsumer(args);
+    if (!whiteness)
+        return { };
+
+    auto blackness = whitenessAndBlacknessConsumer(args);
+    if (!blackness)
+        return { };
+
+    auto alpha = alphaConsumer(args);
+    if (!alpha)
+        return { };
+
+    if (!args.atEnd())
+        return { };
+
+    auto normalizedHue = normalizeHue(*hue);
+    auto [normalizedWhitness, normalizedBlackness] = normalizeWhitenessBlackness(*whiteness, *blackness);
+
+    // NOTE: The explicit conversion to SRGBA<uint8_t> is intentional for performance (no extra allocation for
+    // the extended color) and compatability, forcing serialiazation to use the rgb()/rgba() form.
+    return convertColor<SRGBA<uint8_t>>(HWBA<float> { static_cast<float>(normalizedHue), static_cast<float>(normalizedWhitness), static_cast<float>(normalizedBlackness), static_cast<float>(*alpha) });
+}
+
 static Color parseRelativeHWBParameters(CSSParserTokenRange& args, const CSSParserContext& context)
 {
     ASSERT(args.peek().id() == CSSValueFrom);
@@ -1701,29 +1742,20 @@
         { CSSValueAlpha, CSSUnitType::CSS_PERCENTAGE, originColorAsHWB.alpha * 100.0 }
     };
 
-    auto hue = consumeAngleRawOrNumberRawAllowingSymbolTableIdent(args, symbolTable, context.mode);
-    if (!hue)
-        return { };
+    auto hueConsumer = [&symbolTable, &context](auto& args) { return consumeAngleRawOrNumberRawAllowingSymbolTableIdent(args, symbolTable, context.mode); };
+    auto whitenessAndBlacknessConsumer = [&symbolTable](auto& args) { return consumePercentAllowingSymbolTableIdent(args, symbolTable); };
+    auto alphaConsumer = [&symbolTable](auto& args) { return consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable); };
 
-    auto whiteness = consumePercentAllowingSymbolTableIdent(args, symbolTable);
-    if (!whiteness)
-        return { };
+    return parseHWBParameters(args, WTFMove(hueConsumer), WTFMove(whitenessAndBlacknessConsumer), WTFMove(alphaConsumer));
+}
 
-    auto blackness = consumePercentAllowingSymbolTableIdent(args, symbolTable);
-    if (!blackness)
-        return { };
+static Color parseNonRelativeHWBParameters(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+    auto hueConsumer = [&context](auto& args) { return consumeAngleRawOrNumberRaw(args, context.mode); };
+    auto whitenessAndBlacknessConsumer = [](auto& args) { return consumePercentRaw(args); };
+    auto alphaConsumer = [](auto& args) { return consumeOptionalAlpha(args); };
 
-    auto alpha = consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable);
-    if (!alpha)
-        return { };
-
-    if (!args.atEnd())
-        return { };
-
-    auto normalizedHue = normalizeHue(*hue);
-    auto [normalizedWhitness, normalizedBlackness] = normalizeWhitenessBlackness(*whiteness, *blackness);
-
-    return convertColor<SRGBA<uint8_t>>(HWBA<float> { static_cast<float>(normalizedHue), static_cast<float>(normalizedWhitness), static_cast<float>(normalizedBlackness), static_cast<float>(*alpha) });
+    return parseHWBParameters(args, WTFMove(hueConsumer), WTFMove(whitenessAndBlacknessConsumer), WTFMove(alphaConsumer));
 }
 
 static Color parseHWBParameters(CSSParserTokenRange& range, const CSSParserContext& context)
@@ -1737,20 +1769,25 @@
 
     if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
         return parseRelativeHWBParameters(args, context);
+    return parseNonRelativeHWBParameters(args, context);
+}
 
-    auto hue = consumeAngleRawOrNumberRaw(args, context.mode);
-    if (!hue)
+template<typename ConsumerForLightness, typename ConsumerForAB, typename ConsumerForAlpha>
+static Color parseLabParameters(CSSParserTokenRange& args, ConsumerForLightness&& lightnessConsumer, ConsumerForAB&& abConsumer, ConsumerForAlpha&& alphaConsumer)
+{
+    auto lightness = lightnessConsumer(args);
+    if (!lightness)
         return { };
 
-    auto whiteness = consumePercentRaw(args);
-    if (!whiteness)
+    auto aValue = abConsumer(args);
+    if (!aValue)
         return { };
 
-    auto blackness = consumePercentRaw(args);
-    if (!blackness)
+    auto bValue = abConsumer(args);
+    if (!bValue)
         return { };
 
-    auto alpha = consumeOptionalAlpha(args);
+    auto alpha = alphaConsumer(args);
     if (!alpha)
         return { };
 
@@ -1757,10 +1794,9 @@
     if (!args.atEnd())
         return { };
 
-    auto normalizedHue = normalizeHue(*hue);
-    auto [normalizedWhitness, normalizedBlackness] = normalizeWhitenessBlackness(*whiteness, *blackness);
+    auto normalizedLightness = std::max(0.0, *lightness);
 
-    return convertColor<SRGBA<uint8_t>>(HWBA<float> { static_cast<float>(normalizedHue), static_cast<float>(normalizedWhitness), static_cast<float>(normalizedBlackness), static_cast<float>(*alpha) });
+    return Lab<float> { static_cast<float>(normalizedLightness), static_cast<float>(*aValue), static_cast<float>(*bValue), static_cast<float>(*alpha) };
 }
 
 static Color parseRelativeLabParameters(CSSParserTokenRange& args, const CSSParserContext& context)
@@ -1781,28 +1817,20 @@
         { CSSValueAlpha, CSSUnitType::CSS_PERCENTAGE, originColorAsLab.alpha * 100.0 }
     };
 
-    auto lightness = consumePercentAllowingSymbolTableIdent(args, symbolTable);
-    if (!lightness)
-        return { };
+    auto lightnessConsumer = [&symbolTable](auto& args) { return consumePercentAllowingSymbolTableIdent(args, symbolTable); };
+    auto abConsumer = [&symbolTable](auto& args) { return consumeNumberAllowingSymbolTableIdent(args, symbolTable); };
+    auto alphaConsumer = [&symbolTable](auto& args) { return consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable); };
 
-    auto aValue = consumeNumberAllowingSymbolTableIdent(args, symbolTable);
-    if (!aValue)
-        return { };
+    return parseLabParameters(args, WTFMove(lightnessConsumer), WTFMove(abConsumer), WTFMove(alphaConsumer));
+}
 
-    auto bValue = consumeNumberAllowingSymbolTableIdent(args, symbolTable);
-    if (!bValue)
-        return { };
+static Color parseNonRelativeLabParameters(CSSParserTokenRange& args)
+{
+    auto lightnessConsumer = [](auto& args) { return consumePercentRaw(args); };
+    auto abConsumer = [](auto& args) { return consumeNumberRaw(args); };
+    auto alphaConsumer = [](auto& args) { return consumeOptionalAlpha(args); };
 
-    auto alpha = consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable);
-    if (!alpha)
-        return { };
-
-    if (!args.atEnd())
-        return { };
-
-    auto normalizedLightness = std::max(0.0, *lightness);
-
-    return Lab<float> { static_cast<float>(normalizedLightness), static_cast<float>(*aValue), static_cast<float>(*bValue), static_cast<float>(*alpha) };
+    return parseLabParameters(args, WTFMove(lightnessConsumer), WTFMove(abConsumer), WTFMove(alphaConsumer));
 }
 
 static Color parseLabParameters(CSSParserTokenRange& range, const CSSParserContext& context)
@@ -1816,20 +1844,25 @@
 
     if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
         return parseRelativeLabParameters(args, context);
+    return parseNonRelativeLabParameters(args);
+}
 
-    auto lightness = consumePercentRaw(args);
+template<typename ConsumerForLightness, typename ConsumerForChroma, typename ConsumerForHue, typename ConsumerForAlpha>
+static Color parseLCHParameters(CSSParserTokenRange& args, ConsumerForLightness&& lightnessConsumer, ConsumerForChroma&& chromaConsumer, ConsumerForHue&& hueConsumer, ConsumerForAlpha&& alphaConsumer)
+{
+    auto lightness = lightnessConsumer(args);
     if (!lightness)
         return { };
 
-    auto aValue = consumeNumberRaw(args);
-    if (!aValue)
+    auto chroma = chromaConsumer(args);
+    if (!chroma)
         return { };
 
-    auto bValue = consumeNumberRaw(args);
-    if (!bValue)
+    auto hue = hueConsumer(args);
+    if (!hue)
         return { };
 
-    auto alpha = consumeOptionalAlpha(args);
+    auto alpha = alphaConsumer(args);
     if (!alpha)
         return { };
 
@@ -1837,8 +1870,10 @@
         return { };
 
     auto normalizedLightness = std::max(0.0, *lightness);
+    auto normalizedChroma = std::max(0.0, *chroma);
+    auto normalizedHue = normalizeHue(*hue);
 
-    return Lab<float> { static_cast<float>(normalizedLightness), static_cast<float>(*aValue), static_cast<float>(*bValue), static_cast<float>(*alpha) };
+    return LCHA<float> { static_cast<float>(normalizedLightness), static_cast<float>(normalizedChroma), static_cast<float>(normalizedHue), static_cast<float>(*alpha) };
 }
 
 static Color parseRelativeLCHParameters(CSSParserTokenRange& args, const CSSParserContext& context)
@@ -1859,30 +1894,22 @@
         { CSSValueAlpha, CSSUnitType::CSS_PERCENTAGE, originColorAsLCH.alpha * 100.0 }
     };
 
-    auto lightness = consumePercentAllowingSymbolTableIdent(args, symbolTable);
-    if (!lightness)
-        return { };
+    auto lightnessConsumer = [&symbolTable](auto& args) { return consumePercentAllowingSymbolTableIdent(args, symbolTable); };
+    auto chromaConsumer = [&symbolTable](auto& args) { return consumeNumberAllowingSymbolTableIdent(args, symbolTable); };
+    auto hueConsumer = [&symbolTable, &context](auto& args) { return consumeAngleRawOrNumberRawAllowingSymbolTableIdent(args, symbolTable, context.mode); };
+    auto alphaConsumer = [&symbolTable](auto& args) { return consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable); };
 
-    auto chroma = consumeNumberAllowingSymbolTableIdent(args, symbolTable);
-    if (!chroma)
-        return { };
+    return parseLCHParameters(args, WTFMove(lightnessConsumer), WTFMove(chromaConsumer), WTFMove(hueConsumer), WTFMove(alphaConsumer));
+}
 
-    auto hue = consumeAngleRawOrNumberRawAllowingSymbolTableIdent(args, symbolTable, context.mode);
-    if (!hue)
-        return { };
+static Color parseNonRelativeLCHParameters(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+    auto lightnessConsumer = [](auto& args) { return consumePercentRaw(args); };
+    auto chromaConsumer = [](auto& args) { return consumeNumberRaw(args); };
+    auto hueConsumer = [&context](auto& args) { return consumeAngleRawOrNumberRaw(args, context.mode); };
+    auto alphaConsumer = [](auto& args) { return consumeOptionalAlpha(args); };
 
-    auto alpha = consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable);
-    if (!alpha)
-        return { };
-
-    if (!args.atEnd())
-        return { };
-
-    auto normalizedLightness = std::max(0.0, *lightness);
-    auto normalizedChroma = std::max(0.0, *chroma);
-    auto normalizedHue = normalizeHue(*hue);
-
-    return LCHA<float> { static_cast<float>(normalizedLightness), static_cast<float>(normalizedChroma), static_cast<float>(normalizedHue), static_cast<float>(*alpha) };
+    return parseLCHParameters(args, WTFMove(lightnessConsumer), WTFMove(chromaConsumer), WTFMove(hueConsumer), WTFMove(alphaConsumer));
 }
 
 static Color parseLCHParameters(CSSParserTokenRange& range, const CSSParserContext& context)
@@ -1896,31 +1923,57 @@
 
     if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
         return parseRelativeLCHParameters(args, context);
+    return parseNonRelativeLCHParameters(args, context);
+}
 
-    auto lightness = consumePercentRaw(args);
-    if (!lightness)
-        return { };
+template<typename ColorType, typename ConsumerForRGB, typename ConsumerForAlpha>
+static Color parseColorFunctionForRGBTypes(CSSParserTokenRange& args, ConsumerForRGB&& rgbConsumer, ConsumerForAlpha&& alphaConsumer)
+{
+    double channels[3] = { 0, 0, 0 };
+    for (auto& channel : channels) {
+        auto value = rgbConsumer(args);
+        if (!value)
+            break;
+        channel = *value;
+    }
 
-    auto chroma = consumeNumberRaw(args);
-    if (!chroma)
+    auto alpha = alphaConsumer(args);
+    if (!alpha)
         return { };
 
-    auto hue = consumeAngleRawOrNumberRaw(args, context.mode);
-    if (!hue)
+    if (!args.atEnd())
         return { };
 
-    auto alpha = consumeOptionalAlpha(args);
-    if (!alpha)
-        return { };
+    auto normalizedRed = std::clamp(channels[0], 0.0, 1.0);
+    auto normalizedGreen = std::clamp(channels[1], 0.0, 1.0);
+    auto normalizedBlue = std::clamp(channels[2], 0.0, 1.0);
 
-    if (!args.atEnd())
+    return { ColorType { static_cast<float>(normalizedRed), static_cast<float>(normalizedGreen), static_cast<float>(normalizedBlue), static_cast<float>(*alpha) }, Color::Flags::UseColorFunctionSerialization };
+}
+
+template<typename ColorType> static Color parseRelativeColorFunctionForRGBTypes(CSSParserTokenRange& args, Color originColor, const CSSParserContext& context)
+{
+    ASSERT(args.peek().id() == CSSValueA98Rgb || args.peek().id() == CSSValueDisplayP3 || args.peek().id() == CSSValueProphotoRgb || args.peek().id() == CSSValueRec2020 || args.peek().id() == CSSValueSRGB);
+
+    // Support sRGB and Display-P3 regardless of the setting as we have shipped support for them for a while.
+    if (!context.cssColor4 && (args.peek().id() == CSSValueA98Rgb || args.peek().id() == CSSValueProphotoRgb || args.peek().id() == CSSValueRec2020))
         return { };
 
-    auto normalizedLightness = std::max(0.0, *lightness);
-    auto normalizedChroma = std::max(0.0, *chroma);
-    auto normalizedHue = normalizeHue(*hue);
+    consumeIdentRaw(args);
 
-    return LCHA<float> { static_cast<float>(normalizedLightness), static_cast<float>(normalizedChroma), static_cast<float>(normalizedHue), static_cast<float>(*alpha) };
+    auto originColorAsColorType = originColor.toColorTypeLossy<ColorType>();
+
+    CSSCalcSymbolTable symbolTable {
+        { CSSValueR, CSSUnitType::CSS_PERCENTAGE, originColorAsColorType.red * 100.0 },
+        { CSSValueG, CSSUnitType::CSS_PERCENTAGE, originColorAsColorType.green * 100.0 },
+        { CSSValueB, CSSUnitType::CSS_PERCENTAGE, originColorAsColorType.blue * 100.0 },
+        { CSSValueAlpha, CSSUnitType::CSS_PERCENTAGE, originColorAsColorType.alpha * 100.0 }
+    };
+
+    auto consumeRGB = [&symbolTable](auto& args) { return consumeNumberRawOrPercentDividedBy100RawAllowingSymbolTableIdent(args, symbolTable, ValueRange::All); };
+    auto consumeAlpha = [&symbolTable](auto& args) { return consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable); };
+
+    return parseColorFunctionForRGBTypes<ColorType>(args, WTFMove(consumeRGB), WTFMove(consumeAlpha));
 }
 
 template<typename ColorType> static Color parseColorFunctionForRGBTypes(CSSParserTokenRange& args, const CSSParserContext& context)
@@ -1933,22 +1986,34 @@
 
     consumeIdentRaw(args);
 
+    auto consumeRGB = [](auto& args) { return consumeNumberRawOrPercentDividedBy100Raw(args); };
+    auto consumeAlpha = [](auto& args) { return consumeOptionalAlpha(args); };
+
+    return parseColorFunctionForRGBTypes<ColorType>(args, WTFMove(consumeRGB), WTFMove(consumeAlpha));
+}
+
+template<typename ConsumerForXYZ, typename ConsumerForAlpha>
+static Color parseColorFunctionForXYZParameters(CSSParserTokenRange& args, ConsumerForXYZ&& xyzConsumer, ConsumerForAlpha&& alphaConsumer)
+{
     double channels[3] = { 0, 0, 0 };
-    for (int i = 0; i < 3; ++i) {
-        auto value = consumeNumberRawOrPercentDividedBy100Raw(args);
+    for (auto& channel : channels) {
+        auto value = xyzConsumer(args);
         if (!value)
             break;
-        channels[i] = *value;
+        channel = *value;
     }
 
-    auto alpha = consumeOptionalAlpha(args);
+    auto alpha = alphaConsumer(args);
     if (!alpha)
         return { };
 
-    return { ColorType { clampTo<float>(channels[0], 0.0, 1.0), clampTo<float>(channels[1], 0.0, 1.0), clampTo<float>(channels[2], 0.0, 1.0), static_cast<float>(*alpha) }, Color::Flags::UseColorFunctionSerialization };
+    if (!args.atEnd())
+        return { };
+
+    return { XYZA<float, WhitePoint::D50> { static_cast<float>(channels[0]), static_cast<float>(channels[1]), static_cast<float>(channels[2]), static_cast<float>(*alpha) }, Color::Flags::UseColorFunctionSerialization };
 }
 
-static Color parseColorFunctionForXYZParameters(CSSParserTokenRange& args, const CSSParserContext& context)
+static Color parseRelativeColorFunctionForXYZParameters(CSSParserTokenRange& args, Color originColor, const CSSParserContext& context)
 {
     ASSERT(args.peek().id() == CSSValueXyz);
 
@@ -1957,67 +2022,101 @@
 
     consumeIdentRaw(args);
 
-    double channels[3] = { 0, 0, 0 };
-    [&] {
-        auto x = consumeNumberRaw(args);
-        if (!x)
-            return;
-        channels[0] = *x;
+    auto originColorAsXYZ = originColor.toColorTypeLossy<XYZA<float, WhitePoint::D50>>();
 
-        auto y = consumeNumberRaw(args);
-        if (!y)
-            return;
-        channels[1] = *y;
+    CSSCalcSymbolTable symbolTable {
+        { CSSValueX, CSSUnitType::CSS_NUMBER, originColorAsXYZ.x },
+        { CSSValueY, CSSUnitType::CSS_NUMBER, originColorAsXYZ.y },
+        { CSSValueZ, CSSUnitType::CSS_NUMBER, originColorAsXYZ.z },
+        { CSSValueAlpha, CSSUnitType::CSS_PERCENTAGE, originColorAsXYZ.alpha * 100.0 }
+    };
 
-        auto z = consumeNumberRaw(args);
-        if (!z)
-            return;
-        channels[2] = *z;
-    }();
+    auto consumeXYZ = [&symbolTable](auto& args) { return consumeNumberAllowingSymbolTableIdent(args, symbolTable); };
+    auto consumeAlpha = [&symbolTable](auto& args) { return consumeOptionalAlphaAllowingSymbolTableIdent(args, symbolTable); };
 
-    auto alpha = consumeOptionalAlpha(args);
-    if (!alpha)
+    return parseColorFunctionForXYZParameters(args, WTFMove(consumeXYZ), WTFMove(consumeAlpha));
+}
+
+static Color parseColorFunctionForXYZParameters(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+    ASSERT(args.peek().id() == CSSValueXyz);
+
+    if (!context.cssColor4)
         return { };
 
-    return { XYZA<float, WhitePoint::D50> { static_cast<float>(channels[0]), static_cast<float>(channels[1]), static_cast<float>(channels[2]), static_cast<float>(*alpha) }, Color::Flags::UseColorFunctionSerialization };
+    consumeIdentRaw(args);
+
+    auto consumeXYZ = [](auto& args) { return consumeNumberRaw(args); };
+    auto consumeAlpha = [](auto& args) { return consumeOptionalAlpha(args); };
+
+    return parseColorFunctionForXYZParameters(args, WTFMove(consumeXYZ), WTFMove(consumeAlpha));
 }
 
-static Color parseColorFunctionParameters(CSSParserTokenRange& range, const CSSParserContext& context)
+static Color parseRelativeColorFunctionParameters(CSSParserTokenRange& args, const CSSParserContext& context)
 {
-    ASSERT(range.peek().functionId() == CSSValueColor);
-    auto args = consumeFunction(range);
+    ASSERT(args.peek().id() == CSSValueFrom);
+    consumeIdentRaw(args);
 
-    Color color;
+    auto originColor = consumeOriginColor(args, context);
+    if (!originColor.isValid())
+        return { };
+
     switch (args.peek().id()) {
     case CSSValueA98Rgb:
-        color = parseColorFunctionForRGBTypes<A98RGB<float>>(args, context);
-        break;
+        return parseRelativeColorFunctionForRGBTypes<A98RGB<float>>(args, WTFMove(originColor), context);
     case CSSValueDisplayP3:
-        color = parseColorFunctionForRGBTypes<DisplayP3<float>>(args, context);
-        break;
+        return parseRelativeColorFunctionForRGBTypes<DisplayP3<float>>(args, WTFMove(originColor), context);
     case CSSValueProphotoRgb:
-        color = parseColorFunctionForRGBTypes<ProPhotoRGB<float>>(args, context);
-        break;
+        return parseRelativeColorFunctionForRGBTypes<ProPhotoRGB<float>>(args, WTFMove(originColor), context);
     case CSSValueRec2020:
-        color = parseColorFunctionForRGBTypes<Rec2020<float>>(args, context);
-        break;
+        return parseRelativeColorFunctionForRGBTypes<Rec2020<float>>(args, WTFMove(originColor), context);
     case CSSValueSRGB:
-        color = parseColorFunctionForRGBTypes<SRGBA<float>>(args, context);
-        break;
+        return parseRelativeColorFunctionForRGBTypes<SRGBA<float>>(args, WTFMove(originColor), context);
     case CSSValueXyz:
-        color = parseColorFunctionForXYZParameters(args, context);
-        break;
+        return parseRelativeColorFunctionForXYZParameters(args, WTFMove(originColor), context);
     default:
         return { };
     }
 
-    if (!color.isValid())
-        return { };
+    ASSERT_NOT_REACHED();
+    return { };
+}
 
-    if (!args.atEnd())
+static Color parseNonRelativeColorFunctionParameters(CSSParserTokenRange& args, const CSSParserContext& context)
+{
+    switch (args.peek().id()) {
+    case CSSValueA98Rgb:
+        return parseColorFunctionForRGBTypes<A98RGB<float>>(args, context);
+    case CSSValueDisplayP3:
+        return parseColorFunctionForRGBTypes<DisplayP3<float>>(args, context);
+    case CSSValueProphotoRgb:
+        return parseColorFunctionForRGBTypes<ProPhotoRGB<float>>(args, context);
+    case CSSValueRec2020:
+        return parseColorFunctionForRGBTypes<Rec2020<float>>(args, context);
+    case CSSValueSRGB:
+        return parseColorFunctionForRGBTypes<SRGBA<float>>(args, context);
+    case CSSValueXyz:
+        return parseColorFunctionForXYZParameters(args, context);
+    default:
         return { };
+    }
 
-    ASSERT(color.usesColorFunctionSerialization());
+    ASSERT_NOT_REACHED();
+    return { };
+}
+
+static Color parseColorFunctionParameters(CSSParserTokenRange& range, const CSSParserContext& context)
+{
+    ASSERT(range.peek().functionId() == CSSValueColor);
+    auto args = consumeFunction(range);
+
+    auto color = [&] {
+        if (context.relativeColorSyntaxEnabled && args.peek().id() == CSSValueFrom)
+            return parseRelativeColorFunctionParameters(args, context);
+        return parseNonRelativeColorFunctionParameters(args, context);
+    }();
+
+    ASSERT(!color.isValid() || color.usesColorFunctionSerialization());
     return color;
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to