mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-16 21:20:18 +00:00
LibWeb/CSS: Promote <transform-list/function>
to parsable types
The `transform` property is now parsed based on its JSON data, and shouldn't behave any differently than before. This makes `<transform-list>` and `<transform-function>` work in the `syntax` descriptor for `@property`, and also means we know that `transform` can accept the `none` keyword. We get a few WPT passes out of that.
This commit is contained in:
parent
65ba5acf9d
commit
35fd3bda79
Notes:
github-actions[bot]
2025-10-14 12:43:05 +00:00
Author: https://github.com/AtkinsSJ
Commit: 35fd3bda79
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6466
8 changed files with 170 additions and 136 deletions
|
@ -178,6 +178,10 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
|||
return parsed.release_value();
|
||||
if (auto parsed = parse_for_type(ValueType::String); parsed.has_value())
|
||||
return parsed.release_value();
|
||||
if (auto parsed = parse_for_type(ValueType::TransformFunction); parsed.has_value())
|
||||
return parsed.release_value();
|
||||
if (auto parsed = parse_for_type(ValueType::TransformList); parsed.has_value())
|
||||
return parsed.release_value();
|
||||
if (auto parsed = parse_for_type(ValueType::Url); parsed.has_value())
|
||||
return parsed.release_value();
|
||||
|
||||
|
@ -802,10 +806,6 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_css_value(Pr
|
|||
if (auto parsed_value = parse_touch_action_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::Transform:
|
||||
if (auto parsed_value = parse_transform_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
return ParseError::SyntaxError;
|
||||
case PropertyID::TransformOrigin:
|
||||
if (auto parsed_value = parse_transform_origin_value(tokens); parsed_value && !tokens.has_next_token())
|
||||
return parsed_value.release_nonnull();
|
||||
|
@ -4913,119 +4913,6 @@ RefPtr<StyleValue const> Parser::parse_touch_action_value(TokenStream<ComponentV
|
|||
return StyleValueList::create(move(parsed_values), StyleValueList::Separator::Space);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-transforms-1/#transform-property
|
||||
RefPtr<StyleValue const> Parser::parse_transform_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// <transform> = none | <transform-list>
|
||||
// <transform-list> = <transform-function>+
|
||||
|
||||
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
|
||||
return none;
|
||||
|
||||
StyleValueVector transformations;
|
||||
auto transaction = tokens.begin_transaction();
|
||||
while (tokens.has_next_token()) {
|
||||
auto const& part = tokens.consume_a_token();
|
||||
if (!part.is_function())
|
||||
return nullptr;
|
||||
auto maybe_function = transform_function_from_string(part.function().name);
|
||||
if (!maybe_function.has_value())
|
||||
return nullptr;
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(FunctionContext { part.function().name });
|
||||
|
||||
auto function = maybe_function.release_value();
|
||||
auto function_metadata = transform_function_metadata(function);
|
||||
|
||||
auto function_tokens = TokenStream { part.function().value };
|
||||
auto arguments = parse_a_comma_separated_list_of_component_values(function_tokens);
|
||||
|
||||
if (arguments.size() > function_metadata.parameters.size()) {
|
||||
ErrorReporter::the().report(InvalidValueError {
|
||||
.value_type = "<transform-function>"_fly_string,
|
||||
.value_string = part.function().original_source_text(),
|
||||
.description = MUST(String::formatted("Too many arguments to {}. max: {}", part.function().name, function_metadata.parameters.size())),
|
||||
});
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (arguments.size() < function_metadata.parameters.size() && function_metadata.parameters[arguments.size()].required) {
|
||||
ErrorReporter::the().report(InvalidValueError {
|
||||
.value_type = "<transform-function>"_fly_string,
|
||||
.value_string = part.function().original_source_text(),
|
||||
.description = MUST(String::formatted("Required parameter at position {} is missing", arguments.size())),
|
||||
});
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StyleValueVector values;
|
||||
for (auto argument_index = 0u; argument_index < arguments.size(); ++argument_index) {
|
||||
TokenStream argument_tokens { arguments[argument_index] };
|
||||
argument_tokens.discard_whitespace();
|
||||
|
||||
switch (function_metadata.parameters[argument_index].type) {
|
||||
case TransformFunctionParameterType::Angle: {
|
||||
// These are `<angle> | <zero>` in the spec, so we have to check for both kinds.
|
||||
if (auto angle_value = parse_angle_value(argument_tokens)) {
|
||||
values.append(angle_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
if (argument_tokens.next_token().is(Token::Type::Number) && argument_tokens.next_token().token().number_value() == 0) {
|
||||
argument_tokens.discard_a_token(); // 0
|
||||
values.append(AngleStyleValue::create(Angle::make_degrees(0)));
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
case TransformFunctionParameterType::Length:
|
||||
case TransformFunctionParameterType::LengthNone: {
|
||||
if (auto length_value = parse_length_value(argument_tokens)) {
|
||||
values.append(length_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
if (function_metadata.parameters[argument_index].type == TransformFunctionParameterType::LengthNone
|
||||
&& argument_tokens.next_token().is_ident("none"sv)) {
|
||||
|
||||
argument_tokens.discard_a_token(); // none
|
||||
values.append(KeywordStyleValue::create(Keyword::None));
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
case TransformFunctionParameterType::LengthPercentage: {
|
||||
if (auto length_percentage_value = parse_length_percentage_value(argument_tokens)) {
|
||||
values.append(length_percentage_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
case TransformFunctionParameterType::Number: {
|
||||
if (auto number_value = parse_number_value(argument_tokens)) {
|
||||
values.append(number_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
case TransformFunctionParameterType::NumberPercentage: {
|
||||
if (auto number_percentage_value = parse_number_percentage_value(argument_tokens)) {
|
||||
values.append(number_percentage_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
argument_tokens.discard_whitespace();
|
||||
if (argument_tokens.has_next_token())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
transformations.append(TransformationStyleValue::create(PropertyID::Transform, function, move(values)));
|
||||
}
|
||||
transaction.commit();
|
||||
return StyleValueList::create(move(transformations), StyleValueList::Separator::Space);
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-transforms-1/#propdef-transform-origin
|
||||
RefPtr<StyleValue const> Parser::parse_transform_origin_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue