浏览代码

LibWeb/CSS: Serialize CSSColor without relying on RGB

This gives us 140 subtests pass in:
css/css-color/parsing/color-valid-color-function.html
Lucas CHOLLET 7 月之前
父节点
当前提交
5e62f548db

+ 49 - 5
Libraries/LibWeb/CSS/StyleValues/CSSColor.cpp

@@ -34,6 +34,27 @@ CSSColorValue::ColorType color_type_from_string_view(StringView color_space)
     VERIFY_NOT_REACHED();
     VERIFY_NOT_REACHED();
 }
 }
 
 
+StringView string_view_from_color_type(CSSColorValue::ColorType color_type)
+{
+    if (color_type == CSSColorValue::ColorType::A98RGB)
+        return "a98-rgb"sv;
+    if (color_type == CSSColorValue::ColorType::DisplayP3)
+        return "display-p3"sv;
+    if (color_type == CSSColorValue::ColorType::sRGB)
+        return "srgb"sv;
+    if (color_type == CSSColorValue::ColorType::sRGBLinear)
+        return "srgb-linear"sv;
+    if (color_type == CSSColorValue::ColorType::ProPhotoRGB)
+        return "prophoto-rgb"sv;
+    if (color_type == CSSColorValue::ColorType::Rec2020)
+        return "rec2020"sv;
+    if (color_type == CSSColorValue::ColorType::XYZD50)
+        return "xyz-d50"sv;
+    if (color_type == CSSColorValue::ColorType::XYZD65)
+        return "xyz"sv;
+    VERIFY_NOT_REACHED();
+}
+
 }
 }
 
 
 ValueComparingNonnullRefPtr<CSSColor> CSSColor::create(StringView color_space, ValueComparingNonnullRefPtr<CSSStyleValue> c1, ValueComparingNonnullRefPtr<CSSStyleValue> c2, ValueComparingNonnullRefPtr<CSSStyleValue> c3, ValueComparingRefPtr<CSSStyleValue> alpha)
 ValueComparingNonnullRefPtr<CSSColor> CSSColor::create(StringView color_space, ValueComparingNonnullRefPtr<CSSStyleValue> c1, ValueComparingNonnullRefPtr<CSSStyleValue> c2, ValueComparingNonnullRefPtr<CSSStyleValue> c3, ValueComparingRefPtr<CSSStyleValue> alpha)
@@ -59,19 +80,42 @@ bool CSSColor::equals(CSSStyleValue const& other) const
     return m_properties == other_lab_like.m_properties;
     return m_properties == other_lab_like.m_properties;
 }
 }
 
 
+CSSColor::Resolved CSSColor::resolve_properties() const
+{
+    float const c1 = resolve_with_reference_value(m_properties.channels[0], 1).value_or(0);
+    float const c2 = resolve_with_reference_value(m_properties.channels[1], 1).value_or(0);
+    float const c3 = resolve_with_reference_value(m_properties.channels[2], 1).value_or(0);
+    float const alpha_val = resolve_alpha(m_properties.alpha).value_or(1);
+    return { .channels = { c1, c2, c3 }, .alpha = alpha_val };
+}
+
 // https://www.w3.org/TR/css-color-4/#serializing-color-function-values
 // https://www.w3.org/TR/css-color-4/#serializing-color-function-values
 String CSSColor::to_string(SerializationMode) const
 String CSSColor::to_string(SerializationMode) const
 {
 {
     // FIXME: Do this properly, taking unresolved calculated values into account.
     // FIXME: Do this properly, taking unresolved calculated values into account.
-    return serialize_a_srgb_value(to_color({}));
+    auto resolved = resolve_properties();
+    if (resolved.alpha == 1) {
+        return MUST(String::formatted("color({} {} {} {})",
+            string_view_from_color_type(m_color_type),
+            resolved.channels[0],
+            resolved.channels[1],
+            resolved.channels[2]));
+    }
+
+    return MUST(String::formatted("color({} {} {} {} / {})",
+        string_view_from_color_type(m_color_type),
+        resolved.channels[0],
+        resolved.channels[1],
+        resolved.channels[2],
+        resolved.alpha));
 }
 }
 
 
 Color CSSColor::to_color(Optional<Layout::NodeWithStyle const&>) const
 Color CSSColor::to_color(Optional<Layout::NodeWithStyle const&>) const
 {
 {
-    auto const c1 = resolve_with_reference_value(m_properties.channels[0], 1).value_or(0);
-    auto const c2 = resolve_with_reference_value(m_properties.channels[1], 1).value_or(0);
-    auto const c3 = resolve_with_reference_value(m_properties.channels[2], 1).value_or(0);
-    auto const alpha_val = resolve_alpha(m_properties.alpha).value_or(1);
+    auto [channels, alpha_val] = resolve_properties();
+    auto c1 = channels[0];
+    auto c2 = channels[1];
+    auto c3 = channels[2];
 
 
     if (color_type() == ColorType::A98RGB)
     if (color_type() == ColorType::A98RGB)
         return Color::from_a98rgb(c1, c2, c3, alpha_val);
         return Color::from_a98rgb(c1, c2, c3, alpha_val);

+ 10 - 1
Libraries/LibWeb/CSS/StyleValues/CSSColor.h

@@ -34,7 +34,16 @@ private:
         Array<ValueComparingNonnullRefPtr<CSSStyleValue>, 3> channels;
         Array<ValueComparingNonnullRefPtr<CSSStyleValue>, 3> channels;
         ValueComparingNonnullRefPtr<CSSStyleValue> alpha;
         ValueComparingNonnullRefPtr<CSSStyleValue> alpha;
         bool operator==(Properties const&) const = default;
         bool operator==(Properties const&) const = default;
-    } m_properties;
+    };
+
+    struct Resolved {
+        Array<float, 3> channels {};
+        float alpha {};
+    };
+
+    Resolved resolve_properties() const;
+
+    Properties m_properties;
 };
 };
 
 
 } // Web::CSS
 } // Web::CSS

