diff --git a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp index dab84206db0..f05d081bfe0 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp @@ -129,6 +129,238 @@ static NonnullRefPtr simplify_2_children(T const& original, Non return original; } +static String serialize_a_calculation_tree(CalculationNode const&, CalculationContext const&, CSSStyleValue::SerializationMode); + +// https://drafts.csswg.org/css-values-4/#serialize-a-math-function +static String serialize_a_math_function(CalculationNode const& fn, CalculationContext const& context, CSSStyleValue::SerializationMode serialization_mode) +{ + // To serialize a math function fn: + + // 1. If the root of the calculation tree fn represents is a numeric value (number, percentage, or dimension), and + // the serialization being produced is of a computed value or later, then clamp the value to the range allowed + // for its context (if necessary), then serialize the value as normal and return the result. + if (fn.type() == CalculationNode::Type::Numeric && serialization_mode == CSSStyleValue::SerializationMode::ResolvedValue) { + // FIXME: Clamp the value. Note that we might have an infinite/nan value here. + return fn.to_string(); + } + + // 2. If fn represents an infinite or NaN value: + if (fn.type() == CalculationNode::Type::Numeric) { + auto& numeric_node = static_cast(fn); + if (auto infinite_or_nan = numeric_node.infinite_or_nan_value(); infinite_or_nan.has_value()) { + // 1. Let s be the string "calc(". + StringBuilder builder; + builder.append("calc("sv); + + // 2. Serialize the keyword infinity, -infinity, or NaN, as appropriate to represent the value, and append it to s. + switch (infinite_or_nan.value()) { + case NonFiniteValue::Infinity: + builder.append("infinity"sv); + break; + case NonFiniteValue::NegativeInfinity: + builder.append("-infinity"sv); + break; + case NonFiniteValue::NaN: + builder.append("NaN"sv); + break; + default: + VERIFY_NOT_REACHED(); + } + + // 3. If fn’s type is anything other than «[ ]» (empty, representing a ), append " * " to s. + // Create a numeric value in the canonical unit for fn’s type (such as px for ), with a value of 1. + // Serialize this numeric value and append it to s. + if (!numeric_node.value().has()) { + numeric_node.value().visit( + [&builder](Angle const&) { builder.append(" * 1deg"sv); }, + [&builder](Flex const&) { builder.append(" * 1fr"sv); }, + [&builder](Frequency const&) { builder.append(" * 1hz"sv); }, + [&builder](Length const&) { builder.append(" * 1px"sv); }, + [](Number const&) { VERIFY_NOT_REACHED(); }, + [&builder](Percentage const&) { builder.append(" * 1%"sv); }, + [&builder](Resolution const&) { builder.append(" * 1dppx"sv); }, + [&builder](Time const&) { builder.append(" * 1s"sv); }); + } + + // 4. Append ")" to s, then return it. + builder.append(')'); + return builder.to_string_without_validation(); + } + } + + // 3. If the calculation tree’s root node is a numeric value, or a calc-operator node, let s be a string initially + // containing "calc(". + // Otherwise, let s be a string initially containing the name of the root node, lowercased (such as "sin" or + // "max"), followed by a "(" (open parenthesis). + StringBuilder builder; + if (fn.type() == CalculationNode::Type::Numeric || fn.is_calc_operator_node()) { + builder.append("calc("sv); + } else { + builder.appendff("{}(", fn.name()); + } + + // 4. For each child of the root node, serialize the calculation tree. + // If a result of this serialization starts with a "(" (open parenthesis) and ends with a ")" (close parenthesis), + // remove those characters from the result. + // Concatenate all of the results using ", " (comma followed by space), then append the result to s. + + auto serialized_tree_without_parentheses = [&](CalculationNode const& tree) { + auto tree_serialized = serialize_a_calculation_tree(tree, context, serialization_mode); + if (tree_serialized.starts_with('(') && tree_serialized.ends_with(')')) { + tree_serialized = MUST(tree_serialized.substring_from_byte_offset_with_shared_superstring(1, tree_serialized.byte_count() - 2)); + } + return tree_serialized; + }; + + // Spec issue: https://github.com/w3c/csswg-drafts/issues/11783 + // The three AD-HOCs in this step are mentioned there. + // AD-HOC: Numeric nodes have no children and should serialize directly. + // AD-HOC: calc-operator nodes should also serialize directly, instead of separating their children by commas.# + if (fn.type() == CalculationNode::Type::Numeric || fn.is_calc_operator_node()) { + builder.append(serialized_tree_without_parentheses(fn)); + } else { + Vector serialized_children; + // AD-HOC: For `clamp()`, the first child is a , which is incompatible with "serialize a calculation tree". + // So, we serialize it directly first, and hope for the best. + if (fn.type() == CalculationNode::Type::Round) { + auto rounding_strategy = static_cast(fn).rounding_strategy(); + serialized_children.append(MUST(String::from_utf8(CSS::to_string(rounding_strategy)))); + } + for (auto const& child : fn.children()) { + serialized_children.append(serialized_tree_without_parentheses(child)); + } + builder.join(", "sv, serialized_children); + } + + // 5. Append ")" (close parenthesis) to s. + builder.append(')'); + + // 6. Return s. + return builder.to_string_without_validation(); +} + +// https://drafts.csswg.org/css-values-4/#serialize-a-calculation-tree +static String serialize_a_calculation_tree(CalculationNode const& root, CalculationContext const& context, CSSStyleValue::SerializationMode serialization_mode) +{ + // 1. Let root be the root node of the calculation tree. + // NOTE: Already the case. + + // 2. If root is a numeric value, or a non-math function, serialize root per the normal rules for it and return the result. + // FIXME: Support non-math functions in calculation trees. + if (root.type() == CalculationNode::Type::Numeric) + return root.to_string(); + + // 3. If root is anything but a Sum, Negate, Product, or Invert node, serialize a math function for the function + // corresponding to the node type, treating the node’s children as the function’s comma-separated calculation + // arguments, and return the result. + if (!first_is_one_of(root.type(), CalculationNode::Type::Sum, CalculationNode::Type::Product, CalculationNode::Type::Negate, CalculationNode::Type::Invert)) { + return serialize_a_math_function(root, context, serialization_mode); + } + + // 4. If root is a Negate node, let s be a string initially containing "(-1 * ". + if (root.type() == CalculationNode::Type::Negate) { + StringBuilder builder; + builder.append("(-1 * "sv); + + // Serialize root’s child, and append it to s. + builder.append(serialize_a_calculation_tree(root.children().first(), context, serialization_mode)); + + // Append ")" to s, then return it. + builder.append(')'); + return builder.to_string_without_validation(); + } + + // 5. If root is an Invert node, let s be a string initially containing "(1 / ". + if (root.type() == CalculationNode::Type::Invert) { + StringBuilder builder; + builder.append("(1 / "sv); + + // Serialize root’s child, and append it to s. + builder.append(serialize_a_calculation_tree(root.children().first(), context, serialization_mode)); + + // Append ")" to s, then return it. + builder.append(')'); + return builder.to_string_without_validation(); + } + + // 6. If root is a Sum node, let s be a string initially containing "(". + if (root.type() == CalculationNode::Type::Sum) { + StringBuilder builder; + builder.append('('); + + // FIXME: Sort root’s children. + auto sorted_children = root.children(); + + // Serialize root’s first child, and append it to s. + builder.append(serialize_a_calculation_tree(sorted_children.first(), context, serialization_mode)); + + // For each child of root beyond the first: + for (auto i = 1u; i < sorted_children.size(); ++i) { + auto& child = *sorted_children[i]; + + // 1. If child is a Negate node, append " - " to s, then serialize the Negate’s child and append the + // result to s. + if (child.type() == CalculationNode::Type::Negate) { + builder.append(" - "sv); + builder.append(serialize_a_calculation_tree(static_cast(child).child(), context, serialization_mode)); + } + + // 2. If child is a negative numeric value, append " - " to s, then serialize the negation of child as + // normal and append the result to s. + else if (child.type() == CalculationNode::Type::Numeric && static_cast(child).is_negative()) { + auto const& numeric_node = static_cast(child); + builder.append(" - "sv); + builder.append(serialize_a_calculation_tree(numeric_node.negated(context), context, serialization_mode)); + } + + // 3. Otherwise, append " + " to s, then serialize child and append the result to s. + else { + builder.append(" + "sv); + builder.append(serialize_a_calculation_tree(child, context, serialization_mode)); + } + } + + // Finally, append ")" to s and return it. + builder.append(')'); + return builder.to_string_without_validation(); + } + + // 7. If root is a Product node, let s be a string initially containing "(". + if (root.type() == CalculationNode::Type::Product) { + StringBuilder builder; + builder.append('('); + + // FIXME: Sort root’s children. + auto sorted_children = root.children(); + + // Serialize root’s first child, and append it to s. + builder.append(serialize_a_calculation_tree(sorted_children.first(), context, serialization_mode)); + + // For each child of root beyond the first: + for (auto i = 1u; i < sorted_children.size(); ++i) { + auto& child = *sorted_children[i]; + + // 1. If child is an Invert node, append " / " to s, then serialize the Invert’s child and append the result to s. + if (child.type() == CalculationNode::Type::Invert) { + builder.append(" / "sv); + builder.append(serialize_a_calculation_tree(static_cast(child).child(), context, serialization_mode)); + } + + // 2. Otherwise, append " * " to s, then serialize child and append the result to s. + else { + builder.append(" * "sv); + builder.append(serialize_a_calculation_tree(child, context, serialization_mode)); + } + } + + // Finally, append ")" to s and return it. + builder.append(')'); + return builder.to_string_without_validation(); + } + + VERIFY_NOT_REACHED(); +} + CalculationNode::CalculationNode(Type type, Optional numeric_type) : m_type(type) , m_numeric_type(move(numeric_type)) @@ -137,6 +369,59 @@ CalculationNode::CalculationNode(Type type, Optional numeric_typ CalculationNode::~CalculationNode() = default; +StringView CalculationNode::name() const +{ + switch (m_type) { + case Type::Min: + return "min"sv; + case Type::Max: + return "max"sv; + case Type::Clamp: + return "clamp"sv; + case Type::Abs: + return "abs"sv; + case Type::Sign: + return "sign"sv; + case Type::Sin: + return "sin"sv; + case Type::Cos: + return "cos"sv; + case Type::Tan: + return "tan"sv; + case Type::Asin: + return "asin"sv; + case Type::Acos: + return "acos"sv; + case Type::Atan: + return "atan"sv; + case Type::Atan2: + return "atan2"sv; + case Type::Pow: + return "pow"sv; + case Type::Sqrt: + return "sqrt"sv; + case Type::Hypot: + return "hypot"sv; + case Type::Log: + return "log"sv; + case Type::Exp: + return "exp"sv; + case Type::Round: + return "round"sv; + case Type::Mod: + return "mod"sv; + case Type::Rem: + return "rem"sv; + case Type::Numeric: + case Type::Sum: + case Type::Product: + case Type::Negate: + case Type::Invert: + return "calc"sv; + } + VERIFY_NOT_REACHED(); +} + static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleValue::CalculationResult::Value const& value, CalculationContext const& context) { // https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation @@ -334,6 +619,46 @@ RefPtr NumericCalculationNode::to_style_value(CalculationContext [](Time const& time) -> RefPtr { return TimeStyleValue::create(time); }); } +Optional NumericCalculationNode::infinite_or_nan_value() const +{ + auto raw_value = m_value.visit( + [](Number const& number) { return number.value(); }, + [](Percentage const& percentage) { return percentage.as_fraction(); }, + [](auto const& dimension) { return dimension.raw_value(); }); + + if (isnan(raw_value)) + return NonFiniteValue::NaN; + if (!isfinite(raw_value)) { + if (raw_value < 0) + return NonFiniteValue::NegativeInfinity; + return NonFiniteValue::Infinity; + } + + return {}; +} + +bool NumericCalculationNode::is_negative() const +{ + return m_value.visit( + [&](Number const& number) { return number.value() < 0; }, + [](Percentage const& percentage) { return percentage.value() < 0; }, + [](auto const& dimension) { return dimension.raw_value() < 0; }); +} + +NonnullRefPtr NumericCalculationNode::negated(CalculationContext const& context) const +{ + return value().visit( + [&](Percentage const& percentage) { + return create(Percentage(-percentage.value()), context); + }, + [&](Number const& number) { + return create(Number(number.type(), -number.value()), context); + }, + [&](T const& value) { + return create(T(-value.raw_value(), value.type()), context); + }); +} + void NumericCalculationNode::dump(StringBuilder& builder, int indent) const { builder.appendff("{: >{}}NUMERIC({})\n", "", indent, m_value.visit([](auto& it) { return it.to_string(); })); @@ -2474,10 +2799,9 @@ void CalculatedStyleValue::CalculationResult::invert() m_type = m_type->inverted(); } -String CalculatedStyleValue::to_string(SerializationMode) const +String CalculatedStyleValue::to_string(SerializationMode serialization_mode) const { - // FIXME: Implement this according to https://www.w3.org/TR/css-values-4/#calc-serialize once that stabilizes. - return MUST(String::formatted("calc({})", m_calculation->to_string())); + return serialize_a_math_function(m_calculation, m_context, serialization_mode); } bool CalculatedStyleValue::equals(CSSStyleValue const& other) const @@ -2821,19 +3145,8 @@ NonnullRefPtr simplify_a_calculation_tree(CalculationNode const auto const& root_negate = as(*root); auto const& child = root_negate.child(); // 1. If root’s child is a numeric value, return an equivalent numeric value, but with the value negated (0 - value). - if (child.type() == CalculationNode::Type::Numeric) { - auto const& numeric_child = as(child); - return numeric_child.value().visit( - [&](Percentage const& percentage) { - return NumericCalculationNode::create(Percentage(-percentage.value()), context); - }, - [&](Number const& number) { - return NumericCalculationNode::create(Number(number.type(), -number.value()), context); - }, - [&](T const& value) { - return NumericCalculationNode::create(T(-value.raw_value(), value.type()), context); - }); - } + if (child.type() == CalculationNode::Type::Numeric) + return as(child).negated(context); // 2. If root’s child is a Negate node, return the child’s child. if (child.type() == CalculationNode::Type::Negate) diff --git a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h index 9a2ab01c7bc..0da2aa642d7 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h @@ -223,6 +223,9 @@ public: return first_is_one_of(m_type, Type::Sum, Type::Product, Type::Negate, Type::Invert); } + StringView name() const; + virtual Vector> children() const = 0; + virtual String to_string() const = 0; Optional const& numeric_type() const { return m_numeric_type; } virtual bool contains_percentage() const = 0; @@ -242,6 +245,12 @@ private: Optional m_numeric_type; }; +enum class NonFiniteValue { + Infinity, + NegativeInfinity, + NaN, +}; + class NumericCalculationNode final : public CalculationNode { public: static NonnullRefPtr create(NumericValue, CalculationContext const&); @@ -256,8 +265,13 @@ public: RefPtr to_style_value(CalculationContext const&) const; + virtual Vector> children() const override { return {}; } NumericValue const& value() const { return m_value; } + Optional infinite_or_nan_value() const; + bool is_negative() const; + NonnullRefPtr negated(CalculationContext const&) const; + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -276,7 +290,7 @@ public: virtual CalculatedStyleValue::CalculationResult resolve(CalculationResolutionContext const&) const override; virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; - Vector> const& children() const { return m_values; } + virtual Vector> children() const override { return m_values; } virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -296,7 +310,7 @@ public: virtual CalculatedStyleValue::CalculationResult resolve(CalculationResolutionContext const&) const override; virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; - Vector> const& children() const { return m_values; } + virtual Vector> children() const override { return m_values; } virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -316,6 +330,7 @@ public: virtual CalculatedStyleValue::CalculationResult resolve(CalculationResolutionContext const&) const override; virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } CalculationNode const& child() const { return m_value; } virtual void dump(StringBuilder&, int indent) const override; @@ -336,6 +351,7 @@ public: virtual CalculatedStyleValue::CalculationResult resolve(CalculationResolutionContext const&) const override; virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } CalculationNode const& child() const { return m_value; } virtual void dump(StringBuilder&, int indent) const override; @@ -357,7 +373,7 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; - Vector> const& children() const { return m_values; } + virtual Vector> children() const override { return m_values; } virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -378,7 +394,7 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; - Vector> const& children() const { return m_values; } + virtual Vector> children() const override { return m_values; } virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -399,6 +415,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_min_value, m_center_value, m_max_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -420,6 +438,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -439,6 +459,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -458,6 +480,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -477,6 +501,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -496,6 +522,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -515,6 +543,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -534,6 +564,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -553,6 +585,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -572,6 +606,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_y, m_x } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -592,6 +628,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_x, m_y } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -612,6 +650,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -631,7 +671,7 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; - Vector> const& children() const { return m_values; } + virtual Vector> children() const override { return m_values; } virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -652,6 +692,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_x, m_y } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -672,6 +714,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_value } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -691,6 +735,10 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + // NOTE: This excludes the rounding strategy! + RoundingStrategy rounding_strategy() const { return m_strategy; } + virtual Vector> children() const override { return { { m_x, m_y } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -712,6 +760,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_x, m_y } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; @@ -732,6 +782,8 @@ public: virtual NonnullRefPtr with_simplified_children(CalculationContext const&, CalculationResolutionContext const&) const override; virtual Optional run_operation_if_possible(CalculationContext const&, CalculationResolutionContext const&) const override; + virtual Vector> children() const override { return { { m_x, m_y } }; } + virtual void dump(StringBuilder&, int indent) const override; virtual bool equals(CalculationNode const&) const override; diff --git a/Tests/LibWeb/Text/expected/position-serialization.txt b/Tests/LibWeb/Text/expected/position-serialization.txt index cb505b6ee40..c095da21a96 100644 --- a/Tests/LibWeb/Text/expected/position-serialization.txt +++ b/Tests/LibWeb/Text/expected/position-serialization.txt @@ -11,8 +11,8 @@ computed: 10px 20% inline: 10px top computed: 10px 0% inline: right 10px bottom 20% -computed: calc(100% + (0 - 10px)) 80% +computed: calc(100% - 10px) 80% inline: center center, left bottom computed: 50% 50%, 0% 100% inline: left 10px bottom 20%, right 10px top 20% -computed: 10px 80%, calc(100% + (0 - 10px)) 20% +computed: 10px 80%, calc(100% - 10px) 20% diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-size-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-size-valid.txt index befb31584b6..af70b0b95d9 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-size-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-size-valid.txt @@ -2,8 +2,7 @@ Harness status: OK Found 13 tests -12 Pass -1 Fail +13 Pass Pass e.style['font-size'] = "xx-small" should set the property value Pass e.style['font-size'] = "x-small" should set the property value Pass e.style['font-size'] = "small" should set the property value @@ -16,4 +15,4 @@ Pass e.style['font-size'] = "larger" should set the property value Pass e.style['font-size'] = "smaller" should set the property value Pass e.style['font-size'] = "10px" should set the property value Pass e.style['font-size'] = "20%" should set the property value -Fail e.style['font-size'] = "calc(30% - 40px)" should set the property value \ No newline at end of file +Pass e.style['font-size'] = "calc(30% - 40px)" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/height-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/height-valid.txt index a8ba9c1b9b0..f733531ca88 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/height-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/height-valid.txt @@ -2,15 +2,14 @@ Harness status: OK Found 10 tests -8 Pass -2 Fail +10 Pass Pass e.style['height'] = "auto" should set the property value Pass e.style['height'] = "min-content" should set the property value Pass e.style['height'] = "max-content" should set the property value Pass e.style['height'] = "0" should set the property value Pass e.style['height'] = "10%" should set the property value Pass e.style['height'] = "0.5em" should set the property value -Fail e.style['height'] = "calc(10% - 0.5em)" should set the property value +Pass e.style['height'] = "calc(10% - 0.5em)" should set the property value Pass e.style['height'] = "fit-content(10%)" should set the property value Pass e.style['height'] = "fit-content(0.5em)" should set the property value -Fail e.style['height'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file +Pass e.style['height'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-height-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-height-valid.txt index 9590c381552..c12ca49d65f 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-height-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-height-valid.txt @@ -2,15 +2,14 @@ Harness status: OK Found 10 tests -8 Pass -2 Fail +10 Pass Pass e.style['max-height'] = "none" should set the property value Pass e.style['max-height'] = "min-content" should set the property value Pass e.style['max-height'] = "max-content" should set the property value Pass e.style['max-height'] = "0" should set the property value Pass e.style['max-height'] = "10%" should set the property value Pass e.style['max-height'] = "0.5em" should set the property value -Fail e.style['max-height'] = "calc(10% - 0.5em)" should set the property value +Pass e.style['max-height'] = "calc(10% - 0.5em)" should set the property value Pass e.style['max-height'] = "fit-content(10%)" should set the property value Pass e.style['max-height'] = "fit-content(0.5em)" should set the property value -Fail e.style['max-height'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file +Pass e.style['max-height'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-width-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-width-valid.txt index 7600c640825..a2ef661346c 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-width-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/max-width-valid.txt @@ -2,15 +2,14 @@ Harness status: OK Found 10 tests -8 Pass -2 Fail +10 Pass Pass e.style['max-width'] = "none" should set the property value Pass e.style['max-width'] = "min-content" should set the property value Pass e.style['max-width'] = "max-content" should set the property value Pass e.style['max-width'] = "0" should set the property value Pass e.style['max-width'] = "10%" should set the property value Pass e.style['max-width'] = "0.5em" should set the property value -Fail e.style['max-width'] = "calc(10% - 0.5em)" should set the property value +Pass e.style['max-width'] = "calc(10% - 0.5em)" should set the property value Pass e.style['max-width'] = "fit-content(10%)" should set the property value Pass e.style['max-width'] = "fit-content(0.5em)" should set the property value -Fail e.style['max-width'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file +Pass e.style['max-width'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-height-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-height-valid.txt index 98815e6b642..560803609fb 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-height-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-height-valid.txt @@ -2,15 +2,14 @@ Harness status: OK Found 10 tests -8 Pass -2 Fail +10 Pass Pass e.style['min-height'] = "auto" should set the property value Pass e.style['min-height'] = "min-content" should set the property value Pass e.style['min-height'] = "max-content" should set the property value Pass e.style['min-height'] = "0" should set the property value Pass e.style['min-height'] = "10%" should set the property value Pass e.style['min-height'] = "0.5em" should set the property value -Fail e.style['min-height'] = "calc(10% - 0.5em)" should set the property value +Pass e.style['min-height'] = "calc(10% - 0.5em)" should set the property value Pass e.style['min-height'] = "fit-content(10%)" should set the property value Pass e.style['min-height'] = "fit-content(0.5em)" should set the property value -Fail e.style['min-height'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file +Pass e.style['min-height'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-width-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-width-valid.txt index 9c1cc7f6238..5d4cd27cbf6 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-width-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/min-width-valid.txt @@ -2,15 +2,14 @@ Harness status: OK Found 10 tests -8 Pass -2 Fail +10 Pass Pass e.style['min-width'] = "auto" should set the property value Pass e.style['min-width'] = "min-content" should set the property value Pass e.style['min-width'] = "max-content" should set the property value Pass e.style['min-width'] = "0" should set the property value Pass e.style['min-width'] = "10%" should set the property value Pass e.style['min-width'] = "0.5em" should set the property value -Fail e.style['min-width'] = "calc(10% - 0.5em)" should set the property value +Pass e.style['min-width'] = "calc(10% - 0.5em)" should set the property value Pass e.style['min-width'] = "fit-content(10%)" should set the property value Pass e.style['min-width'] = "fit-content(0.5em)" should set the property value -Fail e.style['min-width'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file +Pass e.style['min-width'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/width-valid.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/width-valid.txt index a6bc3d9de7b..3ebcd0710c2 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/width-valid.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-sizing/parsing/width-valid.txt @@ -2,15 +2,14 @@ Harness status: OK Found 10 tests -8 Pass -2 Fail +10 Pass Pass e.style['width'] = "auto" should set the property value Pass e.style['width'] = "min-content" should set the property value Pass e.style['width'] = "max-content" should set the property value Pass e.style['width'] = "0" should set the property value Pass e.style['width'] = "10%" should set the property value Pass e.style['width'] = "0.5em" should set the property value -Fail e.style['width'] = "calc(10% - 0.5em)" should set the property value +Pass e.style['width'] = "calc(10% - 0.5em)" should set the property value Pass e.style['width'] = "fit-content(10%)" should set the property value Pass e.style['width'] = "fit-content(0.5em)" should set the property value -Fail e.style['width'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file +Pass e.style['width'] = "fit-content(calc(10% - 0.5em))" should set the property value \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-values/calc-serialization-002.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-values/calc-serialization-002.txt index 3155233ec4b..f8cf7ecdeb6 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/css/css-values/calc-serialization-002.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-values/calc-serialization-002.txt @@ -2,8 +2,8 @@ Harness status: OK Found 24 tests -6 Pass -18 Fail +8 Pass +16 Fail Fail testing calc(1vh + 2px + 3%) Pass testing calc(4px + 1vh) Fail testing calc(5px + 6em + 1vh) @@ -22,9 +22,9 @@ Fail testing calc(1vh - 7px) Fail testing calc(5ex - 9ex) Fail testing calc(-80px + 25.4mm) Pass testing calc(2 * (10px + 1rem)) -Fail testing calc(2 * (10px - 1rem)) +Pass testing calc(2 * (10px - 1rem)) Pass testing calc((10px + 1rem) / 2) -Fail testing calc(2 * (min(10px, 20%) + max(1rem, 2%))) +Pass testing calc(2 * (min(10px, 20%) + max(1rem, 2%))) Fail testing calc((min(10px, 20%) + max(1rem, 2%)) * 2) Fail testing calc(1vmin - 14%) Fail testing calc(4 * 3px + 4pc / 8) \ No newline at end of file