LibWeb/CSS: Use CalcSV's context to determine what percentages are

This lets us implement the `matches_number()` and `matches_dimension()`
methods of `CSSNumericType` to spec, instead of being an ad-hoc hack.
This commit is contained in:
Sam Atkins 2025-01-09 17:23:20 +00:00
commit 4e1aa96dce
Notes: github-actions[bot] 2025-01-13 11:00:10 +00:00
5 changed files with 98 additions and 79 deletions

View file

@ -5,11 +5,9 @@
*/ */
#include "CSSNumericType.h" #include "CSSNumericType.h"
#include <AK/HashMap.h>
#include <LibWeb/CSS/Angle.h> #include <LibWeb/CSS/Angle.h>
#include <LibWeb/CSS/Frequency.h> #include <LibWeb/CSS/Frequency.h>
#include <LibWeb/CSS/Length.h> #include <LibWeb/CSS/Length.h>
#include <LibWeb/CSS/Percentage.h>
#include <LibWeb/CSS/Resolution.h> #include <LibWeb/CSS/Resolution.h>
#include <LibWeb/CSS/Time.h> #include <LibWeb/CSS/Time.h>
@ -374,26 +372,47 @@ Optional<CSSNumericType::BaseType> CSSNumericType::entry_with_value_1_while_all_
return result; return result;
} }
static bool matches(CSSNumericType::BaseType base_type, ValueType value_type)
{
switch (base_type) {
case CSSNumericType::BaseType::Length:
return value_type == ValueType::Length;
case CSSNumericType::BaseType::Angle:
return value_type == ValueType::Angle;
case CSSNumericType::BaseType::Time:
return value_type == ValueType::Time;
case CSSNumericType::BaseType::Frequency:
return value_type == ValueType::Frequency;
case CSSNumericType::BaseType::Resolution:
return value_type == ValueType::Resolution;
case CSSNumericType::BaseType::Flex:
return value_type == ValueType::Flex;
case CSSNumericType::BaseType::Percent:
return value_type == ValueType::Percentage;
case CSSNumericType::BaseType::__Count:
default:
return false;
}
}
// https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match // https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match
bool CSSNumericType::matches_dimension(BaseType type) const bool CSSNumericType::matches_dimension(BaseType type, Optional<ValueType> percentages_resolve_as) const
{ {
// A type matches <length> if its only non-zero entry is «[ "length" → 1 ]». // A type matches <length> if its only non-zero entry is «[ "length" → 1 ]».
// Similarly for <angle>, <time>, <frequency>, <resolution>, and <flex>. // Similarly for <angle>, <time>, <frequency>, <resolution>, and <flex>.
// if (entry_with_value_1_while_all_others_are_0() != type)
return false;
// If the context in which the value is used allows <percentage> values, and those percentages are resolved // If the context in which the value is used allows <percentage> values, and those percentages are resolved
// against another type, then for the type to be considered matching it must either have a null percent hint, // against another type, then for the type to be considered matching it must either have a null percent hint,
// or the percent hint must match the other type. // or the percent hint must match the other type.
// if (percentages_resolve_as.has_value())
return !percent_hint().has_value() || matches(*percent_hint(), *percentages_resolve_as);
// If the context does not allow <percentage> values to be mixed with <length>/etc values (or doesnt allow // If the context does not allow <percentage> values to be mixed with <length>/etc values (or doesnt allow
// <percentage> values at all, such as border-width), then for the type to be considered matching the percent // <percentage> values at all, such as border-width), then for the type to be considered matching the percent
// hint must be null. // hint must be null.
return !percent_hint().has_value();
// FIXME: Somehow we need to know what type percentages would be resolved against.
// I'm not at all sure if this check is correct.
if (percent_hint().has_value() && percent_hint() != type)
return false;
return entry_with_value_1_while_all_others_are_0() == type;
} }
// https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match // https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match
@ -408,34 +427,17 @@ bool CSSNumericType::matches_percentage() const
} }
// https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match // https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match
bool CSSNumericType::matches_dimension_percentage(BaseType type) const bool CSSNumericType::matches_dimension_percentage(BaseType type, Optional<ValueType> percentages_resolve_as) const
{ {
// A type matches <length-percentage> if it matches <length> or matches <percentage>. // A type matches <length-percentage> if it matches <length> or matches <percentage>.
// Same for <angle-percentage>, <time-percentage>, etc. // Same for <angle-percentage>, <time-percentage>, etc.
return matches_percentage() || matches_dimension(type); return matches_percentage() || matches_dimension(type, percentages_resolve_as);
} }
// https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match // https://drafts.css-houdini.org/css-typed-om-1/#cssnumericvalue-match
bool CSSNumericType::matches_number() const bool CSSNumericType::matches_number(Optional<ValueType> percentages_resolve_as) const
{ {
// A type matches <number> if it has no non-zero entries. // A type matches <number> if it has no non-zero entries.
//
// If the context in which the value is used allows <percentage> values, and those percentages are resolved
// against a type other than <number>, then for the type to be considered matching the percent hint must
// either be null or match the other type.
//
// If the context allows <percentage> values, but either doesnt resolve them against another type or resolves
// them against a <number>, then for the type to be considered matching the percent hint must either be null
// or "percent".
//
// If the context does not allow <percentage> values, then for the type to be considered matching the percent
// hint must be null.
// FIXME: Somehow we need to know what type percentages would be resolved against.
// For now, just require no percent hint.
if (percent_hint().has_value())
return false;
for (auto i = 0; i < to_underlying(BaseType::__Count); ++i) { for (auto i = 0; i < to_underlying(BaseType::__Count); ++i) {
auto base_type = static_cast<BaseType>(i); auto base_type = static_cast<BaseType>(i);
auto type_exponent = exponent(base_type); auto type_exponent = exponent(base_type);
@ -443,7 +445,21 @@ bool CSSNumericType::matches_number() const
return false; return false;
} }
return true; // If the context in which the value is used allows <percentage> values, and those percentages are resolved
// against a type other than <number>, then for the type to be considered matching the percent hint must
// either be null or match the other type.
if (percentages_resolve_as.has_value() && percentages_resolve_as != ValueType::Number)
return !percent_hint().has_value() || matches(*percent_hint(), *percentages_resolve_as);
// If the context allows <percentage> values, but either doesnt resolve them against another type or resolves
// them against a <number>, then for the type to be considered matching the percent hint must either be null
// or "percent".
if (percentages_resolve_as == ValueType::Number)
return !percent_hint().has_value() || percent_hint() == BaseType::Percent;
// If the context does not allow <percentage> values, then for the type to be considered matching the percent
// hint must be null.
return !percent_hint().has_value();
} }
bool CSSNumericType::matches_dimension() const bool CSSNumericType::matches_dimension() const

