LibWeb: Allow percentages on CSS transform scale functions

This commit is contained in:
Bastiaan van der Plaat 2024-01-08 18:51:19 +01:00 committed by Andreas Kling
parent 57ea3e160a
commit c443f80137
Notes: sideshowbarker 2024-07-17 10:08:28 +09:00
9 changed files with 63 additions and 11 deletions

View file

@ -81,6 +81,7 @@ enum class TransformFunctionParameterType {
Length,
LengthPercentage,
Number,
NumberPercentage
};
struct TransformFunctionParameter {
@ -183,6 +184,8 @@ TransformFunctionMetadata transform_function_metadata(TransformFunction transfor
parameter_type = "LengthPercentage"sv;
else if (parameter_type_name == "number"sv)
parameter_type = "Number"sv;
else if (parameter_type_name == "number-percentage"sv)
parameter_type = "NumberPercentage"sv;
else
VERIFY_NOT_REACHED();

View file

@ -6,8 +6,11 @@ translate3d(1%, 2px, 3em) => matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7.8281
translateX(1px) => matrix(1, 0, 0, 1, 1, 0)
translateY(1%) => matrix(1, 0, 0, 1, 0, 0)
scale(1, 2) => matrix(1, 0, 0, 2, 0, 0)
scale(100%, 200%) => matrix(1, 0, 0, 2, 0, 0)
scaleX(2) => matrix(2, 0, 0, 1, 0, 0)
scaleX(200%) => matrix(2, 0, 0, 1, 0, 0)
scaleY(2.5) => matrix(1, 0, 0, 2.5, 0, 0)
scaleY(250%) => matrix(1, 0, 0, 2.5, 0, 0)
rotate(1deg) => matrix(0.9998477101325989, 0.017452405765652657, -0.017452405765652657, 0.9998477101325989, 0, 0)
rotateX(1rad) => matrix3d(1, 0, 0, 0, 0, 0.5403022766113281, 0.8414709568023682, 0, 0, -0.8414709568023682, 0.5403022766113281, 0, 0, 0, 0, 1)
rotateY(1grad) => matrix3d(0.9998766183853149, 0, -0.015707317739725113, 0, 0, 1, 0, 0, 0.015707317739725113, 0, 0.9998766183853149, 0, 0, 0, 0, 1)

View file

@ -18,8 +18,11 @@
"translateX(1px)",
"translateY(1%)",
"scale(1, 2)",
"scale(100%, 200%)",
"scaleX(2)",
"scaleX(200%)",
"scaleY(2.5)",
"scaleY(250%)",
"rotate(1deg)",
"rotateX(1rad)",
"rotateY(1grad)",

View file

@ -2175,6 +2175,21 @@ RefPtr<StyleValue> Parser::parse_number_value(TokenStream<ComponentValue>& token
return nullptr;
}
RefPtr<StyleValue> Parser::parse_number_or_percentage_value(TokenStream<ComponentValue>& tokens)
{
auto peek_token = tokens.peek_token();
if (peek_token.is(Token::Type::Number)) {
(void)tokens.next_token();
return NumberStyleValue::create(peek_token.token().number().value());
}
if (peek_token.is(Token::Type::Percentage)) {
(void)tokens.next_token();
return PercentageStyleValue::create(Percentage(peek_token.token().percentage()));
}
return nullptr;
}
RefPtr<StyleValue> Parser::parse_identifier_value(ComponentValue const& component_value)
{
if (component_value.is(Token::Type::Ident)) {
@ -5158,6 +5173,19 @@ RefPtr<StyleValue> Parser::parse_transform_value(TokenStream<ComponentValue>& to
}
break;
}
case TransformFunctionParameterType::NumberPercentage: {
if (maybe_calc_value && maybe_calc_value->resolves_to_number()) {
values.append(maybe_calc_value.release_nonnull());
} else {
// FIXME: Remove this reconsume once all parsing functions are TokenStream-based.
argument_tokens.reconsume_current_input_token();
auto number_or_percentage = parse_number_or_percentage_value(argument_tokens);
if (!number_or_percentage)
return nullptr;
values.append(number_or_percentage.release_nonnull());
}
break;
}
}
argument_tokens.skip_whitespace();

View file

@ -220,6 +220,7 @@ private:
RefPtr<StyleValue> parse_dimension_value(ComponentValue const&);
RefPtr<StyleValue> parse_integer_value(TokenStream<ComponentValue>&);
RefPtr<StyleValue> parse_number_value(TokenStream<ComponentValue>&);
RefPtr<StyleValue> parse_number_or_percentage_value(TokenStream<ComponentValue>&);
RefPtr<StyleValue> parse_identifier_value(ComponentValue const&);
RefPtr<StyleValue> parse_color_value(ComponentValue const&);
RefPtr<StyleValue> parse_rect_value(ComponentValue const&);

View file

@ -422,16 +422,23 @@ Vector<CSS::Transformation> StyleProperties::transformations_for_style_value(Sty
return {};
auto& transformation_style_value = it->as_transformation();
auto function = transformation_style_value.transform_function();
auto function_metadata = transform_function_metadata(function);
Vector<TransformValue> values;
size_t argument_index = 0;
for (auto& transformation_value : transformation_style_value.values()) {
if (transformation_value->is_calculated()) {
auto& calculated = transformation_value->as_calculated();
if (calculated.resolves_to_length_percentage()) {
values.append(CSS::LengthPercentage { calculated });
} else if (calculated.resolves_to_percentage()) {
values.append({ calculated.resolve_percentage().value() });
// FIXME: Maybe transform this for loop to always check the metadata for the correct types
if (function_metadata.parameters[argument_index].type == TransformFunctionParameterType::NumberPercentage) {
values.append(NumberPercentage { calculated.resolve_percentage().value() });
} else {
values.append(LengthPercentage { calculated.resolve_percentage().value() });
}
} else if (calculated.resolves_to_number()) {
values.append({ calculated.resolve_number().value() });
values.append({ Number(Number::Type::Number, calculated.resolve_number().value()) });
} else if (calculated.resolves_to_angle()) {
values.append({ calculated.resolve_angle().value() });
} else {
@ -440,14 +447,19 @@ Vector<CSS::Transformation> StyleProperties::transformations_for_style_value(Sty
} else if (transformation_value->is_length()) {
values.append({ transformation_value->as_length().length() });
} else if (transformation_value->is_percentage()) {
values.append({ transformation_value->as_percentage().percentage() });
if (function_metadata.parameters[argument_index].type == TransformFunctionParameterType::NumberPercentage) {
values.append(NumberPercentage { transformation_value->as_percentage().percentage() });
} else {
values.append(LengthPercentage { transformation_value->as_percentage().percentage() });
}
} else if (transformation_value->is_number()) {
values.append({ transformation_value->as_number().number() });
values.append({ Number(Number::Type::Number, transformation_value->as_number().number()) });
} else if (transformation_value->is_angle()) {
values.append({ transformation_value->as_angle().angle() });
} else {
dbgln("FIXME: Unsupported value in transform! {}", transformation_value->to_string());
}
argument_index++;
}
transformations.empend(function, move(values));
}

View file

@ -150,11 +150,11 @@
"scale": {
"parameters": [
{
"type": "<number>",
"type": "<number-percentage>",
"required": true
},
{
"type": "<number>",
"type": "<number-percentage>",
"required": false
}
]
@ -162,7 +162,7 @@
"scaleX": {
"parameters": [
{
"type": "<number>",
"type": "<number-percentage>",
"required": true
}
]
@ -170,7 +170,7 @@
"scaleY": {
"parameters": [
{
"type": "<number>",
"type": "<number-percentage>",
"required": true
}
]

View file

@ -35,8 +35,10 @@ ErrorOr<Gfx::FloatMatrix4x4> Transformation::to_matrix(Optional<Painting::Painta
return value.value().to_radians();
return Error::from_string_literal("Transform contains non absolute units");
},
[](double value) -> ErrorOr<float> {
return value;
[&](CSS::NumberPercentage const& value) -> ErrorOr<float> {
if (value.is_percentage())
return value.percentage().as_fraction();
return value.number().value();
});
};

View file

@ -15,7 +15,7 @@
namespace Web::CSS {
using TransformValue = Variant<AngleOrCalculated, LengthPercentage, double>;
using TransformValue = Variant<AngleOrCalculated, LengthPercentage, NumberPercentage>;
class Transformation {
public: