mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 21:27:35 +00:00
LibWeb: Use new StyleValue parsing for font and font-family
This commit is contained in:
parent
100adffdfb
commit
c8626f2294
2 changed files with 88 additions and 79 deletions
|
@ -5529,64 +5529,71 @@ ErrorOr<RefPtr<StyleValue>> Parser::parse_font_value(Vector<ComponentValue> cons
|
||||||
// So, we have to handle that separately.
|
// So, we have to handle that separately.
|
||||||
int normal_count = 0;
|
int normal_count = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < component_values.size(); ++i) {
|
auto tokens = TokenStream { component_values };
|
||||||
auto value = TRY(parse_css_value(component_values[i]));
|
auto remaining_longhands = Vector { PropertyID::FontSize, PropertyID::FontStretch, PropertyID::FontStyle, PropertyID::FontVariant, PropertyID::FontWeight };
|
||||||
if (!value)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (value->to_identifier() == ValueID::Normal) {
|
while (tokens.has_next_token()) {
|
||||||
|
auto& peek_token = tokens.peek_token();
|
||||||
|
if (peek_token.is(Token::Type::Ident) && value_id_from_string(peek_token.token().ident()) == ValueID::Normal) {
|
||||||
normal_count++;
|
normal_count++;
|
||||||
|
(void)tokens.next_token();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME: Handle angle parameter to `oblique`: https://www.w3.org/TR/css-fonts-4/#font-style-prop
|
|
||||||
if (property_accepts_value(PropertyID::FontStyle, *value)) {
|
auto property_and_value = TRY(parse_css_value_for_properties(remaining_longhands, tokens));
|
||||||
if (font_style)
|
if (!property_and_value.style_value)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
font_style = value.release_nonnull();
|
auto& value = property_and_value.style_value;
|
||||||
continue;
|
remove_property(remaining_longhands, property_and_value.property);
|
||||||
}
|
|
||||||
if (property_accepts_value(PropertyID::FontWeight, *value)) {
|
switch (property_and_value.property) {
|
||||||
if (font_weight)
|
case PropertyID::FontSize: {
|
||||||
return nullptr;
|
VERIFY(!font_size);
|
||||||
font_weight = value.release_nonnull();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (property_accepts_value(PropertyID::FontVariant, *value)) {
|
|
||||||
if (font_variant)
|
|
||||||
return nullptr;
|
|
||||||
font_variant = value.release_nonnull();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (property_accepts_value(PropertyID::FontSize, *value)) {
|
|
||||||
if (font_size)
|
|
||||||
return nullptr;
|
|
||||||
font_size = value.release_nonnull();
|
font_size = value.release_nonnull();
|
||||||
|
|
||||||
// Consume `/ line-height` if present
|
// Consume `/ line-height` if present
|
||||||
if (i + 2 < component_values.size()) {
|
auto maybe_solidus = tokens.peek_token();
|
||||||
auto const& maybe_solidus = component_values[i + 1];
|
if (maybe_solidus.is(Token::Type::Delim) && maybe_solidus.token().delim() == '/') {
|
||||||
if (maybe_solidus.is(Token::Type::Delim) && maybe_solidus.token().delim() == '/') {
|
(void)tokens.next_token();
|
||||||
auto maybe_line_height = TRY(parse_css_value(component_values[i + 2]));
|
auto maybe_line_height = TRY(parse_css_value_for_property(PropertyID::LineHeight, tokens));
|
||||||
if (!(maybe_line_height && property_accepts_value(PropertyID::LineHeight, *maybe_line_height)))
|
if (!maybe_line_height)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
line_height = maybe_line_height.release_nonnull();
|
line_height = maybe_line_height.release_nonnull();
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consume font-families
|
// Consume font-families
|
||||||
auto maybe_font_families = TRY(parse_font_family_value(component_values, i + 1));
|
auto maybe_font_families = TRY(parse_font_family_value(tokens));
|
||||||
if (!maybe_font_families)
|
// font-family comes last, so we must not have any tokens left over.
|
||||||
|
if (!maybe_font_families || tokens.has_next_token())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
font_families = maybe_font_families.release_nonnull();
|
font_families = maybe_font_families.release_nonnull();
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
if (property_accepts_value(PropertyID::FontStretch, *value)) {
|
case PropertyID::FontStretch: {
|
||||||
if (font_stretch)
|
VERIFY(!font_stretch);
|
||||||
return nullptr;
|
|
||||||
font_stretch = value.release_nonnull();
|
font_stretch = value.release_nonnull();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
case PropertyID::FontStyle: {
|
||||||
|
// FIXME: Handle angle parameter to `oblique`: https://www.w3.org/TR/css-fonts-4/#font-style-prop
|
||||||
|
VERIFY(!font_style);
|
||||||
|
font_style = value.release_nonnull();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case PropertyID::FontVariant: {
|
||||||
|
VERIFY(!font_variant);
|
||||||
|
font_variant = value.release_nonnull();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case PropertyID::FontWeight: {
|
||||||
|
VERIFY(!font_weight);
|
||||||
|
font_weight = value.release_nonnull();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5612,15 +5619,10 @@ ErrorOr<RefPtr<StyleValue>> Parser::parse_font_value(Vector<ComponentValue> cons
|
||||||
return FontStyleValue::create(font_stretch.release_nonnull(), font_style.release_nonnull(), font_weight.release_nonnull(), font_size.release_nonnull(), line_height.release_nonnull(), font_families.release_nonnull());
|
return FontStyleValue::create(font_stretch.release_nonnull(), font_style.release_nonnull(), font_weight.release_nonnull(), font_size.release_nonnull(), line_height.release_nonnull(), font_families.release_nonnull());
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<RefPtr<StyleValue>> Parser::parse_font_family_value(Vector<ComponentValue> const& component_values, size_t start_index)
|
ErrorOr<RefPtr<StyleValue>> Parser::parse_font_family_value(TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
auto is_comma_or_eof = [&](size_t i) -> bool {
|
auto next_is_comma_or_eof = [&]() -> bool {
|
||||||
if (i < component_values.size()) {
|
return !tokens.has_next_token() || tokens.peek_token().is(Token::Type::Comma);
|
||||||
auto const& maybe_comma = component_values[i];
|
|
||||||
if (!maybe_comma.is(Token::Type::Comma))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note: Font-family names can either be a quoted string, or a keyword, or a series of custom-idents.
|
// Note: Font-family names can either be a quoted string, or a keyword, or a series of custom-idents.
|
||||||
|
@ -5629,54 +5631,59 @@ ErrorOr<RefPtr<StyleValue>> Parser::parse_font_family_value(Vector<ComponentValu
|
||||||
// font-family: "my cool font!", serif;
|
// font-family: "my cool font!", serif;
|
||||||
StyleValueVector font_families;
|
StyleValueVector font_families;
|
||||||
Vector<DeprecatedString> current_name_parts;
|
Vector<DeprecatedString> current_name_parts;
|
||||||
for (size_t i = start_index; i < component_values.size(); ++i) {
|
while (tokens.has_next_token()) {
|
||||||
auto const& part = component_values[i];
|
auto const& peek = tokens.peek_token();
|
||||||
|
|
||||||
if (part.is(Token::Type::String)) {
|
if (peek.is(Token::Type::String)) {
|
||||||
// `font-family: my cool "font";` is invalid.
|
// `font-family: my cool "font";` is invalid.
|
||||||
if (!current_name_parts.is_empty())
|
if (!current_name_parts.is_empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!is_comma_or_eof(i + 1))
|
(void)tokens.next_token(); // String
|
||||||
|
if (!next_is_comma_or_eof())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
font_families.append(TRY(StringStyleValue::create(TRY(String::from_utf8(part.token().string())))));
|
TRY(font_families.try_append(TRY(StringStyleValue::create(TRY(String::from_utf8(peek.token().string()))))));
|
||||||
i++;
|
(void)tokens.next_token(); // Comma
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (part.is(Token::Type::Ident)) {
|
|
||||||
|
if (peek.is(Token::Type::Ident)) {
|
||||||
// If this is a valid identifier, it's NOT a custom-ident and can't be part of a larger name.
|
// If this is a valid identifier, it's NOT a custom-ident and can't be part of a larger name.
|
||||||
auto maybe_ident = TRY(parse_css_value(part));
|
|
||||||
if (maybe_ident) {
|
// CSS-wide keywords are not allowed
|
||||||
// CSS-wide keywords are not allowed
|
if (auto builtin = TRY(parse_builtin_value(peek)))
|
||||||
if (maybe_ident->is_builtin())
|
return nullptr;
|
||||||
|
|
||||||
|
auto maybe_ident = value_id_from_string(peek.token().ident());
|
||||||
|
// Can't have a generic-font-name as a token in an unquoted font name.
|
||||||
|
if (maybe_ident.has_value() && is_generic_font_family(maybe_ident.value())) {
|
||||||
|
if (!current_name_parts.is_empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (is_generic_font_family(maybe_ident->to_identifier())) {
|
(void)tokens.next_token(); // Ident
|
||||||
// Can't have a generic-font-name as a token in an unquoted font name.
|
if (!next_is_comma_or_eof())
|
||||||
if (!current_name_parts.is_empty())
|
return nullptr;
|
||||||
return nullptr;
|
TRY(font_families.try_append(TRY(IdentifierStyleValue::create(maybe_ident.value()))));
|
||||||
if (!is_comma_or_eof(i + 1))
|
(void)tokens.next_token(); // Comma
|
||||||
return nullptr;
|
continue;
|
||||||
font_families.append(maybe_ident.release_nonnull());
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
current_name_parts.append(part.token().ident());
|
TRY(current_name_parts.try_append(tokens.next_token().token().ident()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (part.is(Token::Type::Comma)) {
|
|
||||||
|
if (peek.is(Token::Type::Comma)) {
|
||||||
if (current_name_parts.is_empty())
|
if (current_name_parts.is_empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
font_families.append(TRY(StringStyleValue::create(TRY(String::from_utf8(DeprecatedString::join(' ', current_name_parts))))));
|
(void)tokens.next_token(); // Comma
|
||||||
|
TRY(font_families.try_append(TRY(StringStyleValue::create(TRY(String::join(' ', current_name_parts))))));
|
||||||
current_name_parts.clear();
|
current_name_parts.clear();
|
||||||
// Can't have a trailing comma
|
// Can't have a trailing comma
|
||||||
if (i + 1 == component_values.size())
|
if (!tokens.has_next_token())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current_name_parts.is_empty()) {
|
if (!current_name_parts.is_empty()) {
|
||||||
font_families.append(TRY(StringStyleValue::create(TRY(String::from_utf8(DeprecatedString::join(' ', current_name_parts))))));
|
TRY(font_families.try_append(TRY(StringStyleValue::create(TRY(String::join(' ', current_name_parts))))));
|
||||||
current_name_parts.clear();
|
current_name_parts.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7036,10 +7043,12 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
|
||||||
if (auto parsed_value = FIXME_TRY(parse_font_value(component_values)))
|
if (auto parsed_value = FIXME_TRY(parse_font_value(component_values)))
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
return ParseError::SyntaxError;
|
return ParseError::SyntaxError;
|
||||||
case PropertyID::FontFamily:
|
case PropertyID::FontFamily: {
|
||||||
if (auto parsed_value = FIXME_TRY(parse_font_family_value(component_values)))
|
auto tokens_without_whitespace = TokenStream { component_values };
|
||||||
|
if (auto parsed_value = FIXME_TRY(parse_font_family_value(tokens_without_whitespace)))
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
return ParseError::SyntaxError;
|
return ParseError::SyntaxError;
|
||||||
|
}
|
||||||
case PropertyID::GridColumn:
|
case PropertyID::GridColumn:
|
||||||
if (auto parsed_value = FIXME_TRY(parse_grid_track_placement_shorthand_value(component_values)))
|
if (auto parsed_value = FIXME_TRY(parse_grid_track_placement_shorthand_value(component_values)))
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
|
|
|
@ -315,7 +315,7 @@ private:
|
||||||
ErrorOr<RefPtr<StyleValue>> parse_flex_value(Vector<ComponentValue> const&);
|
ErrorOr<RefPtr<StyleValue>> parse_flex_value(Vector<ComponentValue> const&);
|
||||||
ErrorOr<RefPtr<StyleValue>> parse_flex_flow_value(Vector<ComponentValue> const&);
|
ErrorOr<RefPtr<StyleValue>> parse_flex_flow_value(Vector<ComponentValue> const&);
|
||||||
ErrorOr<RefPtr<StyleValue>> parse_font_value(Vector<ComponentValue> const&);
|
ErrorOr<RefPtr<StyleValue>> parse_font_value(Vector<ComponentValue> const&);
|
||||||
ErrorOr<RefPtr<StyleValue>> parse_font_family_value(Vector<ComponentValue> const&, size_t start_index = 0);
|
ErrorOr<RefPtr<StyleValue>> parse_font_family_value(TokenStream<ComponentValue>&);
|
||||||
ErrorOr<RefPtr<StyleValue>> parse_list_style_value(Vector<ComponentValue> const&);
|
ErrorOr<RefPtr<StyleValue>> parse_list_style_value(Vector<ComponentValue> const&);
|
||||||
ErrorOr<RefPtr<StyleValue>> parse_overflow_value(Vector<ComponentValue> const&);
|
ErrorOr<RefPtr<StyleValue>> parse_overflow_value(Vector<ComponentValue> const&);
|
||||||
enum class AllowInsetKeyword {
|
enum class AllowInsetKeyword {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue