LibWeb: Make animation parsing logic reusable

This is useful for parsing of other coordinating list shorthands
This commit is contained in:
Callum Law 2025-10-17 21:22:43 +13:00 committed by Sam Atkins
parent bb7d5747e7
commit 94c788f2e0
Notes: github-actions[bot] 2025-10-23 09:11:12 +00:00
2 changed files with 68 additions and 54 deletions

View file

@ -96,6 +96,71 @@ RefPtr<StyleValue const> Parser::parse_simple_comma_separated_value_list(Propert
});
}
RefPtr<StyleValue const> Parser::parse_coordinating_value_list_shorthand(TokenStream<ComponentValue>& tokens, PropertyID shorthand_id, Vector<PropertyID> const& longhand_ids)
{
HashMap<PropertyID, StyleValueVector> longhand_vectors;
auto transaction = tokens.begin_transaction();
do {
Vector<PropertyID> remaining_longhands {};
remaining_longhands.extend(longhand_ids);
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> parsed_values;
while (tokens.has_next_token() && !tokens.next_token().is(Token::Type::Comma)) {
auto property_and_value = parse_css_value_for_properties(remaining_longhands, tokens);
if (!property_and_value.has_value())
return {};
remove_property(remaining_longhands, property_and_value->property);
parsed_values.set(property_and_value->property, property_and_value->style_value.release_nonnull());
}
if (parsed_values.is_empty())
return {};
for (auto const& longhand_id : longhand_ids)
longhand_vectors.ensure(longhand_id).append(*parsed_values.get(longhand_id).value_or_lazy_evaluated([&]() -> ValueComparingNonnullRefPtr<StyleValue const> {
auto initial_value = property_initial_value(longhand_id);
if (initial_value->is_value_list())
return initial_value->as_value_list().values()[0];
return initial_value;
}));
if (tokens.has_next_token()) {
if (tokens.next_token().is(Token::Type::Comma))
tokens.discard_a_token();
else
return {};
}
} while (tokens.has_next_token());
transaction.commit();
// FIXME: This is for compatibility with parse_comma_separated_value_list(), which returns a single value directly
// instead of a list if there's only one, it would be nicer if we always returned a list.
if (longhand_vectors.get(longhand_ids[0])->size() == 1) {
StyleValueVector longhand_values {};
for (auto const& longhand_id : longhand_ids)
longhand_values.append((*longhand_vectors.get(longhand_id))[0]);
return ShorthandStyleValue::create(shorthand_id, longhand_ids, longhand_values);
}
StyleValueVector longhand_values {};
for (auto const& longhand_id : longhand_ids)
longhand_values.append(StyleValueList::create(move(*longhand_vectors.get(longhand_id)), StyleValueList::Separator::Comma));
return ShorthandStyleValue::create(shorthand_id, longhand_ids, longhand_values);
}
RefPtr<StyleValue const> Parser::parse_css_value_for_property(PropertyID property_id, TokenStream<ComponentValue>& tokens)
{
return parse_css_value_for_properties({ &property_id, 1 }, tokens)
@ -1295,60 +1360,8 @@ RefPtr<StyleValue const> Parser::parse_animation_value(TokenStream<ComponentValu
PropertyID::AnimationName
};
HashMap<PropertyID, StyleValueVector> longhand_vectors;
auto transaction = tokens.begin_transaction();
do {
Vector<PropertyID> remaining_longhands {};
remaining_longhands.extend(longhand_ids);
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> parsed_values;
while (tokens.has_next_token() && !tokens.next_token().is(Token::Type::Comma)) {
auto property_and_value = parse_css_value_for_properties(remaining_longhands, tokens);
if (!property_and_value.has_value())
return {};
remove_property(remaining_longhands, property_and_value->property);
parsed_values.set(property_and_value->property, property_and_value->style_value.release_nonnull());
}
if (parsed_values.is_empty())
return {};
for (auto const& longhand_id : longhand_ids)
longhand_vectors.ensure(longhand_id).append(*parsed_values.get(longhand_id).value_or(property_initial_value(longhand_id)));
if (tokens.has_next_token()) {
if (tokens.next_token().is(Token::Type::Comma))
tokens.discard_a_token();
else
return {};
}
} while (tokens.has_next_token());
transaction.commit();
// FIXME: This is for compatibility with parse_comma_separated_value_list(), which returns a single value directly
// instead of a list if there's only one, it would be nicer if we always returned a list.
if (longhand_vectors.get(PropertyID::AnimationDuration)->size() == 1) {
StyleValueVector longhand_values {};
for (auto const& longhand_id : longhand_ids)
longhand_values.append((*longhand_vectors.get(longhand_id))[0]);
return ShorthandStyleValue::create(PropertyID::Animation, longhand_ids, longhand_values);
}
StyleValueVector longhand_values {};
for (auto const& longhand_id : longhand_ids)
longhand_values.append(StyleValueList::create(move(*longhand_vectors.get(longhand_id)), StyleValueList::Separator::Comma));
return ShorthandStyleValue::create(PropertyID::Animation, longhand_ids, longhand_values);
// FIXME: The animation-trigger properties are reset-only sub-properties of the animation shorthand.
return parse_coordinating_value_list_shorthand(tokens, PropertyID::Animation, longhand_ids);
}
RefPtr<StyleValue const> Parser::parse_background_value(TokenStream<ComponentValue>& tokens)