+ 0 - 1
Libraries/LibWeb/CSS/StyleValues/CSSColorValue.h

@@ -53,7 +53,6 @@ protected:
     static Optional<double> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
     static Optional<double> resolve_with_reference_value(CSSStyleValue const&, float one_hundred_percent_value);
     static Optional<double> resolve_alpha(CSSStyleValue const&);
     static Optional<double> resolve_alpha(CSSStyleValue const&);
 
 
-private:
     ColorType m_color_type;
     ColorType m_color_type;
 };
 };
 
 

+ 312 - 0
Tests/LibWeb/Text/expected/wpt-import/css/css-color/parsing/color-valid-color-function.txt

@@ -0,0 +1,312 @@
+Harness status: OK
+
+Found 306 tests
+
+140 Pass
+166 Fail
+Pass	e.style['color'] = "color(srgb 0% 0% 0%)" should set the property value
+Pass	e.style['color'] = "color(srgb 10% 10% 10%)" should set the property value
+Pass	e.style['color'] = "color(srgb .2 .2 25%)" should set the property value
+Pass	e.style['color'] = "color(srgb 0 0 0 / 1)" should set the property value
+Pass	e.style['color'] = "color(srgb 0% 0 0 / 0.5)" should set the property value
+Pass	e.style['color'] = "color(srgb 20% 0 10/0.5)" should set the property value
+Pass	e.style['color'] = "color(srgb 20% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(srgb 400% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(srgb 50% -160 160)" should set the property value
+Pass	e.style['color'] = "color(srgb 50% -200 200)" should set the property value
+Pass	e.style['color'] = "color(srgb 0 0 0 / -10%)" should set the property value
+Pass	e.style['color'] = "color(srgb 0 0 0 / 110%)" should set the property value
+Pass	e.style['color'] = "color(srgb 0 0 0 / 300%)" should set the property value
+Pass	e.style['color'] = "color(srgb 200 200 200)" should set the property value
+Pass	e.style['color'] = "color(srgb 200 200 200 / 200)" should set the property value
+Pass	e.style['color'] = "color(srgb -200 -200 -200)" should set the property value
+Pass	e.style['color'] = "color(srgb -200 -200 -200 / -200)" should set the property value
+Pass	e.style['color'] = "color(srgb 200% 200% 200%)" should set the property value
+Pass	e.style['color'] = "color(srgb 200% 200% 200% / 200%)" should set the property value
+Pass	e.style['color'] = "color(srgb -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(srgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(srgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(srgb calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(srgb none none none / none)" should set the property value
+Fail	e.style['color'] = "color(srgb none none none)" should set the property value
+Fail	e.style['color'] = "color(srgb 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(srgb none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(srgb 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(srgb 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(srgb 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(srgb calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(srgb calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(srgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(srgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 0% 0% 0%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 10% 10% 10%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear .2 .2 25%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 0 0 0 / 1)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 0% 0 0 / 0.5)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 20% 0 10/0.5)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 20% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 400% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 50% -160 160)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 50% -200 200)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 0 0 0 / -10%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 0 0 0 / 110%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 0 0 0 / 300%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 200 200 200)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 200 200 200 / 200)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear -200 -200 -200)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear -200 -200 -200 / -200)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 200% 200% 200%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear 200% 200% 200% / 200%)" should set the property value
+Pass	e.style['color'] = "color(srgb-linear -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(srgb-linear calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(srgb-linear calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear none none none / none)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear none none none)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(srgb-linear 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 0% 0% 0%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 10% 10% 10%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb .2 .2 25%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 0 0 0 / 1)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 0% 0 0 / 0.5)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 20% 0 10/0.5)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 20% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 400% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 50% -160 160)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 50% -200 200)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 0 0 0 / -10%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 0 0 0 / 110%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 0 0 0 / 300%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 200 200 200)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 200 200 200 / 200)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb -200 -200 -200)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb -200 -200 -200 / -200)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 200% 200% 200%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb 200% 200% 200% / 200%)" should set the property value
+Pass	e.style['color'] = "color(a98-rgb -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(a98-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(a98-rgb calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb none none none / none)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb none none none)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(a98-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Pass	e.style['color'] = "color(rec2020 0% 0% 0%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 10% 10% 10%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 .2 .2 25%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 0 0 0 / 1)" should set the property value
+Pass	e.style['color'] = "color(rec2020 0% 0 0 / 0.5)" should set the property value
+Pass	e.style['color'] = "color(rec2020 20% 0 10/0.5)" should set the property value
+Pass	e.style['color'] = "color(rec2020 20% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 400% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 50% -160 160)" should set the property value
+Pass	e.style['color'] = "color(rec2020 50% -200 200)" should set the property value
+Pass	e.style['color'] = "color(rec2020 0 0 0 / -10%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 0 0 0 / 110%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 0 0 0 / 300%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 200 200 200)" should set the property value
+Pass	e.style['color'] = "color(rec2020 200 200 200 / 200)" should set the property value
+Pass	e.style['color'] = "color(rec2020 -200 -200 -200)" should set the property value
+Pass	e.style['color'] = "color(rec2020 -200 -200 -200 / -200)" should set the property value
+Pass	e.style['color'] = "color(rec2020 200% 200% 200%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 200% 200% 200% / 200%)" should set the property value
+Pass	e.style['color'] = "color(rec2020 -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(rec2020 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(rec2020 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(rec2020 calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(rec2020 none none none / none)" should set the property value
+Fail	e.style['color'] = "color(rec2020 none none none)" should set the property value
+Fail	e.style['color'] = "color(rec2020 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(rec2020 none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(rec2020 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(rec2020 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(rec2020 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(rec2020 calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(rec2020 calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(rec2020 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(rec2020 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 0% 0% 0%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 10% 10% 10%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb .2 .2 25%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 0 0 0 / 1)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 0% 0 0 / 0.5)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 20% 0 10/0.5)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 20% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 400% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 50% -160 160)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 50% -200 200)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 0 0 0 / -10%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 0 0 0 / 110%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 0 0 0 / 300%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 200 200 200)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 200 200 200 / 200)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb -200 -200 -200)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb -200 -200 -200 / -200)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 200% 200% 200%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb 200% 200% 200% / 200%)" should set the property value
+Pass	e.style['color'] = "color(prophoto-rgb -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb none none none / none)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb none none none)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(prophoto-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Pass	e.style['color'] = "color(display-p3 0% 0% 0%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 10% 10% 10%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 .2 .2 25%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 0 0 0 / 1)" should set the property value
+Pass	e.style['color'] = "color(display-p3 0% 0 0 / 0.5)" should set the property value
+Pass	e.style['color'] = "color(display-p3 20% 0 10/0.5)" should set the property value
+Pass	e.style['color'] = "color(display-p3 20% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 400% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 50% -160 160)" should set the property value
+Pass	e.style['color'] = "color(display-p3 50% -200 200)" should set the property value
+Pass	e.style['color'] = "color(display-p3 0 0 0 / -10%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 0 0 0 / 110%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 0 0 0 / 300%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 200 200 200)" should set the property value
+Pass	e.style['color'] = "color(display-p3 200 200 200 / 200)" should set the property value
+Pass	e.style['color'] = "color(display-p3 -200 -200 -200)" should set the property value
+Pass	e.style['color'] = "color(display-p3 -200 -200 -200 / -200)" should set the property value
+Pass	e.style['color'] = "color(display-p3 200% 200% 200%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 200% 200% 200% / 200%)" should set the property value
+Pass	e.style['color'] = "color(display-p3 -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(display-p3 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(display-p3 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(display-p3 calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(display-p3 none none none / none)" should set the property value
+Fail	e.style['color'] = "color(display-p3 none none none)" should set the property value
+Fail	e.style['color'] = "color(display-p3 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(display-p3 none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(display-p3 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(display-p3 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(display-p3 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(display-p3 calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(display-p3 calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(display-p3 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(display-p3 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Fail	e.style['color'] = "color(xyz 0% 0% 0%)" should set the property value
+Fail	e.style['color'] = "color(xyz 10% 10% 10%)" should set the property value
+Fail	e.style['color'] = "color(xyz .2 .2 25%)" should set the property value
+Fail	e.style['color'] = "color(xyz 0 0 0 / 1)" should set the property value
+Fail	e.style['color'] = "color(xyz 0% 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz 20% 0 10/0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz 20% 0 10/50%)" should set the property value
+Fail	e.style['color'] = "color(xyz 400% 0 10/50%)" should set the property value
+Fail	e.style['color'] = "color(xyz 50% -160 160)" should set the property value
+Fail	e.style['color'] = "color(xyz 50% -200 200)" should set the property value
+Fail	e.style['color'] = "color(xyz 0 0 0 / -10%)" should set the property value
+Fail	e.style['color'] = "color(xyz 0 0 0 / 110%)" should set the property value
+Fail	e.style['color'] = "color(xyz 0 0 0 / 300%)" should set the property value
+Fail	e.style['color'] = "color(xyz 200 200 200)" should set the property value
+Fail	e.style['color'] = "color(xyz 200 200 200 / 200)" should set the property value
+Fail	e.style['color'] = "color(xyz -200 -200 -200)" should set the property value
+Fail	e.style['color'] = "color(xyz -200 -200 -200 / -200)" should set the property value
+Fail	e.style['color'] = "color(xyz 200% 200% 200%)" should set the property value
+Fail	e.style['color'] = "color(xyz 200% 200% 200% / 200%)" should set the property value
+Fail	e.style['color'] = "color(xyz -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(xyz calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(xyz calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(xyz calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz none none none / none)" should set the property value
+Fail	e.style['color'] = "color(xyz none none none)" should set the property value
+Fail	e.style['color'] = "color(xyz 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(xyz none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(xyz 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(xyz 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(xyz calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(xyz calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(xyz calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 0% 0% 0%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 10% 10% 10%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 .2 .2 25%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 0 0 0 / 1)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 0% 0 0 / 0.5)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 20% 0 10/0.5)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 20% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 400% 0 10/50%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 50% -160 160)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 50% -200 200)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 0 0 0 / -10%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 0 0 0 / 110%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 0 0 0 / 300%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 200 200 200)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 200 200 200 / 200)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 -200 -200 -200)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 -200 -200 -200 / -200)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 200% 200% 200%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 200% 200% 200% / 200%)" should set the property value
+Pass	e.style['color'] = "color(xyz-d50 -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 none none none / none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 none none none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d50 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0% 0% 0%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 10% 10% 10%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 .2 .2 25%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0 0 0 / 1)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0% 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 20% 0 10/0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 20% 0 10/50%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 400% 0 10/50%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 50% -160 160)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 50% -200 200)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0 0 0 / -10%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0 0 0 / 110%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0 0 0 / 300%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 200 200 200)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 200 200 200 / 200)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 -200 -200 -200)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 -200 -200 -200 / -200)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 200% 200% 200%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 200% 200% 200% / 200%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 -200% -200% -200% / -200%)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 calc(50%) 50% 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 none none none / none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 none none none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 10% none none / none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 none none none / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0 0 0 / none)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0 calc(infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0 calc(-infinity) 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 calc(NaN) 0 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 calc(0 / 0) 0 0)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)" should set the property value
+Fail	e.style['color'] = "color(xyz-d65 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))" should set the property value