View file

@ -68,18 +68,18 @@ public:
Optional<CSSNumericType> consistent_type(CSSNumericType const& other) const; Optional<CSSNumericType> consistent_type(CSSNumericType const& other) const;
Optional<CSSNumericType> made_consistent_with(CSSNumericType const& other) const; Optional<CSSNumericType> made_consistent_with(CSSNumericType const& other) const;
bool matches_angle() const { return matches_dimension(BaseType::Angle); } bool matches_angle(Optional<ValueType> percentages_resolve_as) const { return matches_dimension(BaseType::Angle, percentages_resolve_as); }
bool matches_angle_percentage() const { return matches_dimension_percentage(BaseType::Angle); } bool matches_angle_percentage(Optional<ValueType> percentages_resolve_as) const { return matches_dimension_percentage(BaseType::Angle, percentages_resolve_as); }
bool matches_flex() const { return matches_dimension(BaseType::Flex); } bool matches_flex(Optional<ValueType> percentages_resolve_as) const { return matches_dimension(BaseType::Flex, percentages_resolve_as); }
bool matches_frequency() const { return matches_dimension(BaseType::Frequency); } bool matches_frequency(Optional<ValueType> percentages_resolve_as) const { return matches_dimension(BaseType::Frequency, percentages_resolve_as); }
bool matches_frequency_percentage() const { return matches_dimension_percentage(BaseType::Frequency); } bool matches_frequency_percentage(Optional<ValueType> percentages_resolve_as) const { return matches_dimension_percentage(BaseType::Frequency, percentages_resolve_as); }
bool matches_length() const { return matches_dimension(BaseType::Length); } bool matches_length(Optional<ValueType> percentages_resolve_as) const { return matches_dimension(BaseType::Length, percentages_resolve_as); }
bool matches_length_percentage() const { return matches_dimension_percentage(BaseType::Length); } bool matches_length_percentage(Optional<ValueType> percentages_resolve_as) const { return matches_dimension_percentage(BaseType::Length, percentages_resolve_as); }
bool matches_number() const; bool matches_number(Optional<ValueType> percentages_resolve_as) const;
bool matches_percentage() const; bool matches_percentage() const;
bool matches_resolution() const { return matches_dimension(BaseType::Resolution); } bool matches_resolution(Optional<ValueType> percentages_resolve_as) const { return matches_dimension(BaseType::Resolution, percentages_resolve_as); }
bool matches_time() const { return matches_dimension(BaseType::Time); } bool matches_time(Optional<ValueType> percentages_resolve_as) const { return matches_dimension(BaseType::Time, percentages_resolve_as); }
bool matches_time_percentage() const { return matches_dimension_percentage(BaseType::Time); } bool matches_time_percentage(Optional<ValueType> percentages_resolve_as) const { return matches_dimension_percentage(BaseType::Time, percentages_resolve_as); }
bool matches_dimension() const; bool matches_dimension() const;
@ -104,8 +104,8 @@ private:
void copy_all_entries_from(CSSNumericType const& other, SkipIfAlreadyPresent); void copy_all_entries_from(CSSNumericType const& other, SkipIfAlreadyPresent);
Optional<BaseType> entry_with_value_1_while_all_others_are_0() const; Optional<BaseType> entry_with_value_1_while_all_others_are_0() const;
bool matches_dimension(BaseType) const; bool matches_dimension(BaseType, Optional<ValueType> percentages_resolve_as) const;
bool matches_dimension_percentage(BaseType) const; bool matches_dimension_percentage(BaseType, Optional<ValueType> percentages_resolve_as) const;
Array<Optional<i32>, to_underlying(BaseType::__Count)> m_type_exponents; Array<Optional<i32>, to_underlying(BaseType::__Count)> m_type_exponents;
Optional<BaseType> m_percent_hint; Optional<BaseType> m_percent_hint;

View file

@ -1825,7 +1825,7 @@ bool CalculatedStyleValue::equals(CSSStyleValue const& other) const
Optional<Angle> CalculatedStyleValue::resolve_angle() const Optional<Angle> CalculatedStyleValue::resolve_angle() const
{ {
auto result = m_calculation->resolve({}, {}); auto result = m_calculation->resolve({}, {});
if (result.type().has_value() && result.type()->matches_angle()) if (result.type().has_value() && result.type()->matches_angle(m_context.percentages_resolve_as))
return Angle::make_degrees(result.value()); return Angle::make_degrees(result.value());
return {}; return {};
} }
@ -1838,7 +1838,7 @@ Optional<Angle> CalculatedStyleValue::resolve_angle(Layout::Node const& layout_n
Optional<Angle> CalculatedStyleValue::resolve_angle(Length::ResolutionContext const& context) const Optional<Angle> CalculatedStyleValue::resolve_angle(Length::ResolutionContext const& context) const
{ {
auto result = m_calculation->resolve(context, {}); auto result = m_calculation->resolve(context, {});
if (result.type().has_value() && result.type()->matches_angle()) if (result.type().has_value() && result.type()->matches_angle(m_context.percentages_resolve_as))
return Angle::make_degrees(result.value()); return Angle::make_degrees(result.value());
return {}; return {};
} }
@ -1846,7 +1846,7 @@ Optional<Angle> CalculatedStyleValue::resolve_angle(Length::ResolutionContext co
Optional<Angle> CalculatedStyleValue::resolve_angle_percentage(Angle const& percentage_basis) const Optional<Angle> CalculatedStyleValue::resolve_angle_percentage(Angle const& percentage_basis) const
{ {
auto result = m_calculation->resolve({}, percentage_basis); auto result = m_calculation->resolve({}, percentage_basis);
if (result.type().has_value() && result.type()->matches_angle()) if (result.type().has_value() && result.type()->matches_angle(m_context.percentages_resolve_as))
return Angle::make_degrees(result.value()); return Angle::make_degrees(result.value());
return {}; return {};
} }
@ -1854,7 +1854,7 @@ Optional<Angle> CalculatedStyleValue::resolve_angle_percentage(Angle const& perc
Optional<Flex> CalculatedStyleValue::resolve_flex() const Optional<Flex> CalculatedStyleValue::resolve_flex() const
{ {
auto result = m_calculation->resolve({}, {}); auto result = m_calculation->resolve({}, {});
if (result.type().has_value() && result.type()->matches_flex()) if (result.type().has_value() && result.type()->matches_flex(m_context.percentages_resolve_as))
return Flex::make_fr(result.value()); return Flex::make_fr(result.value());
return {}; return {};
} }
@ -1862,7 +1862,7 @@ Optional<Flex> CalculatedStyleValue::resolve_flex() const
Optional<Frequency> CalculatedStyleValue::resolve_frequency() const Optional<Frequency> CalculatedStyleValue::resolve_frequency() const
{ {
auto result = m_calculation->resolve({}, {}); auto result = m_calculation->resolve({}, {});
if (result.type().has_value() && result.type()->matches_frequency()) if (result.type().has_value() && result.type()->matches_frequency(m_context.percentages_resolve_as))
return Frequency::make_hertz(result.value()); return Frequency::make_hertz(result.value());
return {}; return {};
} }
@ -1870,7 +1870,7 @@ Optional<Frequency> CalculatedStyleValue::resolve_frequency() const
Optional<Frequency> CalculatedStyleValue::resolve_frequency_percentage(Frequency const& percentage_basis) const Optional<Frequency> CalculatedStyleValue::resolve_frequency_percentage(Frequency const& percentage_basis) const
{ {
auto result = m_calculation->resolve({}, percentage_basis); auto result = m_calculation->resolve({}, percentage_basis);
if (result.type().has_value() && result.type()->matches_frequency()) if (result.type().has_value() && result.type()->matches_frequency(m_context.percentages_resolve_as))
return Frequency::make_hertz(result.value()); return Frequency::make_hertz(result.value());
return {}; return {};
} }
@ -1878,7 +1878,7 @@ Optional<Frequency> CalculatedStyleValue::resolve_frequency_percentage(Frequency
Optional<Length> CalculatedStyleValue::resolve_length(Length::ResolutionContext const& context) const Optional<Length> CalculatedStyleValue::resolve_length(Length::ResolutionContext const& context) const
{ {
auto result = m_calculation->resolve(context, {}); auto result = m_calculation->resolve(context, {});
if (result.type().has_value() && result.type()->matches_length()) if (result.type().has_value() && result.type()->matches_length(m_context.percentages_resolve_as))
return Length::make_px(CSSPixels { result.value() }); return Length::make_px(CSSPixels { result.value() });
return {}; return {};
} }
@ -1901,7 +1901,7 @@ Optional<Length> CalculatedStyleValue::resolve_length_percentage(Layout::Node co
Optional<Length> CalculatedStyleValue::resolve_length_percentage(Length::ResolutionContext const& resolution_context, Length const& percentage_basis) const Optional<Length> CalculatedStyleValue::resolve_length_percentage(Length::ResolutionContext const& resolution_context, Length const& percentage_basis) const
{ {
auto result = m_calculation->resolve(resolution_context, percentage_basis); auto result = m_calculation->resolve(resolution_context, percentage_basis);
if (result.type().has_value() && result.type()->matches_length()) if (result.type().has_value() && result.type()->matches_length(m_context.percentages_resolve_as))
return Length::make_px(CSSPixels { result.value() }); return Length::make_px(CSSPixels { result.value() });
return {}; return {};
} }
@ -1917,7 +1917,7 @@ Optional<Percentage> CalculatedStyleValue::resolve_percentage() const
Optional<Resolution> CalculatedStyleValue::resolve_resolution() const Optional<Resolution> CalculatedStyleValue::resolve_resolution() const
{ {
auto result = m_calculation->resolve({}, {}); auto result = m_calculation->resolve({}, {});
if (result.type().has_value() && result.type()->matches_resolution()) if (result.type().has_value() && result.type()->matches_resolution(m_context.percentages_resolve_as))
return Resolution::make_dots_per_pixel(result.value()); return Resolution::make_dots_per_pixel(result.value());
return {}; return {};
} }
@ -1925,7 +1925,7 @@ Optional<Resolution> CalculatedStyleValue::resolve_resolution() const
Optional<Time> CalculatedStyleValue::resolve_time() const Optional<Time> CalculatedStyleValue::resolve_time() const
{ {
auto result = m_calculation->resolve({}, {}); auto result = m_calculation->resolve({}, {});
if (result.type().has_value() && result.type()->matches_time()) if (result.type().has_value() && result.type()->matches_time(m_context.percentages_resolve_as))
return Time::make_seconds(result.value()); return Time::make_seconds(result.value());
return {}; return {};
} }
@ -1933,7 +1933,7 @@ Optional<Time> CalculatedStyleValue::resolve_time() const
Optional<Time> CalculatedStyleValue::resolve_time_percentage(Time const& percentage_basis) const Optional<Time> CalculatedStyleValue::resolve_time_percentage(Time const& percentage_basis) const
{ {
auto result = m_calculation->resolve({}, percentage_basis); auto result = m_calculation->resolve({}, percentage_basis);
if (result.type().has_value() && result.type()->matches_time()) if (result.type().has_value() && result.type()->matches_time(m_context.percentages_resolve_as))
return Time::make_seconds(result.value()); return Time::make_seconds(result.value());
return {}; return {};
} }
@ -1941,7 +1941,7 @@ Optional<Time> CalculatedStyleValue::resolve_time_percentage(Time const& percent
Optional<double> CalculatedStyleValue::resolve_number() const Optional<double> CalculatedStyleValue::resolve_number() const
{ {
auto result = m_calculation->resolve({}, {}); auto result = m_calculation->resolve({}, {});
if (result.type().has_value() && result.type()->matches_number()) if (result.type().has_value() && result.type()->matches_number(m_context.percentages_resolve_as))
return result.value(); return result.value();
return {}; return {};
} }
@ -1949,7 +1949,7 @@ Optional<double> CalculatedStyleValue::resolve_number() const
Optional<double> CalculatedStyleValue::resolve_number(Length::ResolutionContext const& context) const Optional<double> CalculatedStyleValue::resolve_number(Length::ResolutionContext const& context) const
{ {
auto result = m_calculation->resolve(context, {}); auto result = m_calculation->resolve(context, {});
if (result.type().has_value() && result.type()->matches_number()) if (result.type().has_value() && result.type()->matches_number(m_context.percentages_resolve_as))
return result.value(); return result.value();
return {}; return {};
} }
@ -1962,7 +1962,7 @@ Optional<double> CalculatedStyleValue::resolve_number(Layout::Node const& layout
Optional<i64> CalculatedStyleValue::resolve_integer() const Optional<i64> CalculatedStyleValue::resolve_integer() const
{ {
auto result = m_calculation->resolve({}, {}); auto result = m_calculation->resolve({}, {});
if (result.type().has_value() && result.type()->matches_number()) if (result.type().has_value() && result.type()->matches_number(m_context.percentages_resolve_as))
return llround(result.value()); return llround(result.value());
return {}; return {};
} }
@ -1970,7 +1970,7 @@ Optional<i64> CalculatedStyleValue::resolve_integer() const
Optional<i64> CalculatedStyleValue::resolve_integer(Length::ResolutionContext const& context) const Optional<i64> CalculatedStyleValue::resolve_integer(Length::ResolutionContext const& context) const
{ {
auto result = m_calculation->resolve(context, {}); auto result = m_calculation->resolve(context, {});
if (result.type().has_value() && result.type()->matches_number()) if (result.type().has_value() && result.type()->matches_number(m_context.percentages_resolve_as))
return llround(result.value()); return llround(result.value());
return {}; return {};
} }

View file

@ -69,23 +69,23 @@ public:
virtual String to_string(SerializationMode) const override; virtual String to_string(SerializationMode) const override;
virtual bool equals(CSSStyleValue const& other) const override; virtual bool equals(CSSStyleValue const& other) const override;
bool resolves_to_angle() const { return m_resolved_type.matches_angle(); } bool resolves_to_angle() const { return m_resolved_type.matches_angle(m_context.percentages_resolve_as); }
bool resolves_to_angle_percentage() const { return m_resolved_type.matches_angle_percentage(); } bool resolves_to_angle_percentage() const { return m_resolved_type.matches_angle_percentage(m_context.percentages_resolve_as); }
Optional<Angle> resolve_angle() const; Optional<Angle> resolve_angle() const;
Optional<Angle> resolve_angle(Layout::Node const& layout_node) const; Optional<Angle> resolve_angle(Layout::Node const& layout_node) const;
Optional<Angle> resolve_angle(Length::ResolutionContext const& context) const; Optional<Angle> resolve_angle(Length::ResolutionContext const& context) const;
Optional<Angle> resolve_angle_percentage(Angle const& percentage_basis) const; Optional<Angle> resolve_angle_percentage(Angle const& percentage_basis) const;
bool resolves_to_flex() const { return m_resolved_type.matches_flex(); } bool resolves_to_flex() const { return m_resolved_type.matches_flex(m_context.percentages_resolve_as); }
Optional<Flex> resolve_flex() const; Optional<Flex> resolve_flex() const;
bool resolves_to_frequency() const { return m_resolved_type.matches_frequency(); } bool resolves_to_frequency() const { return m_resolved_type.matches_frequency(m_context.percentages_resolve_as); }
bool resolves_to_frequency_percentage() const { return m_resolved_type.matches_frequency_percentage(); } bool resolves_to_frequency_percentage() const { return m_resolved_type.matches_frequency_percentage(m_context.percentages_resolve_as); }
Optional<Frequency> resolve_frequency() const; Optional<Frequency> resolve_frequency() const;
Optional<Frequency> resolve_frequency_percentage(Frequency const& percentage_basis) const; Optional<Frequency> resolve_frequency_percentage(Frequency const& percentage_basis) const;
bool resolves_to_length() const { return m_resolved_type.matches_length(); } bool resolves_to_length() const { return m_resolved_type.matches_length(m_context.percentages_resolve_as); }
bool resolves_to_length_percentage() const { return m_resolved_type.matches_length_percentage(); } bool resolves_to_length_percentage() const { return m_resolved_type.matches_length_percentage(m_context.percentages_resolve_as); }
Optional<Length> resolve_length(Length::ResolutionContext const&) const; Optional<Length> resolve_length(Length::ResolutionContext const&) const;
Optional<Length> resolve_length(Layout::Node const& layout_node) const; Optional<Length> resolve_length(Layout::Node const& layout_node) const;
Optional<Length> resolve_length_percentage(Layout::Node const&, Length const& percentage_basis) const; Optional<Length> resolve_length_percentage(Layout::Node const&, Length const& percentage_basis) const;
@ -95,15 +95,15 @@ public:
bool resolves_to_percentage() const { return m_resolved_type.matches_percentage(); } bool resolves_to_percentage() const { return m_resolved_type.matches_percentage(); }
Optional<Percentage> resolve_percentage() const; Optional<Percentage> resolve_percentage() const;
bool resolves_to_resolution() const { return m_resolved_type.matches_resolution(); } bool resolves_to_resolution() const { return m_resolved_type.matches_resolution(m_context.percentages_resolve_as); }
Optional<Resolution> resolve_resolution() const; Optional<Resolution> resolve_resolution() const;
bool resolves_to_time() const { return m_resolved_type.matches_time(); } bool resolves_to_time() const { return m_resolved_type.matches_time(m_context.percentages_resolve_as); }
bool resolves_to_time_percentage() const { return m_resolved_type.matches_time_percentage(); } bool resolves_to_time_percentage() const { return m_resolved_type.matches_time_percentage(m_context.percentages_resolve_as); }
Optional<Time> resolve_time() const; Optional<Time> resolve_time() const;
Optional<Time> resolve_time_percentage(Time const& percentage_basis) const; Optional<Time> resolve_time_percentage(Time const& percentage_basis) const;
bool resolves_to_number() const { return m_resolved_type.matches_number(); } bool resolves_to_number() const { return m_resolved_type.matches_number(m_context.percentages_resolve_as); }
Optional<double> resolve_number() const; Optional<double> resolve_number() const;
Optional<double> resolve_number(Length::ResolutionContext const&) const; Optional<double> resolve_number(Length::ResolutionContext const&) const;
Optional<double> resolve_number(Layout::Node const& layout_node) const; Optional<double> resolve_number(Layout::Node const& layout_node) const;
@ -126,6 +126,8 @@ private:
{ {
} }
Optional<ValueType> percentage_resolved_type() const;
CSSNumericType m_resolved_type; CSSNumericType m_resolved_type;
NonnullOwnPtr<CalculationNode> m_calculation; NonnullOwnPtr<CalculationNode> m_calculation;
CalculationContext m_context; CalculationContext m_context;

View file

@ -53,23 +53,23 @@ String generate_calculation_type_check(StringView calculation_variable_name, Str
first_type_check = false; first_type_check = false;
if (allowed_type_name == "<angle>"sv) { if (allowed_type_name == "<angle>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_angle()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_angle(percentages_resolve_as)"sv);
} else if (allowed_type_name == "<dimension>"sv) { } else if (allowed_type_name == "<dimension>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_dimension()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_dimension()"sv);
} else if (allowed_type_name == "<flex>"sv) { } else if (allowed_type_name == "<flex>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_flex()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_flex(percentages_resolve_as)"sv);
} else if (allowed_type_name == "<frequency>"sv) { } else if (allowed_type_name == "<frequency>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_frequency()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_frequency(percentages_resolve_as)"sv);
} else if (allowed_type_name == "<length>"sv) { } else if (allowed_type_name == "<length>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_length()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_length(percentages_resolve_as)"sv);
} else if (allowed_type_name == "<number>"sv) { } else if (allowed_type_name == "<number>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_number()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_number(percentages_resolve_as)"sv);
} else if (allowed_type_name == "<percentage>"sv) { } else if (allowed_type_name == "<percentage>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_percentage()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_percentage()"sv);
} else if (allowed_type_name == "<resolution>"sv) { } else if (allowed_type_name == "<resolution>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_resolution()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_resolution(percentages_resolve_as)"sv);
} else if (allowed_type_name == "<time>"sv) { } else if (allowed_type_name == "<time>"sv) {
builder.appendff("{}.{}", calculation_variable_name, "matches_time()"sv); builder.appendff("{}.{}", calculation_variable_name, "matches_time(percentages_resolve_as)"sv);
} else { } else {
dbgln("I don't know what '{}' is!", allowed_type_name); dbgln("I don't know what '{}' is!", allowed_type_name);
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@ -120,6 +120,7 @@ OwnPtr<CalculationNode> Parser::parse_math_function(Function const& function, Ca
{ {
TokenStream stream { function.value }; TokenStream stream { function.value };
auto arguments = parse_a_comma_separated_list_of_component_values(stream); auto arguments = parse_a_comma_separated_list_of_component_values(stream);
auto const& percentages_resolve_as = context.percentages_resolve_as;
)~~~"); )~~~");
functions_data.for_each_member([&](auto& name, JsonValue const& value) -> void { functions_data.for_each_member([&](auto& name, JsonValue const& value) -> void {