diff --git a/Userland/Libraries/LibWeb/CSS/Angle.cpp b/Userland/Libraries/LibWeb/CSS/Angle.cpp index 37acc9ad65a..38a56ee51ed 100644 --- a/Userland/Libraries/LibWeb/CSS/Angle.cpp +++ b/Userland/Libraries/LibWeb/CSS/Angle.cpp @@ -52,6 +52,11 @@ double Angle::to_degrees() const VERIFY_NOT_REACHED(); } +double Angle::to_radians() const +{ + return to_degrees() * (AK::Pi / 180.0); +} + StringView Angle::unit_name() const { switch (m_type) { diff --git a/Userland/Libraries/LibWeb/CSS/Angle.h b/Userland/Libraries/LibWeb/CSS/Angle.h index e6d1c94459e..b9339909827 100644 --- a/Userland/Libraries/LibWeb/CSS/Angle.h +++ b/Userland/Libraries/LibWeb/CSS/Angle.h @@ -28,7 +28,9 @@ public: Angle percentage_of(Percentage const&) const; ErrorOr to_string() const; + double to_degrees() const; + double to_radians() const; Type type() const { return m_type; } double raw_value() const { return m_value; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index f86538e2847..fe34bd26283 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -3594,6 +3594,30 @@ ErrorOr> Parser::parse_sign_function(Function const& fun return TRY(SignCalculationNode::create(calculation_node.release_nonnull())); } +ErrorOr> Parser::parse_sin_function(Function const& function) +{ + auto calculation_node = TRY(parse_a_calculation(function.values())); + + if (!calculation_node) { + dbgln_if(CSS_PARSER_DEBUG, "sin() parameter must be a valid calculation"sv); + return nullptr; + } + + auto maybe_parameter_type = calculation_node->resolved_type(); + if (!maybe_parameter_type.has_value()) { + dbgln_if(CSS_PARSER_DEBUG, "Failed to resolve type for sin() parameter"sv); + return nullptr; + } + + auto resolved_type = maybe_parameter_type.value(); + if (resolved_type != CalculatedStyleValue::ResolvedType::Number && resolved_type != CalculatedStyleValue::ResolvedType::Angle) { + dbgln_if(CSS_PARSER_DEBUG, "sin() parameter must be a number or angle"sv); + return nullptr; + } + + return TRY(SinCalculationNode::create(calculation_node.release_nonnull())); +} + ErrorOr> Parser::parse_dynamic_value(ComponentValue const& component_value) { if (component_value.is_function()) { @@ -3638,6 +3662,9 @@ ErrorOr> Parser::parse_a_calc_function_node(Function con if (function.name().equals_ignoring_ascii_case("sign"sv)) return TRY(parse_sign_function(function)); + if (function.name().equals_ignoring_ascii_case("sin"sv)) + return TRY(parse_sin_function(function)); + dbgln_if(CSS_PARSER_DEBUG, "We didn't implement `{}` function yet", function.name()); return nullptr; } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index c33ca081f25..2703218cde5 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -295,6 +295,7 @@ private: ErrorOr> parse_clamp_function(Function const&); ErrorOr> parse_abs_function(Function const&); ErrorOr> parse_sign_function(Function const&); + ErrorOr> parse_sin_function(Function const&); ErrorOr> parse_dimension_value(ComponentValue const&); ErrorOr> parse_integer_value(TokenStream&); ErrorOr> parse_number_value(TokenStream&); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp index 495cdefdef9..80b7043ed4d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp @@ -24,6 +24,14 @@ static bool is_dimension(CalculatedStyleValue::ResolvedType type) && type != CalculatedStyleValue::ResolvedType::Percentage; } +static double resolve_value_radians(CalculatedStyleValue::CalculationResult::Value value) +{ + return value.visit( + [](Number const& number) { return number.value(); }, + [](Angle const& angle) { return angle.to_radians(); }, + [](auto const&) { VERIFY_NOT_REACHED(); return 0.0; }); +}; + static double resolve_value(CalculatedStyleValue::CalculationResult::Value value, Optional context) { return value.visit( @@ -842,6 +850,60 @@ ErrorOr ConstantCalculationNode::dump(StringBuilder& builder, int indent) return {}; } +ErrorOr> SinCalculationNode::create(NonnullOwnPtr value) +{ + return adopt_nonnull_own_or_enomem(new (nothrow) SinCalculationNode(move(value))); +} + +SinCalculationNode::SinCalculationNode(NonnullOwnPtr value) + : CalculationNode(Type::Sin) + , m_value(move(value)) +{ +} + +SinCalculationNode::~SinCalculationNode() = default; + +ErrorOr SinCalculationNode::to_string() const +{ + StringBuilder builder; + builder.append("sin("sv); + builder.append(TRY(m_value->to_string())); + builder.append(")"sv); + return builder.to_string(); +} + +Optional SinCalculationNode::resolved_type() const +{ + return CalculatedStyleValue::ResolvedType::Number; +} + +bool SinCalculationNode::contains_percentage() const +{ + return m_value->contains_percentage(); +} + +CalculatedStyleValue::CalculationResult SinCalculationNode::resolve(Optional context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const +{ + auto node_a = m_value->resolve(context, percentage_basis); + auto node_a_value = resolve_value_radians(node_a.value()); + auto result = sin(node_a_value); + + return { Number(Number::Type::Number, result) }; +} + +ErrorOr SinCalculationNode::for_each_child_node(Function(NonnullOwnPtr&)> const& callback) +{ + TRY(m_value->for_each_child_node(callback)); + TRY(callback(m_value)); + return {}; +} + +ErrorOr SinCalculationNode::dump(StringBuilder& builder, int indent) const +{ + TRY(builder.try_appendff("{: >{}}SIN: {}\n", "", indent, TRY(to_string()))); + return {}; +} + void CalculatedStyleValue::CalculationResult::add(CalculationResult const& other, Optional context, PercentageBasis const& percentage_basis) { add_or_subtract_internal(SumOperation::Add, other, context, percentage_basis); diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h index 972d2ee1bd6..483b624fe5d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h @@ -152,6 +152,16 @@ public: // https://drafts.csswg.org/css-values-4/#calc-constants Constant, + // Trigonometric functions, a sub-type of operator node + // https://drafts.csswg.org/css-values-4/#trig-funcs + Sin, + Cos, + Tan, + Asin, + Acos, + Atan, + Atan2, + // This only exists during parsing. Unparsed, }; @@ -386,4 +396,22 @@ private: CalculationNode::ConstantType m_constant; }; +class SinCalculationNode final : public CalculationNode { +public: + static ErrorOr> create(NonnullOwnPtr); + ~SinCalculationNode(); + + virtual ErrorOr to_string() const override; + virtual Optional resolved_type() const override; + virtual bool contains_percentage() const override; + virtual CalculatedStyleValue::CalculationResult resolve(Optional, CalculatedStyleValue::PercentageBasis const&) const override; + virtual ErrorOr for_each_child_node(Function(NonnullOwnPtr&)> const&) override; + + virtual ErrorOr dump(StringBuilder&, int indent) const override; + +private: + SinCalculationNode(NonnullOwnPtr); + NonnullOwnPtr m_value; +}; + }