LibWeb: Properly clamp interpolated opacity values

Opacity values are unique in that the range which calculated and
interpolated values should be clamped to [0,1] is different from the
range of allowed values [-∞,∞].

This fixes 28 WPT tests that were regressed in #6112
This commit is contained in:
Callum Law
2025-09-09 22:03:23 +12:00
committed by Sam Atkins
parent 517e3f5f1d
commit 43dd0f2dda
Notes: github-actions[bot] 2025-09-24 11:02:58 +00:00
4 changed files with 251 additions and 21 deletions

View File

@@ -891,35 +891,44 @@ AcceptedTypeRangeMap property_accepted_type_ranges(PropertyID property_id)
StringBuilder ranges_builder;
for (auto& type : valid_types.values()) {
VERIFY(type.is_string());
// Opacity values are unique in that the range which calculated and interpolated values should be clamped
// to [0,1] is different from the range of allowed values [-∞,∞]. To handle this we set the allowed range
// in Properties.json to [-∞,∞] but overwrite it to [0,1] here.
// FIXME: This is confusing as property_accepts_{number,percentage}() has a different range from this
// despite the names sounding similar.
if (first_is_one_of(name, "opacity"sv, "fill-opacity"sv, "flood-opacity"sv, "stop-opacity"sv, "stroke-opacity"sv)) {
ranges_builder.append("{ ValueType::Number, { 0, 1 } }, { ValueType::Percentage, { 0, 100 } }"sv);
} else {
for (auto& type : valid_types.values()) {
VERIFY(type.is_string());
Vector<String> type_parts = MUST(type.as_string().split(' '));
Vector<String> type_parts = MUST(type.as_string().split(' '));
if (type_parts.size() < 2)
continue;
if (type_parts.size() < 2)
continue;
auto type_name = type_parts.first();
auto type_name = type_parts.first();
if (type_name == "custom-ident")
continue;
if (type_name == "custom-ident")
continue;
// Drop the brackets on the range e.g. "[-∞,∞]" -> "-∞,∞"
auto type_range = MUST(type_parts.get(1)->substring_from_byte_offset(1, type_parts.get(1)->byte_count() - 2));
// Drop the brackets on the range e.g. "[-∞,∞]" -> "-∞,∞"
auto type_range = MUST(type_parts.get(1)->substring_from_byte_offset(1, type_parts.get(1)->byte_count() - 2));
auto limits = MUST(type_range.split(','));
auto limits = MUST(type_range.split(','));
if (limits.size() != 2)
VERIFY_NOT_REACHED();
if (limits.size() != 2)
VERIFY_NOT_REACHED();
// FIXME: Use min and max values for i32 instead of float where applicable (e.g. for "integer")
auto min = limits.get(0) == "-∞" ? "AK::NumericLimits<float>::lowest()"_string : *limits.get(0);
auto max = limits.get(1) == "" ? "AK::NumericLimits<float>::max()"_string : *limits.get(1);
// FIXME: Use min and max values for i32 instead of float where applicable (e.g. for "integer")
auto min = limits.get(0) == "-∞" ? "AK::NumericLimits<float>::lowest()"_string : *limits.get(0);
auto max = limits.get(1) == "" ? "AK::NumericLimits<float>::max()"_string : *limits.get(1);
if (!ranges_builder.is_empty())
ranges_builder.appendff(", ");
if (!ranges_builder.is_empty())
ranges_builder.appendff(", ");
ranges_builder.appendff("{{ ValueType::{}, {{ {}, {} }} }}", title_casify(type_name), min, max);
ranges_builder.appendff("{{ ValueType::{}, {{ {}, {} }} }}", title_casify(type_name), min, max);
}
}
property_generator.set("ranges", ranges_builder.to_string_without_validation());