LibWeb: Implement counter-[increment,reset,set] properties

These control the state of CSS counters.

Parsing code for `reversed(counter-name)` is implemented, but disabled
for now until we are able to resolve values for those.
This commit is contained in:
Sam Atkins 2024-07-24 15:47:11 +01:00
commit 017d6c3314
Notes: github-actions[bot] 2024-07-26 10:05:39 +00:00
15 changed files with 315 additions and 5 deletions

View file

@ -44,6 +44,7 @@
#include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h>
#include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
#include <LibWeb/CSS/StyleValues/CounterDefinitionsStyleValue.h>
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
#include <LibWeb/CSS/StyleValues/EasingStyleValue.h>
@ -2891,6 +2892,63 @@ RefPtr<StyleValue> Parser::parse_color_value(TokenStream<ComponentValue>& tokens
return nullptr;
}
RefPtr<StyleValue> Parser::parse_counter_definitions_value(TokenStream<ComponentValue>& tokens, AllowReversed allow_reversed, i32 default_value_if_not_reversed)
{
// If AllowReversed is Yes, parses:
// [ <counter-name> <integer>? | <reversed-counter-name> <integer>? ]+
// Otherwise parses:
// [ <counter-name> <integer>? ]+
// FIXME: This disabled parsing of `reversed()` counters. Remove this line once they're supported.
allow_reversed = AllowReversed::No;
auto transaction = tokens.begin_transaction();
tokens.skip_whitespace();
Vector<CounterDefinition> counter_definitions;
while (tokens.has_next_token()) {
auto per_item_transaction = tokens.begin_transaction();
CounterDefinition definition {};
// <counter-name> | <reversed-counter-name>
auto& token = tokens.next_token();
if (token.is(Token::Type::Ident)) {
definition.name = token.token().ident();
definition.is_reversed = false;
} else if (allow_reversed == AllowReversed::Yes && token.is_function("reversed"sv)) {
TokenStream function_tokens { token.function().values() };
function_tokens.skip_whitespace();
auto& name_token = function_tokens.next_token();
if (!name_token.is(Token::Type::Ident))
break;
function_tokens.skip_whitespace();
if (function_tokens.has_next_token())
break;
definition.name = name_token.token().ident();
definition.is_reversed = true;
} else {
break;
}
tokens.skip_whitespace();
// <integer>?
definition.value = parse_integer_value(tokens);
if (!definition.value && !definition.is_reversed)
definition.value = IntegerStyleValue::create(default_value_if_not_reversed);
counter_definitions.append(move(definition));
tokens.skip_whitespace();
per_item_transaction.commit();
}
if (counter_definitions.is_empty())
return {};
transaction.commit();
return CounterDefinitionsStyleValue::create(move(counter_definitions));
}
RefPtr<StyleValue> Parser::parse_ratio_value(TokenStream<ComponentValue>& tokens)
{
if (auto ratio = parse_ratio(tokens); ratio.has_value())
@ -4170,6 +4228,36 @@ RefPtr<StyleValue> Parser::parse_content_value(TokenStream<ComponentValue>& toke
return ContentStyleValue::create(StyleValueList::create(move(content_values), StyleValueList::Separator::Space), move(alt_text));
}
// https://drafts.csswg.org/css-lists-3/#propdef-counter-increment
RefPtr<StyleValue> Parser::parse_counter_increment_value(TokenStream<ComponentValue>& tokens)
{
// [ <counter-name> <integer>? ]+ | none
if (auto none = parse_all_as_single_none_value(tokens))
return none;
return parse_counter_definitions_value(tokens, AllowReversed::No, 1);
}
// https://drafts.csswg.org/css-lists-3/#propdef-counter-reset
RefPtr<StyleValue> Parser::parse_counter_reset_value(TokenStream<ComponentValue>& tokens)
{
// [ <counter-name> <integer>? | <reversed-counter-name> <integer>? ]+ | none
if (auto none = parse_all_as_single_none_value(tokens))
return none;
return parse_counter_definitions_value(tokens, AllowReversed::Yes, 0);
}
// https://drafts.csswg.org/css-lists-3/#propdef-counter-set
RefPtr<StyleValue> Parser::parse_counter_set_value(TokenStream<ComponentValue>& tokens)
{
// [ <counter-name> <integer>? ]+ | none
if (auto none = parse_all_as_single_none_value(tokens))
return none;
return parse_counter_definitions_value(tokens, AllowReversed::No, 0);
}
// https://www.w3.org/TR/css-display-3/#the-display-properties
RefPtr<StyleValue> Parser::parse_display_value(TokenStream<ComponentValue>& tokens)
{
@ -6758,6 +6846,18 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
if (auto parsed_value = parse_content_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::CounterIncrement:
if (auto parsed_value = parse_counter_increment_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::CounterReset:
if (auto parsed_value = parse_counter_reset_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::CounterSet:
if (auto parsed_value = parse_counter_set_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::Display:
if (auto parsed_value = parse_display_value(tokens); parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();