LibWeb/CSS: Give calc() a CalculationContext for resolving percentages

This is passed in at construction, meaning we will be able to refer to
it later, when we're no longer inside the Parser.
This commit is contained in:
Sam Atkins 2025-01-08 16:14:17 +00:00
commit 4efdb76857
Notes: github-actions[bot] 2025-01-13 11:00:31 +00:00
8 changed files with 111 additions and 84 deletions

View file

@ -109,7 +109,7 @@ CalculationNode::CalculationNode(Type type, Optional<CSSNumericType> numeric_typ
CalculationNode::~CalculationNode() = default;
static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleValue::CalculationResult::Value const& value, Optional<ValueType> percentage_resolved_type)
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
// Anything else is a terminal value, whose type is determined based on its CSS type.
@ -152,14 +152,14 @@ static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleVa
return CSSNumericType { CSSNumericType::BaseType::Flex, 1 };
},
// NOTE: <calc-constant> is a separate node type. (FIXME: Should it be?)
[&percentage_resolved_type](Percentage const&) {
[&context](Percentage const&) {
// -> <percentage>
// If, in the context in which the math function containing this calculation is placed,
// <percentage>s are resolved relative to another type of value (such as in width,
// where <percentage> is resolved against a <length>), and that other type is not <number>,
// the type is determined as the other type, but with a percent hint set to that other type.
if (percentage_resolved_type.has_value() && percentage_resolved_type != ValueType::Number && percentage_resolved_type != ValueType::Percentage) {
auto base_type = CSSNumericType::base_type_from_value_type(*percentage_resolved_type);
if (context.percentages_resolve_as.has_value() && context.percentages_resolve_as != ValueType::Number && context.percentages_resolve_as != ValueType::Percentage) {
auto base_type = CSSNumericType::base_type_from_value_type(*context.percentages_resolve_as);
VERIFY(base_type.has_value());
auto result = CSSNumericType { base_type.value(), 1 };
result.set_percent_hint(base_type);
@ -174,9 +174,9 @@ static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleVa
});
}
NonnullOwnPtr<NumericCalculationNode> NumericCalculationNode::create(NumericValue value, Optional<ValueType> percentage_resolved_type)
NonnullOwnPtr<NumericCalculationNode> NumericCalculationNode::create(NumericValue value, CalculationContext const& context)
{
auto numeric_type = numeric_type_from_calculated_style_value(value, percentage_resolved_type);
auto numeric_type = numeric_type_from_calculated_style_value(value, context);
return adopt_own(*new (nothrow) NumericCalculationNode(move(value), numeric_type));
}

View file

@ -24,6 +24,11 @@ namespace Web::CSS {
class CalculationNode;
// https://drafts.csswg.org/css-values-4/#ref-for-calc-calculation%E2%91%A2%E2%91%A7
struct CalculationContext {
Optional<ValueType> percentages_resolve_as {};
};
class CalculatedStyleValue : public CSSStyleValue {
public:
using PercentageBasis = Variant<Empty, Angle, Flex, Frequency, Length, Time>;
@ -56,9 +61,9 @@ public:
Optional<CSSNumericType> m_type;
};
static ValueComparingNonnullRefPtr<CalculatedStyleValue> create(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type)
static ValueComparingNonnullRefPtr<CalculatedStyleValue> create(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type, CalculationContext context)
{
return adopt_ref(*new (nothrow) CalculatedStyleValue(move(calculation), resolved_type));
return adopt_ref(*new (nothrow) CalculatedStyleValue(move(calculation), move(resolved_type), move(context)));
}
virtual String to_string(SerializationMode) const override;
@ -113,15 +118,17 @@ public:
String dump() const;
private:
explicit CalculatedStyleValue(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type)
explicit CalculatedStyleValue(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type, CalculationContext context)
: CSSStyleValue(Type::Calculated)
, m_resolved_type(resolved_type)
, m_resolved_type(move(resolved_type))
, m_calculation(move(calculation))
, m_context(move(context))
{
}
CSSNumericType m_resolved_type;
NonnullOwnPtr<CalculationNode> m_calculation;
CalculationContext m_context;
};
// https://www.w3.org/TR/css-values-4/#calculation-tree
@ -258,7 +265,7 @@ private:
class NumericCalculationNode final : public CalculationNode {
public:
static NonnullOwnPtr<NumericCalculationNode> create(NumericValue, Optional<ValueType> percentage_resolved_type = {});
static NonnullOwnPtr<NumericCalculationNode> create(NumericValue, CalculationContext const&);
~NumericCalculationNode();
virtual String to_string() const override;

View file

@ -16,15 +16,19 @@ String EdgeStyleValue::to_string(SerializationMode mode) const
auto flipped_percentage = 100 - offset().percentage().value();
return Percentage(flipped_percentage).to_string();
}
// FIXME: Figure out how to get the proper calculation context here
CalculationContext context = {};
Vector<NonnullOwnPtr<CalculationNode>> sum_parts;
sum_parts.append(NumericCalculationNode::create(Percentage(100)));
sum_parts.append(NumericCalculationNode::create(Percentage(100), context));
if (offset().is_length()) {
sum_parts.append(NegateCalculationNode::create(NumericCalculationNode::create(offset().length())));
sum_parts.append(NegateCalculationNode::create(NumericCalculationNode::create(offset().length(), context)));
} else {
// FIXME: Flip calculated offsets (convert CalculatedStyleValue to CalculationNode, then negate and append)
return to_string(CSSStyleValue::SerializationMode::Normal);
}
auto flipped_absolute = CalculatedStyleValue::create(SumCalculationNode::create(move(sum_parts)), CSSNumericType(CSSNumericType::BaseType::Length, 1));
auto flipped_absolute = CalculatedStyleValue::create(SumCalculationNode::create(move(sum_parts)), CSSNumericType(CSSNumericType::BaseType::Length, 1), context);
return flipped_absolute->to_string(mode);
}
return offset().to_string();