1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 14:37:43 +00:00

LibWeb: Use CSSNumericType for CalculatedStyleValue resolved type

This commit is contained in:
Sam Atkins 2023-06-30 16:29:06 +01:00 committed by Andreas Kling
parent 4d84080fdc
commit f21a30e45f
4 changed files with 54 additions and 60 deletions

View file

@ -3407,32 +3407,12 @@ ErrorOr<RefPtr<CalculatedStyleValue>> Parser::parse_calculated_value(Vector<Comp
} }
} }
auto calc_type = calculation_tree->resolved_type(); auto calc_type = calculation_tree->determine_type(m_context.current_property_id());
if (!calc_type.has_value()) { if (!calc_type.has_value()) {
dbgln_if(CSS_PARSER_DEBUG, "calc() resolved as invalid!!!"); dbgln_if(CSS_PARSER_DEBUG, "calc() resolved as invalid!!!");
return nullptr; return nullptr;
} }
dbgln_if(CSS_PARSER_DEBUG, "Deduced calc() resolved type as: {}", calc_type->dump());
[[maybe_unused]] auto to_string = [](CalculatedStyleValue::ResolvedType type) {
switch (type) {
case CalculatedStyleValue::ResolvedType::Angle:
return "Angle"sv;
case CalculatedStyleValue::ResolvedType::Frequency:
return "Frequency"sv;
case CalculatedStyleValue::ResolvedType::Integer:
return "Integer"sv;
case CalculatedStyleValue::ResolvedType::Length:
return "Length"sv;
case CalculatedStyleValue::ResolvedType::Number:
return "Number"sv;
case CalculatedStyleValue::ResolvedType::Percentage:
return "Percentage"sv;
case CalculatedStyleValue::ResolvedType::Time:
return "Time"sv;
}
VERIFY_NOT_REACHED();
};
dbgln_if(CSS_PARSER_DEBUG, "Deduced calc() resolved type as: {}", to_string(calc_type.value()));
return CalculatedStyleValue::create(calculation_tree.release_nonnull(), calc_type.release_value()); return CalculatedStyleValue::create(calculation_tree.release_nonnull(), calc_type.release_value());
} }
@ -4127,7 +4107,7 @@ ErrorOr<RefPtr<StyleValue>> Parser::parse_dynamic_value(ComponentValue const& co
if (!function_node) if (!function_node)
return nullptr; return nullptr;
auto function_type = function_node->resolved_type(); auto function_type = function_node->determine_type(m_context.current_property_id());
if (!function_type.has_value()) if (!function_type.has_value())
return nullptr; return nullptr;
@ -8266,6 +8246,13 @@ ErrorOr<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readonl
} }
return {}; return {};
}; };
auto any_property_accepts_type_percentage = [](ReadonlySpan<PropertyID> property_ids, ValueType value_type) -> Optional<PropertyID> {
for (auto const& property : property_ids) {
if (property_accepts_type(property, value_type) && property_accepts_type(property, ValueType::Percentage))
return property;
}
return {};
};
auto any_property_accepts_identifier = [](ReadonlySpan<PropertyID> property_ids, ValueID identifier) -> Optional<PropertyID> { auto any_property_accepts_identifier = [](ReadonlySpan<PropertyID> property_ids, ValueID identifier) -> Optional<PropertyID> {
for (auto const& property : property_ids) { for (auto const& property : property_ids) {
if (property_accepts_identifier(property, identifier)) if (property_accepts_identifier(property, identifier))
@ -8416,34 +8403,41 @@ ErrorOr<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readonl
if (auto maybe_dynamic = TRY(parse_dynamic_value(peek_token)); maybe_dynamic && maybe_dynamic->is_calculated()) { if (auto maybe_dynamic = TRY(parse_dynamic_value(peek_token)); maybe_dynamic && maybe_dynamic->is_calculated()) {
(void)tokens.next_token(); (void)tokens.next_token();
auto& calculated = maybe_dynamic->as_calculated(); auto& calculated = maybe_dynamic->as_calculated();
switch (calculated.resolved_type()) { if (calculated.resolves_to_angle_percentage()) {
case CalculatedStyleValue::ResolvedType::Angle: if (auto property = any_property_accepts_type_percentage(property_ids, ValueType::Angle); property.has_value())
return PropertyAndValue { *property, calculated };
} else if (calculated.resolves_to_angle()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value()) if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value())
return PropertyAndValue { *property, calculated }; return PropertyAndValue { *property, calculated };
break; } else if (calculated.resolves_to_frequency_percentage()) {
case CalculatedStyleValue::ResolvedType::Frequency: if (auto property = any_property_accepts_type_percentage(property_ids, ValueType::Frequency); property.has_value())
return PropertyAndValue { *property, calculated };
} else if (calculated.resolves_to_frequency()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Frequency); property.has_value()) if (auto property = any_property_accepts_type(property_ids, ValueType::Frequency); property.has_value())
return PropertyAndValue { *property, calculated }; return PropertyAndValue { *property, calculated };
break; } else if (calculated.resolves_to_number_percentage()) {
case CalculatedStyleValue::ResolvedType::Integer: if (auto property = any_property_accepts_type_percentage(property_ids, ValueType::Number); property.has_value())
case CalculatedStyleValue::ResolvedType::Number: return PropertyAndValue { *property, calculated };
} else if (calculated.resolves_to_number()) {
if (property_accepts_numeric) { if (property_accepts_numeric) {
auto property_or_resolved = property_accepting_integer.value_or_lazy_evaluated([property_accepting_number]() { return property_accepting_number.value(); }); auto property_or_resolved = property_accepting_integer.value_or_lazy_evaluated([property_accepting_number]() { return property_accepting_number.value(); });
return PropertyAndValue { property_or_resolved, calculated }; return PropertyAndValue { property_or_resolved, calculated };
} }
break; } else if (calculated.resolves_to_length_percentage()) {
case CalculatedStyleValue::ResolvedType::Length: if (auto property = any_property_accepts_type_percentage(property_ids, ValueType::Length); property.has_value())
return PropertyAndValue { *property, calculated };
} else if (calculated.resolves_to_length()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value()) if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value())
return PropertyAndValue { *property, calculated }; return PropertyAndValue { *property, calculated };
break; } else if (calculated.resolves_to_time_percentage()) {
case CalculatedStyleValue::ResolvedType::Percentage: if (auto property = any_property_accepts_type_percentage(property_ids, ValueType::Time); property.has_value())
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value())
return PropertyAndValue { *property, calculated }; return PropertyAndValue { *property, calculated };
break; } else if (calculated.resolves_to_time()) {
case CalculatedStyleValue::ResolvedType::Time:
if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value()) if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value())
return PropertyAndValue { *property, calculated }; return PropertyAndValue { *property, calculated };
break; } else if (calculated.resolves_to_percentage()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value())
return PropertyAndValue { *property, calculated };
} }
} }
} }

