1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 22:38:13 +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()) {
dbgln_if(CSS_PARSER_DEBUG, "calc() resolved as invalid!!!");
return nullptr;
}
[[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()));
dbgln_if(CSS_PARSER_DEBUG, "Deduced calc() resolved type as: {}", calc_type->dump());
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)
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())
return nullptr;
@ -8266,6 +8246,13 @@ ErrorOr<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readonl
}
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> {
for (auto const& property : property_ids) {
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()) {
(void)tokens.next_token();
auto& calculated = maybe_dynamic->as_calculated();
switch (calculated.resolved_type()) {
case CalculatedStyleValue::ResolvedType::Angle:
if (calculated.resolves_to_angle_percentage()) {
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())
return PropertyAndValue { *property, calculated };
break;
case CalculatedStyleValue::ResolvedType::Frequency:
} else if (calculated.resolves_to_frequency_percentage()) {
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())
return PropertyAndValue { *property, calculated };
break;
case CalculatedStyleValue::ResolvedType::Integer:
case CalculatedStyleValue::ResolvedType::Number:
} else if (calculated.resolves_to_number_percentage()) {
if (auto property = any_property_accepts_type_percentage(property_ids, ValueType::Number); property.has_value())
return PropertyAndValue { *property, calculated };
} else if (calculated.resolves_to_number()) {
if (property_accepts_numeric) {
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 };
}
break;
case CalculatedStyleValue::ResolvedType::Length:
} else if (calculated.resolves_to_length_percentage()) {
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())
return PropertyAndValue { *property, calculated };
break;
case CalculatedStyleValue::ResolvedType::Percentage:
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value())
} else if (calculated.resolves_to_time_percentage()) {
if (auto property = any_property_accepts_type_percentage(property_ids, ValueType::Time); property.has_value())
return PropertyAndValue { *property, calculated };
break;
case CalculatedStyleValue::ResolvedType::Time:
} else if (calculated.resolves_to_time()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value())
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.
// 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) {
dbgln("Stopped expanding CSS variables: maximum length reached.");
return false;
@ -952,23 +952,20 @@ bool StyleComputer::expand_unresolved_values(DOM::Element& element, StringView p
return false;
}
// FIXME: Handle all math functions.
if (value.function().name().equals_ignoring_ascii_case("calc"sv)) {
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()) {
switch (calc_value->resolved_type()) {
case CalculatedStyleValue::ResolvedType::Integer: {
auto resolved_value = calc_value->resolve_integer();
if (calc_value->resolves_to_number()) {
auto resolved_value = calc_value->resolve_number();
dest.empend(Parser::Token::create_number(resolved_value.value()));
continue;
}
case CalculatedStyleValue::ResolvedType::Percentage: {
} else if (calc_value->resolves_to_percentage()) {
auto resolved_value = calc_value->resolve_percentage();
dest.empend(Parser::Token::create_percentage(resolved_value.value().value()));
continue;
}
default:
} else {
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();
} else if (value.is_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();
if (maybe_percentage.has_value())
unclamped_opacity = maybe_percentage->as_fraction();
else
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();
if (maybe_number.has_value())
unclamped_opacity = maybe_number.value();

View file

@ -65,51 +65,54 @@ public:
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));
}
ErrorOr<String> to_string() 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_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_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;
Optional<Length> resolve_length(Layout::Node const& layout_node) 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;
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_percentage(Time const& percentage_basis) const;
bool resolves_to_integer() const { return m_resolved_type == ResolvedType::Integer; }
bool resolves_to_number() const { return resolves_to_integer() || m_resolved_type == ResolvedType::Number; }
bool resolves_to_number() const { return m_resolved_type.matches_number(); }
bool resolves_to_number_percentage() const { return m_resolved_type.matches_number_percentage(); }
Optional<double> resolve_number() const;
Optional<i64> resolve_integer();
bool contains_percentage() const;
private:
explicit CalculatedStyleValue(NonnullOwnPtr<CalculationNode> calculation, ResolvedType resolved_type)
explicit CalculatedStyleValue(NonnullOwnPtr<CalculationNode> calculation, CSSNumericType resolved_type)
: StyleValue(Type::Calculated)
, m_resolved_type(resolved_type)
, m_calculation(move(calculation))
{
}
ResolvedType m_resolved_type;
CSSNumericType m_resolved_type;
NonnullOwnPtr<CalculationNode> m_calculation;
};