From c443f8013793436674312631ed4e441c5d242cd4 Mon Sep 17 00:00:00 2001 From: Bastiaan van der Plaat Date: Mon, 8 Jan 2024 18:51:19 +0100 Subject: [PATCH] LibWeb: Allow percentages on CSS transform scale functions --- .../LibWeb/GenerateCSSTransformFunctions.cpp | 3 ++ .../css/getComputedStyle-transform.txt | 3 ++ .../input/css/getComputedStyle-transform.html | 3 ++ .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 28 +++++++++++++++++++ Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 1 + .../Libraries/LibWeb/CSS/StyleProperties.cpp | 20 ++++++++++--- .../LibWeb/CSS/TransformFunctions.json | 8 +++--- .../Libraries/LibWeb/CSS/Transformation.cpp | 6 ++-- .../Libraries/LibWeb/CSS/Transformation.h | 2 +- 9 files changed, 63 insertions(+), 11 deletions(-) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSTransformFunctions.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSTransformFunctions.cpp index e6ca5752f6..590bbda82b 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSTransformFunctions.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSTransformFunctions.cpp @@ -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(); diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-transform.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-transform.txt index f0065f6748..265d8c7ff5 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-transform.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-transform.txt @@ -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) diff --git a/Tests/LibWeb/Text/input/css/getComputedStyle-transform.html b/Tests/LibWeb/Text/input/css/getComputedStyle-transform.html index 3418ba45db..b0327c8dcf 100644 --- a/Tests/LibWeb/Text/input/css/getComputedStyle-transform.html +++ b/Tests/LibWeb/Text/input/css/getComputedStyle-transform.html @@ -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)", diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index e8aa91f224..f867328e7d 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -2175,6 +2175,21 @@ RefPtr Parser::parse_number_value(TokenStream& token return nullptr; } +RefPtr Parser::parse_number_or_percentage_value(TokenStream& 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 Parser::parse_identifier_value(ComponentValue const& component_value) { if (component_value.is(Token::Type::Ident)) { @@ -5158,6 +5173,19 @@ RefPtr Parser::parse_transform_value(TokenStream& 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(); diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index 7d2dc07159..e3927fb236 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -220,6 +220,7 @@ private: RefPtr parse_dimension_value(ComponentValue const&); RefPtr parse_integer_value(TokenStream&); RefPtr parse_number_value(TokenStream&); + RefPtr parse_number_or_percentage_value(TokenStream&); RefPtr parse_identifier_value(ComponentValue const&); RefPtr parse_color_value(ComponentValue const&); RefPtr parse_rect_value(ComponentValue const&); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 93547b54e2..5b88fa0078 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -422,16 +422,23 @@ Vector 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 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 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)); } diff --git a/Userland/Libraries/LibWeb/CSS/TransformFunctions.json b/Userland/Libraries/LibWeb/CSS/TransformFunctions.json index 6f764e6d04..6b71a3cc9a 100644 --- a/Userland/Libraries/LibWeb/CSS/TransformFunctions.json +++ b/Userland/Libraries/LibWeb/CSS/TransformFunctions.json @@ -150,11 +150,11 @@ "scale": { "parameters": [ { - "type": "", + "type": "", "required": true }, { - "type": "", + "type": "", "required": false } ] @@ -162,7 +162,7 @@ "scaleX": { "parameters": [ { - "type": "", + "type": "", "required": true } ] @@ -170,7 +170,7 @@ "scaleY": { "parameters": [ { - "type": "", + "type": "", "required": true } ] diff --git a/Userland/Libraries/LibWeb/CSS/Transformation.cpp b/Userland/Libraries/LibWeb/CSS/Transformation.cpp index b76cda62b4..88b65e3646 100644 --- a/Userland/Libraries/LibWeb/CSS/Transformation.cpp +++ b/Userland/Libraries/LibWeb/CSS/Transformation.cpp @@ -35,8 +35,10 @@ ErrorOr Transformation::to_matrix(Optional ErrorOr { - return value; + [&](CSS::NumberPercentage const& value) -> ErrorOr { + if (value.is_percentage()) + return value.percentage().as_fraction(); + return value.number().value(); }); }; diff --git a/Userland/Libraries/LibWeb/CSS/Transformation.h b/Userland/Libraries/LibWeb/CSS/Transformation.h index 56bed71e75..eb38fe61fb 100644 --- a/Userland/Libraries/LibWeb/CSS/Transformation.h +++ b/Userland/Libraries/LibWeb/CSS/Transformation.h @@ -15,7 +15,7 @@ namespace Web::CSS { -using TransformValue = Variant; +using TransformValue = Variant; class Transformation { public: