LibWeb: Handle guaranteed-invalid values in animation keyframes

When a CSS animation keyframe uses var() referencing a nonexistent or
invalid custom property, variable substitution produces a
guaranteed-invalid value. The animation keyframe processing code did not
handle this case, allowing the value to reach compute_opacity() (and
similar functions) which would hit VERIFY_NOT_REACHED().

Fix this by skipping guaranteed-invalid values in
compute_keyframe_values, matching how the regular cascading code treats
them.

This fixes a crash on chess.com.
This commit is contained in:
Andreas Kling 2026-03-20 23:54:09 -05:00 committed by Andreas Kling
parent 6564eff91c
commit be56df8d4f
3 changed files with 22 additions and 0 deletions

View file

@ -711,6 +711,14 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
if (style_value->is_unresolved())
style_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingParams { abstract_element.document() }, abstract_element, PropertyNameAndID::from_id(property_id), style_value->as_unresolved());
// https://drafts.csswg.org/css-values-5/#invalid-at-computed-value-time
// When substitution results in a guaranteed-invalid value, treat it as unset
// (i.e. inherit for inherited properties, initial for non-inherited properties).
if (style_value->is_guaranteed_invalid()) {
specified_values.set(property_id, nullptr);
continue;
}
for_each_property_expanding_shorthands(property_id, *style_value, [&](PropertyID longhand_id, StyleValue const& longhand_value) {
auto physical_longhand_id = map_logical_alias_to_physical_property(longhand_id, LogicalAliasMappingContext { computed_properties.writing_mode(), computed_properties.direction() });
auto physical_longhand_id_bitmap_index = to_underlying(physical_longhand_id) - to_underlying(first_longhand_property_id);

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<div id="foo"></div>
<script src="../include.js"></script>
<script>
test(() => {
const anim = foo.animate([{ opacity: "var(--nonexistent)" }, { opacity: "1" }], 1000);
anim.pause();
anim.currentTime = 500;
println(getComputedStyle(foo).opacity);
});
</script>
</html>