View file

@ -820,7 +820,7 @@ bool StyleComputer::expand_variables(DOM::Element& element, Optional<CSS::Select
{ {
// Arbitrary large value chosen to avoid the billion-laughs attack. // Arbitrary large value chosen to avoid the billion-laughs attack.
// https://www.w3.org/TR/css-variables-1/#long-variables // https://www.w3.org/TR/css-variables-1/#long-variables
const size_t MAX_VALUE_COUNT = 16384; size_t const MAX_VALUE_COUNT = 16384;
if (source.remaining_token_count() + dest.size() > MAX_VALUE_COUNT) { if (source.remaining_token_count() + dest.size() > MAX_VALUE_COUNT) {
dbgln("Stopped expanding CSS variables: maximum length reached."); dbgln("Stopped expanding CSS variables: maximum length reached.");
return false; return false;
@ -952,23 +952,20 @@ bool StyleComputer::expand_unresolved_values(DOM::Element& element, StringView p
return false; return false;
} }
// FIXME: Handle all math functions.
if (value.function().name().equals_ignoring_ascii_case("calc"sv)) { if (value.function().name().equals_ignoring_ascii_case("calc"sv)) {
auto const& calc_function = value.function(); auto const& calc_function = value.function();
if (auto calc_value = Parser::Parser::parse_calculated_value({}, Parser::ParsingContext { document() }, calc_function.values()).release_value_but_fixme_should_propagate_errors()) { if (auto calc_value = Parser::Parser::parse_calculated_value({}, Parser::ParsingContext { document() }, calc_function.values()).release_value_but_fixme_should_propagate_errors()) {
switch (calc_value->resolved_type()) { if (calc_value->resolves_to_number()) {
case CalculatedStyleValue::ResolvedType::Integer: { auto resolved_value = calc_value->resolve_number();
auto resolved_value = calc_value->resolve_integer();
dest.empend(Parser::Token::create_number(resolved_value.value())); dest.empend(Parser::Token::create_number(resolved_value.value()));
continue; continue;
} } else if (calc_value->resolves_to_percentage()) {
case CalculatedStyleValue::ResolvedType::Percentage: {
auto resolved_value = calc_value->resolve_percentage(); auto resolved_value = calc_value->resolve_percentage();
dest.empend(Parser::Token::create_percentage(resolved_value.value().value())); dest.empend(Parser::Token::create_percentage(resolved_value.value().value()));
continue; continue;
} } else {
default:
dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Unimplemented calc() expansion: {}", calc_value->to_string()); dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Unimplemented calc() expansion: {}", calc_value->to_string());
break;
} }
} }
} }

View file

@ -265,13 +265,13 @@ static float resolve_opacity_value(CSS::StyleValue const& value)
unclamped_opacity = value.as_number().number(); unclamped_opacity = value.as_number().number();
} else if (value.is_calculated()) { } else if (value.is_calculated()) {
auto& calculated = value.as_calculated(); auto& calculated = value.as_calculated();
if (calculated.resolved_type() == CalculatedStyleValue::ResolvedType::Percentage) { if (calculated.resolves_to_percentage()) {
auto maybe_percentage = value.as_calculated().resolve_percentage(); auto maybe_percentage = value.as_calculated().resolve_percentage();
if (maybe_percentage.has_value()) if (maybe_percentage.has_value())
unclamped_opacity = maybe_percentage->as_fraction(); unclamped_opacity = maybe_percentage->as_fraction();
else else
dbgln("Unable to resolve calc() as opacity (percentage): {}", value.to_string()); dbgln("Unable to resolve calc() as opacity (percentage): {}", value.to_string());
} else { } else if (calculated.resolves_to_number()) {
auto maybe_number = const_cast<CalculatedStyleValue&>(value.as_calculated()).resolve_number(); auto maybe_number = const_cast<CalculatedStyleValue&>(value.as_calculated()).resolve_number();
if (maybe_number.has_value()) if (maybe_number.has_value())
unclamped_opacity = maybe_number.value(); unclamped_opacity = maybe_number.value();

View file

@ -65,51 +65,54 @@ public:
Value m_value; Value m_value;
}; };
static ErrorOr<ValueComparingNonnullRefPtr<CalculatedStyleValue>> create(NonnullOwnPtr<CalculationNode> calculation, ResolvedType resolved_type) static ErrorOr<ValueComparingNonnullRefPtr<CalculatedStyleValue>> create(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type)
{ {
return adopt_nonnull_ref_or_enomem(new (nothrow) CalculatedStyleValue(move(calculation), resolved_type)); return adopt_nonnull_ref_or_enomem(new (nothrow) CalculatedStyleValue(move(calculation), resolved_type));
} }
ErrorOr<String> to_string() const override; ErrorOr<String> to_string() const override;
virtual bool equals(StyleValue const& other) const override; virtual bool equals(StyleValue const& other) const override;
ResolvedType resolved_type() const { return m_resolved_type; }
bool resolves_to_angle() const { return m_resolved_type == ResolvedType::Angle; } bool resolves_to_angle() const { return m_resolved_type.matches_angle(); }
bool resolves_to_angle_percentage() const { return m_resolved_type.matches_angle_percentage(); }
Optional<Angle> resolve_angle() const; Optional<Angle> resolve_angle() const;
Optional<Angle> resolve_angle_percentage(Angle const& percentage_basis) const; Optional<Angle> resolve_angle_percentage(Angle const& percentage_basis) const;
bool resolves_to_frequency() const { return m_resolved_type == ResolvedType::Frequency; } bool resolves_to_frequency() const { return m_resolved_type.matches_frequency(); }
bool resolves_to_frequency_percentage() const { return m_resolved_type.matches_frequency_percentage(); }
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 == ResolvedType::Length; } bool resolves_to_length() const { return m_resolved_type.matches_length(); }
bool resolves_to_length_percentage() const { return m_resolved_type.matches_length_percentage(); }
[[nodiscard]] Optional<Length> resolve_length(Length::ResolutionContext const&) const; [[nodiscard]] 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;
bool resolves_to_percentage() const { return m_resolved_type == ResolvedType::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_time() const { return m_resolved_type == ResolvedType::Time; } bool resolves_to_time() const { return m_resolved_type.matches_time(); }
bool resolves_to_time_percentage() const { return m_resolved_type.matches_time_percentage(); }
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_integer() const { return m_resolved_type == ResolvedType::Integer; } bool resolves_to_number() const { return m_resolved_type.matches_number(); }
bool resolves_to_number() const { return resolves_to_integer() || m_resolved_type == ResolvedType::Number; } bool resolves_to_number_percentage() const { return m_resolved_type.matches_number_percentage(); }
Optional<double> resolve_number() const; Optional<double> resolve_number() const;
Optional<i64> resolve_integer(); Optional<i64> resolve_integer();
bool contains_percentage() const; bool contains_percentage() const;
private: private:
explicit CalculatedStyleValue(NonnullOwnPtr<CalculationNode> calculation, ResolvedType resolved_type) explicit CalculatedStyleValue(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type)
: StyleValue(Type::Calculated) : StyleValue(Type::Calculated)
, m_resolved_type(resolved_type) , m_resolved_type(resolved_type)
, m_calculation(move(calculation)) , m_calculation(move(calculation))
{ {
} }
ResolvedType m_resolved_type; CSSNumericType m_resolved_type;
NonnullOwnPtr<CalculationNode> m_calculation; NonnullOwnPtr<CalculationNode> m_calculation;
}; };