/* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, Tobias Christiansen * Copyright (c) 2021-2023, Sam Atkins * Copyright (c) 2022-2023, MacDue * * SPDX-License-Identifier: BSD-2-Clause */ #include "CalculatedStyleValue.h" #include #include namespace Web::CSS { static bool is_number(CalculatedStyleValue::ResolvedType type) { return type == CalculatedStyleValue::ResolvedType::Number || type == CalculatedStyleValue::ResolvedType::Integer; } static bool is_dimension(CalculatedStyleValue::ResolvedType type) { return type != CalculatedStyleValue::ResolvedType::Number && type != CalculatedStyleValue::ResolvedType::Integer && 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( [](Number const& number) { return number.value(); }, [](Angle const& angle) { return angle.to_degrees(); }, [](Flex const& flex) { return flex.to_fr(); }, [](Frequency const& frequency) { return frequency.to_hertz(); }, [&context](Length const& length) { return length.to_px(*context).to_double(); }, [](Percentage const& percentage) { return percentage.value(); }, [](Time const& time) { return time.to_seconds(); }); } static Optional add_the_types(Vector> const& nodes, PropertyID property_id) { Optional left_type; for (auto const& value : nodes) { auto right_type = value->determine_type(property_id); if (!right_type.has_value()) return {}; if (left_type.has_value()) { left_type = left_type->added_to(right_type.value()); } else { left_type = right_type; } if (!left_type.has_value()) return {}; } return left_type; } static CalculatedStyleValue::CalculationResult to_resolved_type(CalculatedStyleValue::ResolvedType type, double value) { switch (type) { case CalculatedStyleValue::ResolvedType::Integer: return { Number(Number::Type::Integer, value) }; case CalculatedStyleValue::ResolvedType::Number: return { Number(Number::Type::Number, value) }; case CalculatedStyleValue::ResolvedType::Angle: return { Angle::make_degrees(value) }; case CalculatedStyleValue::ResolvedType::Flex: return { Flex::make_fr(value) }; case CalculatedStyleValue::ResolvedType::Frequency: return { Frequency::make_hertz(value) }; case CalculatedStyleValue::ResolvedType::Length: return { Length::make_px(CSSPixels::nearest_value_for(value)) }; case CalculatedStyleValue::ResolvedType::Percentage: return { Percentage(value) }; case CalculatedStyleValue::ResolvedType::Time: return { Time::make_seconds(value) }; } VERIFY_NOT_REACHED(); } Optional CalculationNode::constant_type_from_string(StringView string) { if (string.equals_ignoring_ascii_case("e"sv)) return CalculationNode::ConstantType::E; if (string.equals_ignoring_ascii_case("pi"sv)) return CalculationNode::ConstantType::Pi; if (string.equals_ignoring_ascii_case("infinity"sv)) return CalculationNode::ConstantType::Infinity; if (string.equals_ignoring_ascii_case("-infinity"sv)) return CalculationNode::ConstantType::MinusInfinity; if (string.equals_ignoring_ascii_case("NaN"sv)) return CalculationNode::ConstantType::NaN; return {}; } CalculationNode::CalculationNode(Type type) : m_type(type) { } CalculationNode::~CalculationNode() = default; NonnullOwnPtr NumericCalculationNode::create(NumericValue value) { return adopt_own(*new (nothrow) NumericCalculationNode(move(value))); } NumericCalculationNode::NumericCalculationNode(NumericValue value) : CalculationNode(Type::Numeric) , m_value(move(value)) { } NumericCalculationNode::~NumericCalculationNode() = default; String NumericCalculationNode::to_string() const { return m_value.visit([](auto& value) { return value.to_string(); }); } Optional NumericCalculationNode::resolved_type() const { return m_value.visit( [](Number const&) { return CalculatedStyleValue::ResolvedType::Number; }, [](Angle const&) { return CalculatedStyleValue::ResolvedType::Angle; }, [](Flex const&) { return CalculatedStyleValue::ResolvedType::Flex; }, [](Frequency const&) { return CalculatedStyleValue::ResolvedType::Frequency; }, [](Length const&) { return CalculatedStyleValue::ResolvedType::Length; }, [](Percentage const&) { return CalculatedStyleValue::ResolvedType::Percentage; }, [](Time const&) { return CalculatedStyleValue::ResolvedType::Time; }); } // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation Optional NumericCalculationNode::determine_type(PropertyID property_id) const { // Anything else is a terminal value, whose type is determined based on its CSS type: return m_value.visit( [](Number const&) { // -> // -> // the type is «[ ]» (empty map) return CSSNumericType {}; }, [](Length const&) { // -> // the type is «[ "length" → 1 ]» return CSSNumericType { CSSNumericType::BaseType::Length, 1 }; }, [](Angle const&) { // -> // the type is «[ "angle" → 1 ]» return CSSNumericType { CSSNumericType::BaseType::Angle, 1 }; }, [](Time const&) { // ->