Skip to content

Commit

Permalink
LibWeb/CSS: Recalculate calc() numeric type when resolving percentages
Browse files Browse the repository at this point in the history
Previously, `percentage_of` would be called on the previous value,
potentially changing its numeric type, yet this potential change
was never reflected as the old numeric type was always used. Now,
the numeric type will be re-calculated every time after the
percentage is resolved. As well, VERIFY checks have been placed to
uphold the requirements for the numeric types to match what the
actual values are.
  • Loading branch information
Jaycadox authored and AtkinsSJ committed Jan 4, 2025
1 parent 938ffe1 commit db58986
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 4 deletions.
19 changes: 15 additions & 4 deletions Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ CalculationNode::CalculationNode(Type type, Optional<CSSNumericType> numeric_typ

CalculationNode::~CalculationNode() = default;

NonnullOwnPtr<NumericCalculationNode> NumericCalculationNode::create(NumericValue value, Optional<ValueType> percentage_resolved_type)
static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleValue::CalculationResult::Value const& value, Optional<ValueType> percentage_resolved_type)
{
// 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.
// (Unless otherwise specified, the type’s associated percent hint is null.)
auto numeric_type = value.visit(
return value.visit(
[](Number const&) {
// -> <number>
// -> <integer>
Expand Down Expand Up @@ -172,7 +172,11 @@ NonnullOwnPtr<NumericCalculationNode> NumericCalculationNode::create(NumericValu
// result.set_percent_hint(CSSNumericType::BaseType::Percent);
return result;
});
}

NonnullOwnPtr<NumericCalculationNode> NumericCalculationNode::create(NumericValue value, Optional<ValueType> percentage_resolved_type)
{
auto numeric_type = numeric_type_from_calculated_style_value(value, percentage_resolved_type);
return adopt_own(*new (nothrow) NumericCalculationNode(move(value), numeric_type));
}

Expand Down Expand Up @@ -200,11 +204,13 @@ CalculatedStyleValue::CalculationResult NumericCalculationNode::resolve(Optional
// NOTE: Depending on whether percentage_basis is set, the caller of resolve() is expecting a raw percentage or
// resolved type.
return percentage_basis.visit(
[&](Empty const&) -> CalculatedStyleValue::CalculationResult {
[&](Empty const&) {
VERIFY(numeric_type_from_calculated_style_value(m_value, {}) == numeric_type());
return CalculatedStyleValue::CalculationResult::from_value(m_value, resolution_context, numeric_type());
},
[&](auto const& value) {
return CalculatedStyleValue::CalculationResult::from_value(value.percentage_of(m_value.get<Percentage>()), resolution_context, numeric_type());
auto const calculated_value = value.percentage_of(m_value.get<Percentage>());
return CalculatedStyleValue::CalculationResult::from_value(calculated_value, resolution_context, numeric_type_from_calculated_style_value(calculated_value, {}));
});
}

Expand Down Expand Up @@ -1730,6 +1736,11 @@ bool RemCalculationNode::equals(CalculationNode const& other) const

CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalculationResult::from_value(Value const& value, Optional<Length::ResolutionContext const&> context, Optional<CSSNumericType> numeric_type)
{
auto const expected_numeric_type = numeric_type_from_calculated_style_value(value, {});
if (numeric_type.has_value()) {
VERIFY(numeric_type.value() == expected_numeric_type);
}

auto number = value.visit(
[](Number const& number) { return number.value(); },
[](Angle const& angle) { return angle.to_degrees(); },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PASS! (Didn't crash)
12 changes: 12 additions & 0 deletions Tests/LibWeb/Text/input/css/singular-percentage-calc-crash.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script src="../include.js"></script>
<style>
div {
transform: translateX(calc(10%))
}
</style>
<div></div>
<script>
test(() => {
println(`PASS! (Didn't crash)`);
});
</script>

0 comments on commit db58986

Please sign in to comment.