+ 59 - 0
Tests/LibWeb/Text/input/wpt-import/css/css-color/parsing/color-valid-color-function.html

@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Color Level 4: Parsing and serialization of colors using valid color() function syntax</title>
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#color-function">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#resolving-color-function-values">
+<link rel="help" href="https://drafts.csswg.org/css-color-4/#serializing-color-function-values">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+for (const colorSpace of [ "srgb", "srgb-linear", "a98-rgb", "rec2020", "prophoto-rgb", "display-p3", "xyz", "xyz-d50", "xyz-d65" ]) {
+    const resultColorSpace = colorSpace == "xyz" ? "xyz-d65" : colorSpace;
+
+    test_valid_value("color", `color(${colorSpace} 0% 0% 0%)`, `color(${resultColorSpace} 0 0 0)`);
+    test_valid_value("color", `color(${colorSpace} 10% 10% 10%)`, `color(${resultColorSpace} 0.1 0.1 0.1)`);
+    test_valid_value("color", `color(${colorSpace} .2 .2 25%)`, `color(${resultColorSpace} 0.2 0.2 0.25)`);
+    test_valid_value("color", `color(${colorSpace} 0 0 0 / 1)`, `color(${resultColorSpace} 0 0 0)`);
+    test_valid_value("color", `color(${colorSpace} 0% 0 0 / 0.5)`, `color(${resultColorSpace} 0 0 0 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 20% 0 10/0.5)`, `color(${resultColorSpace} 0.2 0 10 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 20% 0 10/50%)`, `color(${resultColorSpace} 0.2 0 10 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 400% 0 10/50%)`, `color(${resultColorSpace} 4 0 10 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 50% -160 160)`, `color(${resultColorSpace} 0.5 -160 160)`);
+    test_valid_value("color", `color(${colorSpace} 50% -200 200)`, `color(${resultColorSpace} 0.5 -200 200)`);
+    test_valid_value("color", `color(${colorSpace} 0 0 0 / -10%)`, `color(${resultColorSpace} 0 0 0 / 0)`);
+    test_valid_value("color", `color(${colorSpace} 0 0 0 / 110%)`, `color(${resultColorSpace} 0 0 0)`);
+    test_valid_value("color", `color(${colorSpace} 0 0 0 / 300%)`, `color(${resultColorSpace} 0 0 0)`);
+    test_valid_value("color", `color(${colorSpace} 200 200 200)`, `color(${resultColorSpace} 200 200 200)`);
+    test_valid_value("color", `color(${colorSpace} 200 200 200 / 200)`, `color(${resultColorSpace} 200 200 200)`);
+    test_valid_value("color", `color(${colorSpace} -200 -200 -200)`, `color(${resultColorSpace} -200 -200 -200)`);
+    test_valid_value("color", `color(${colorSpace} -200 -200 -200 / -200)`, `color(${resultColorSpace} -200 -200 -200 / 0)`);
+    test_valid_value("color", `color(${colorSpace} 200% 200% 200%)`, `color(${resultColorSpace} 2 2 2)`);
+    test_valid_value("color", `color(${colorSpace} 200% 200% 200% / 200%)`, `color(${resultColorSpace} 2 2 2)`);
+    test_valid_value("color", `color(${colorSpace} -200% -200% -200% / -200%)`, `color(${resultColorSpace} -2 -2 -2 / 0)`);
+    test_valid_value("color", `color(${colorSpace} calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))`, `color(${resultColorSpace} calc(1.5) calc(-0.5) calc(0.5) / calc(0.5))`);
+    test_valid_value("color", `color(${colorSpace} calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))`, `color(${resultColorSpace} calc(150%) calc(-50%) calc(50%) / calc(-150%))`);
+    test_valid_value("color", `color(${colorSpace} calc(50%) 50% 0.5)`, `color(${resultColorSpace} calc(50%) 0.5 0.5)`);
+
+    test_valid_value("color", `color(${colorSpace} none none none / none)`, `color(${resultColorSpace} none none none / none)`);
+    test_valid_value("color", `color(${colorSpace} none none none)`, `color(${resultColorSpace} none none none)`);
+    test_valid_value("color", `color(${colorSpace} 10% none none / none)`, `color(${resultColorSpace} 0.1 none none / none)`);
+    test_valid_value("color", `color(${colorSpace} none none none / 0.5)`, `color(${resultColorSpace} none none none / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 0 0 0 / none)`, `color(${resultColorSpace} 0 0 0 / none)`);
+
+    test_valid_value("color", `color(${colorSpace} 0 calc(infinity) 0)`, `color(${resultColorSpace} 0 calc(infinity) 0)`);
+    test_valid_value("color", `color(${colorSpace} 0 calc(-infinity) 0)`, `color(${resultColorSpace} 0 calc(-infinity) 0)`);
+    test_valid_value("color", `color(${colorSpace} calc(NaN) 0 0)`, `color(${resultColorSpace} calc(NaN) 0 0)`);
+    test_valid_value("color", `color(${colorSpace} calc(0 / 0) 0 0)`, `color(${resultColorSpace} calc(NaN) 0 0)`);
+
+    // calc(50% + (sign(1em - 10px) * 10%)) cannot be evaluated eagerly because font relative units are not yet known at parse time.
+    test_valid_value("color", `color(${colorSpace} calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)`, `color(${resultColorSpace} calc(50% + (10% * sign(1em - 10px))) 0 0 / 0.5)`);
+    test_valid_value("color", `color(${colorSpace} 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))`, `color(${resultColorSpace} 0.5 0 0 / calc(50% + (10% * sign(1em - 10px))))`);
+}
+</script>
+</body>
+</html>