Skip to content

Commit

Permalink
WIP: Break all the tests by changing how we parse numbers and dimensions
Browse files Browse the repository at this point in the history
  • Loading branch information
AtkinsSJ committed Jan 6, 2025
1 parent 967de29 commit 175040a
Showing 1 changed file with 58 additions and 157 deletions.
215 changes: 58 additions & 157 deletions Libraries/LibWeb/CSS/Parser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8727,13 +8727,6 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
}
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_keyword = [](ReadonlySpan<PropertyID> property_ids, Keyword keyword) -> Optional<PropertyID> {
for (auto const& property : property_ids) {
if (property_accepts_keyword(property, keyword))
Expand Down Expand Up @@ -8802,40 +8795,11 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
return PropertyAndValue { *property, maybe_ratio };
}

auto property_accepting_integer = any_property_accepts_type(property_ids, ValueType::Integer);
auto property_accepting_number = any_property_accepts_type(property_ids, ValueType::Number);
bool property_accepts_numeric = property_accepting_integer.has_value() || property_accepting_number.has_value();

if (peek_token.is(Token::Type::Number) && property_accepts_numeric) {
if (peek_token.token().number().is_integer() && property_accepting_integer.has_value()) {
auto integer = IntegerStyleValue::create(peek_token.token().number().integer_value());
if (property_accepts_integer(*property_accepting_integer, integer->as_integer().integer())) {
tokens.discard_a_token(); // integer
return PropertyAndValue { *property_accepting_integer, integer };
}
}
if (property_accepting_number.has_value()) {
auto number = NumberStyleValue::create(peek_token.token().number().value());
if (property_accepts_number(*property_accepting_number, number->as_number().number())) {
tokens.discard_a_token(); // number
return PropertyAndValue { *property_accepting_number, number };
}
}
}

if (auto property = any_property_accepts_type(property_ids, ValueType::OpenTypeTag); property.has_value()) {
if (auto maybe_rect = parse_opentype_tag_value(tokens))
return PropertyAndValue { *property, maybe_rect };
}

if (peek_token.is(Token::Type::Percentage)) {
auto percentage = Percentage(peek_token.token().percentage());
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value() && property_accepts_percentage(*property, percentage)) {
tokens.discard_a_token();
return PropertyAndValue { *property, PercentageStyleValue::create(percentage) };
}
}

if (auto property = any_property_accepts_type(property_ids, ValueType::Rect); property.has_value()) {
if (auto maybe_rect = parse_rect_value(tokens))
return PropertyAndValue { *property, maybe_rect };
Expand All @@ -8851,133 +8815,70 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
return PropertyAndValue { *property, url };
}

bool property_accepts_dimension = any_property_accepts_type(property_ids, ValueType::Angle).has_value()
|| any_property_accepts_type(property_ids, ValueType::Flex).has_value()
|| any_property_accepts_type(property_ids, ValueType::Frequency).has_value()
|| any_property_accepts_type(property_ids, ValueType::Length).has_value()
|| any_property_accepts_type(property_ids, ValueType::Percentage).has_value()
|| any_property_accepts_type(property_ids, ValueType::Resolution).has_value()
|| any_property_accepts_type(property_ids, ValueType::Time).has_value();

if (property_accepts_dimension) {
if (peek_token.is(Token::Type::Number) && m_context.is_parsing_svg_presentation_attribute()) {
auto transaction = tokens.begin_transaction();
auto const& token = tokens.consume_a_token();
// https://svgwg.org/svg2-draft/types.html#presentation-attribute-css-value
// We need to allow <number> in any place that expects a <length> or <angle>.
// FIXME: How should these numbers be interpreted? https://github.com/w3c/svgwg/issues/792
// For now: Convert them to px lengths, or deg angles.
auto angle = Angle::make_degrees(token.token().number_value());
if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value() && property_accepts_angle(*property, angle)) {
transaction.commit();
return PropertyAndValue { *property, AngleStyleValue::create(angle) };
}
auto length = Length::make_px(CSSPixels::nearest_value_for(token.token().number_value()));
if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value() && property_accepts_length(*property, length)) {
transaction.commit();
return PropertyAndValue { *property, LengthStyleValue::create(length) };
}
if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value()) {
if (property_accepts_type(*property, ValueType::Percentage)) {
if (auto value = parse_angle_percentage_value(tokens))
return PropertyAndValue { *property, value };
}
if (auto value = parse_angle_value(tokens))
return PropertyAndValue { *property, value };
}

auto transaction = tokens.begin_transaction();
if (auto maybe_dimension = parse_dimension(peek_token); maybe_dimension.has_value()) {
tokens.discard_a_token();
auto dimension = maybe_dimension.release_value();
if (dimension.is_angle()) {
auto angle = dimension.angle();
if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value() && property_accepts_angle(*property, angle)) {
transaction.commit();
return PropertyAndValue { *property, AngleStyleValue::create(angle) };
}
}
if (dimension.is_flex()) {
auto flex = dimension.flex();
if (auto property = any_property_accepts_type(property_ids, ValueType::Flex); property.has_value() && property_accepts_flex(*property, flex)) {
transaction.commit();
return PropertyAndValue { *property, FlexStyleValue::create(flex) };
}
}
if (dimension.is_frequency()) {
auto frequency = dimension.frequency();
if (auto property = any_property_accepts_type(property_ids, ValueType::Frequency); property.has_value() && property_accepts_frequency(*property, frequency)) {
transaction.commit();
return PropertyAndValue { *property, FrequencyStyleValue::create(frequency) };
}
}
if (dimension.is_length()) {
auto length = dimension.length();
if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value() && property_accepts_length(*property, length)) {
transaction.commit();
return PropertyAndValue { *property, LengthStyleValue::create(length) };
}
}
if (dimension.is_resolution()) {
auto resolution = dimension.resolution();
if (auto property = any_property_accepts_type(property_ids, ValueType::Resolution); property.has_value() && property_accepts_resolution(*property, resolution)) {
transaction.commit();
return PropertyAndValue { *property, ResolutionStyleValue::create(resolution) };
}
}
if (dimension.is_time()) {
auto time = dimension.time();
if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value() && property_accepts_time(*property, time)) {
transaction.commit();
return PropertyAndValue { *property, TimeStyleValue::create(time) };
}
}
if (auto property = any_property_accepts_type(property_ids, ValueType::Flex); property.has_value()) {
if (auto value = parse_flex_value(tokens))
return PropertyAndValue { *property, value };
}

if (auto property = any_property_accepts_type(property_ids, ValueType::Frequency); property.has_value()) {
if (property_accepts_type(*property, ValueType::Percentage)) {
if (auto value = parse_frequency_percentage_value(tokens))
return PropertyAndValue { *property, value };
}
if (auto value = parse_frequency_value(tokens))
return PropertyAndValue { *property, value };
}

// In order to not end up parsing `calc()` and other math expressions multiple times,
// we parse it once, and then see if its resolved type matches what the property accepts.
if (peek_token.is_function() && (property_accepts_dimension || property_accepts_numeric)) {
if (auto maybe_calculated = parse_calculated_value(peek_token); maybe_calculated) {
tokens.discard_a_token();
auto& calculated = *maybe_calculated;
// This is a bit sensitive to ordering: `<foo>` and `<percentage>` have to be checked before `<foo-percentage>`.
// FIXME: When parsing SVG presentation attributes, <number> is permitted wherever <length>, <length-percentage>, or <angle> are.
// The specifics are unclear, so I'm ignoring this for calculated values for now.
// See https://github.com/w3c/svgwg/issues/792
if (calculated.resolves_to_percentage()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); 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 };
} else 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_flex()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Flex); 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 };
} 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_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 };
}
} 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_length()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value())
return PropertyAndValue { *property, calculated };
} 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_time()) {
if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value())
return PropertyAndValue { *property, calculated };
} 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 };
}
if (auto property = any_property_accepts_type(property_ids, ValueType::Integer); property.has_value()) {
if (auto maybe_integer = parse_integer_value(tokens))
return PropertyAndValue { *property, maybe_integer };
}

if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value()) {
if (property_accepts_type(*property, ValueType::Percentage)) {
if (auto value = parse_length_percentage_value(tokens))
return PropertyAndValue { *property, value };
}
if (auto value = parse_length_value(tokens))
return PropertyAndValue { *property, value };
}

if (auto property = any_property_accepts_type(property_ids, ValueType::Number); property.has_value()) {
if (property_accepts_type(*property, ValueType::Percentage)) {
if (auto value = parse_number_percentage_value(tokens))
return PropertyAndValue { *property, value };
}
if (auto maybe_integer = parse_number_value(tokens))
return PropertyAndValue { *property, maybe_integer };
}

if (auto property = any_property_accepts_type(property_ids, ValueType::Resolution); property.has_value()) {
if (auto value = parse_resolution_value(tokens))
return PropertyAndValue { *property, value };
}

if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value()) {
if (property_accepts_type(*property, ValueType::Percentage)) {
if (auto value = parse_time_percentage_value(tokens))
return PropertyAndValue { *property, value };
}
if (auto value = parse_time_value(tokens))
return PropertyAndValue { *property, value };
}

// <percentage> is checked after the <foo-percentage> types.
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value()) {
if (auto value = parse_percentage_value(tokens))
return PropertyAndValue { *property, value };
}

if (auto property = any_property_accepts_type(property_ids, ValueType::Paint); property.has_value()) {
Expand Down

0 comments on commit 175040a

Please sign in to comment.