From 6f5b107fccdaa93b4508441754b10a00f40ecaa8 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Sun, 20 Apr 2025 22:55:04 +0100 Subject: [PATCH] LibWeb: Resolve absolute `calc()` values in color functions Currently, `calc()` values with relative units are not handled correctly and will output an error to the console. --- .../StyleValues/ColorFunctionStyleValue.cpp | 20 ++++++- .../parsing/color-computed-color-function.txt | 52 +++++++++---------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp index 02dbea45a75..58452947a22 100644 --- a/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp @@ -7,6 +7,7 @@ #include "ColorFunctionStyleValue.h" #include #include +#include #include #include @@ -93,9 +94,26 @@ ColorFunctionStyleValue::Resolved ColorFunctionStyleValue::resolve_properties() // https://www.w3.org/TR/css-color-4/#serializing-color-function-values String ColorFunctionStyleValue::to_string(SerializationMode mode) const { - auto convert_percentage = [](ValueComparingNonnullRefPtr const& value) -> RemoveReference { + auto convert_percentage = [&](ValueComparingNonnullRefPtr const& value) -> RemoveReference { if (value->is_percentage()) return NumberStyleValue::create(value->as_percentage().value() / 100); + if (mode == SerializationMode::ResolvedValue && value->is_calculated()) { + // FIXME: Figure out how to get the proper calculation resolution context here + CalculationResolutionContext context {}; + auto const& calculated = value->as_calculated(); + if (calculated.resolves_to_percentage()) { + if (auto resolved_percentage = calculated.resolve_percentage(context); resolved_percentage.has_value()) { + auto resolved_number = resolved_percentage->value() / 100; + if (!isfinite(resolved_number)) + resolved_number = 0; + return NumberStyleValue::create(resolved_number); + } + } else if (calculated.resolves_to_number()) { + if (auto resolved_number = calculated.resolve_number(context); resolved_number.has_value()) + return NumberStyleValue::create(*resolved_number); + } + } + return value; }; diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-color/parsing/color-computed-color-function.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-color/parsing/color-computed-color-function.txt index e15966406c2..afb6bd2300e 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-color/parsing/color-computed-color-function.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-color/parsing/color-computed-color-function.txt @@ -2,8 +2,8 @@ Harness status: OK Found 421 tests -377 Pass -44 Fail +401 Pass +20 Fail Pass Property color value 'color(srgb 0% 0% 0%)' Pass Property color value 'color(srgb 10% 10% 10%)' Pass Property color value 'color(srgb .2 .2 25%)' @@ -25,14 +25,14 @@ Pass Property color value 'color(srgb 200% 200% 200%)' Pass Property color value 'color(srgb 200% 200% 200% / 200%)' Pass Property color value 'color(srgb -200% -200% -200% / -200%)' Pass Property color value 'color(srgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))' -Fail Property color value 'color(srgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' +Pass Property color value 'color(srgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' Pass Property color value 'color(srgb none none none / none)' Pass Property color value 'color(srgb none none none)' Pass Property color value 'color(srgb 10% none none / none)' Pass Property color value 'color(srgb none none none / 0.5)' Pass Property color value 'color(srgb 0 0 0 / none)' -Fail Property color value 'color(srgb calc(NaN) 0 0)' -Fail Property color value 'color(srgb calc(0 / 0) 0 0)' +Pass Property color value 'color(srgb calc(NaN) 0 0)' +Pass Property color value 'color(srgb calc(0 / 0) 0 0)' Fail Property color value 'color(srgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)' Fail Property color value 'color(srgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))' Pass Property color value 'color(srgb-linear 0% 0% 0%)' @@ -56,14 +56,14 @@ Pass Property color value 'color(srgb-linear 200% 200% 200%)' Pass Property color value 'color(srgb-linear 200% 200% 200% / 200%)' Pass Property color value 'color(srgb-linear -200% -200% -200% / -200%)' Pass Property color value 'color(srgb-linear calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))' -Fail Property color value 'color(srgb-linear calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' +Pass Property color value 'color(srgb-linear calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' Pass Property color value 'color(srgb-linear none none none / none)' Pass Property color value 'color(srgb-linear none none none)' Pass Property color value 'color(srgb-linear 10% none none / none)' Pass Property color value 'color(srgb-linear none none none / 0.5)' Pass Property color value 'color(srgb-linear 0 0 0 / none)' -Fail Property color value 'color(srgb-linear calc(NaN) 0 0)' -Fail Property color value 'color(srgb-linear calc(0 / 0) 0 0)' +Pass Property color value 'color(srgb-linear calc(NaN) 0 0)' +Pass Property color value 'color(srgb-linear calc(0 / 0) 0 0)' Fail Property color value 'color(srgb-linear calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)' Fail Property color value 'color(srgb-linear 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))' Pass Property color value 'color(a98-rgb 0% 0% 0%)' @@ -87,14 +87,14 @@ Pass Property color value 'color(a98-rgb 200% 200% 200%)' Pass Property color value 'color(a98-rgb 200% 200% 200% / 200%)' Pass Property color value 'color(a98-rgb -200% -200% -200% / -200%)' Pass Property color value 'color(a98-rgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))' -Fail Property color value 'color(a98-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' +Pass Property color value 'color(a98-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' Pass Property color value 'color(a98-rgb none none none / none)' Pass Property color value 'color(a98-rgb none none none)' Pass Property color value 'color(a98-rgb 10% none none / none)' Pass Property color value 'color(a98-rgb none none none / 0.5)' Pass Property color value 'color(a98-rgb 0 0 0 / none)' -Fail Property color value 'color(a98-rgb calc(NaN) 0 0)' -Fail Property color value 'color(a98-rgb calc(0 / 0) 0 0)' +Pass Property color value 'color(a98-rgb calc(NaN) 0 0)' +Pass Property color value 'color(a98-rgb calc(0 / 0) 0 0)' Fail Property color value 'color(a98-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)' Fail Property color value 'color(a98-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))' Pass Property color value 'color(rec2020 0% 0% 0%)' @@ -118,14 +118,14 @@ Pass Property color value 'color(rec2020 200% 200% 200%)' Pass Property color value 'color(rec2020 200% 200% 200% / 200%)' Pass Property color value 'color(rec2020 -200% -200% -200% / -200%)' Pass Property color value 'color(rec2020 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))' -Fail Property color value 'color(rec2020 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' +Pass Property color value 'color(rec2020 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' Pass Property color value 'color(rec2020 none none none / none)' Pass Property color value 'color(rec2020 none none none)' Pass Property color value 'color(rec2020 10% none none / none)' Pass Property color value 'color(rec2020 none none none / 0.5)' Pass Property color value 'color(rec2020 0 0 0 / none)' -Fail Property color value 'color(rec2020 calc(NaN) 0 0)' -Fail Property color value 'color(rec2020 calc(0 / 0) 0 0)' +Pass Property color value 'color(rec2020 calc(NaN) 0 0)' +Pass Property color value 'color(rec2020 calc(0 / 0) 0 0)' Fail Property color value 'color(rec2020 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)' Fail Property color value 'color(rec2020 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))' Pass Property color value 'color(prophoto-rgb 0% 0% 0%)' @@ -149,14 +149,14 @@ Pass Property color value 'color(prophoto-rgb 200% 200% 200%)' Pass Property color value 'color(prophoto-rgb 200% 200% 200% / 200%)' Pass Property color value 'color(prophoto-rgb -200% -200% -200% / -200%)' Pass Property color value 'color(prophoto-rgb calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))' -Fail Property color value 'color(prophoto-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' +Pass Property color value 'color(prophoto-rgb calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' Pass Property color value 'color(prophoto-rgb none none none / none)' Pass Property color value 'color(prophoto-rgb none none none)' Pass Property color value 'color(prophoto-rgb 10% none none / none)' Pass Property color value 'color(prophoto-rgb none none none / 0.5)' Pass Property color value 'color(prophoto-rgb 0 0 0 / none)' -Fail Property color value 'color(prophoto-rgb calc(NaN) 0 0)' -Fail Property color value 'color(prophoto-rgb calc(0 / 0) 0 0)' +Pass Property color value 'color(prophoto-rgb calc(NaN) 0 0)' +Pass Property color value 'color(prophoto-rgb calc(0 / 0) 0 0)' Fail Property color value 'color(prophoto-rgb calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)' Fail Property color value 'color(prophoto-rgb 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))' Pass Property color value 'color(display-p3 0% 0% 0%)' @@ -180,14 +180,14 @@ Pass Property color value 'color(display-p3 200% 200% 200%)' Pass Property color value 'color(display-p3 200% 200% 200% / 200%)' Pass Property color value 'color(display-p3 -200% -200% -200% / -200%)' Pass Property color value 'color(display-p3 calc(0.5 + 1) calc(0.5 - 1) calc(0.5) / calc(-0.5 + 1))' -Fail Property color value 'color(display-p3 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' +Pass Property color value 'color(display-p3 calc(50% * 3) calc(-150% / 3) calc(50%) / calc(-50% * 3))' Pass Property color value 'color(display-p3 none none none / none)' Pass Property color value 'color(display-p3 none none none)' Pass Property color value 'color(display-p3 10% none none / none)' Pass Property color value 'color(display-p3 none none none / 0.5)' Pass Property color value 'color(display-p3 0 0 0 / none)' -Fail Property color value 'color(display-p3 calc(NaN) 0 0)' -Fail Property color value 'color(display-p3 calc(0 / 0) 0 0)' +Pass Property color value 'color(display-p3 calc(NaN) 0 0)' +Pass Property color value 'color(display-p3 calc(0 / 0) 0 0)' Fail Property color value 'color(display-p3 calc(50% + (sign(1em - 10px) * 10%)) 0 0 / 0.5)' Fail Property color value 'color(display-p3 0.5 0 0 / calc(50% + (sign(1em - 10px) * 10%)))' Pass Property color value 'color(xyz 0 0 0)' @@ -210,8 +210,8 @@ Pass Property color value 'color(xyz none none none)' Pass Property color value 'color(xyz 0.2 none none / none)' Pass Property color value 'color(xyz none none none / 0.5)' Pass Property color value 'color(xyz 0 0 0 / none)' -Fail Property color value 'color(xyz calc(NaN) 0 0)' -Fail Property color value 'color(xyz calc(0 / 0) 0 0)' +Pass Property color value 'color(xyz calc(NaN) 0 0)' +Pass Property color value 'color(xyz calc(0 / 0) 0 0)' Fail Property color value 'color(xyz calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)' Fail Property color value 'color(xyz 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))' Pass Property color value 'color(xyz-d50 0 0 0)' @@ -234,8 +234,8 @@ Pass Property color value 'color(xyz-d50 none none none)' Pass Property color value 'color(xyz-d50 0.2 none none / none)' Pass Property color value 'color(xyz-d50 none none none / 0.5)' Pass Property color value 'color(xyz-d50 0 0 0 / none)' -Fail Property color value 'color(xyz-d50 calc(NaN) 0 0)' -Fail Property color value 'color(xyz-d50 calc(0 / 0) 0 0)' +Pass Property color value 'color(xyz-d50 calc(NaN) 0 0)' +Pass Property color value 'color(xyz-d50 calc(0 / 0) 0 0)' Fail Property color value 'color(xyz-d50 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)' Fail Property color value 'color(xyz-d50 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))' Pass Property color value 'color(xyz-d65 0 0 0)' @@ -258,8 +258,8 @@ Pass Property color value 'color(xyz-d65 none none none)' Pass Property color value 'color(xyz-d65 0.2 none none / none)' Pass Property color value 'color(xyz-d65 none none none / 0.5)' Pass Property color value 'color(xyz-d65 0 0 0 / none)' -Fail Property color value 'color(xyz-d65 calc(NaN) 0 0)' -Fail Property color value 'color(xyz-d65 calc(0 / 0) 0 0)' +Pass Property color value 'color(xyz-d65 calc(NaN) 0 0)' +Pass Property color value 'color(xyz-d65 calc(0 / 0) 0 0)' Fail Property color value 'color(xyz-d65 calc(0.5 + (sign(1em - 10px) * 0.1)) 0 0 / 0.5)' Fail Property color value 'color(xyz-d65 0.5 0 0 / calc(0.5 + (sign(1em - 10px) * 0.1)))' Pass Property color value 'color(srgb 1.00 0.50 0.200)' [sRGB all numbers]