1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-29 03:52:12 +00:00

LibWeb: Allow multiple text-decoration-lines

The spec grammar for `text-decoration-line` is:

`none | [ underline || overline || line-through || blink ]`

Which means that it's either `none`, or any combination of the other
values. This patch makes that parse for `text-decoration-line` and
`text-decoration`, stores the results as a Vector, and adjusts
`paint_text_decoration()` to run as a loop over all the values that are
provided.

As noted, storing a Vector of values is a bit wasteful, as they could be
stored as flags in a single `u8`. But I was getting too confused trying
to do that in a nice way.
This commit is contained in:
Sam Atkins 2022-04-14 16:22:35 +01:00 committed by Andreas Kling
parent 85da8cbb07
commit 7c91fda088
9 changed files with 142 additions and 66 deletions

View file

@ -4673,15 +4673,15 @@ RefPtr<StyleValue> Parser::parse_overflow_value(Vector<ComponentValue> const& co
RefPtr<StyleValue> Parser::parse_text_decoration_value(Vector<ComponentValue> const& component_values)
{
if (component_values.size() > 4)
return nullptr;
RefPtr<StyleValue> decoration_line;
RefPtr<StyleValue> decoration_thickness;
RefPtr<StyleValue> decoration_style;
RefPtr<StyleValue> decoration_color;
for (auto& part : component_values) {
auto tokens = TokenStream { component_values };
while (tokens.has_next_token()) {
auto& part = tokens.next_token();
auto value = parse_css_value(part);
if (!value)
return nullptr;
@ -4695,7 +4695,11 @@ RefPtr<StyleValue> Parser::parse_text_decoration_value(Vector<ComponentValue> co
if (property_accepts_value(PropertyID::TextDecorationLine, *value)) {
if (decoration_line)
return nullptr;
decoration_line = value.release_nonnull();
tokens.reconsume_current_input_token();
auto parsed_decoration_line = parse_text_decoration_line_value(tokens);
if (!parsed_decoration_line)
return nullptr;
decoration_line = parsed_decoration_line.release_nonnull();
continue;
}
if (property_accepts_value(PropertyID::TextDecorationThickness, *value)) {
@ -4726,6 +4730,45 @@ RefPtr<StyleValue> Parser::parse_text_decoration_value(Vector<ComponentValue> co
return TextDecorationStyleValue::create(decoration_line.release_nonnull(), decoration_thickness.release_nonnull(), decoration_style.release_nonnull(), decoration_color.release_nonnull());
}
RefPtr<StyleValue> Parser::parse_text_decoration_line_value(TokenStream<ComponentValue>& tokens)
{
NonnullRefPtrVector<StyleValue> style_values;
while (tokens.has_next_token()) {
auto& token = tokens.next_token();
auto maybe_value = parse_css_value(token);
if (!maybe_value || !property_accepts_value(PropertyID::TextDecorationLine, *maybe_value)) {
tokens.reconsume_current_input_token();
break;
}
auto value = maybe_value.release_nonnull();
if (auto maybe_line = value_id_to_text_decoration_line(value->to_identifier()); maybe_line.has_value()) {
auto line = maybe_line.release_value();
if (line == TextDecorationLine::None) {
if (!style_values.is_empty()) {
tokens.reconsume_current_input_token();
break;
}
return value;
}
if (style_values.contains_slow(value)) {
tokens.reconsume_current_input_token();
break;
}
style_values.append(move(value));
continue;
}
tokens.reconsume_current_input_token();
break;
}
if (style_values.is_empty())
return nullptr;
return StyleValueList::create(move(style_values), StyleValueList::Separator::Space);
}
static Optional<CSS::TransformFunction> parse_transform_function_name(StringView name)
{
if (name == "matrix")
@ -5076,6 +5119,13 @@ Result<NonnullRefPtr<StyleValue>, Parser::ParsingResult> Parser::parse_css_value
if (auto parsed_value = parse_text_decoration_value(component_values))
return parsed_value.release_nonnull();
return ParsingResult::SyntaxError;
case PropertyID::TextDecorationLine: {
TokenStream tokens { component_values };
auto parsed_value = parse_text_decoration_line_value(tokens);
if (parsed_value && !tokens.has_next_token())
return parsed_value.release_nonnull();
return ParsingResult::SyntaxError;
}
case PropertyID::TextShadow:
if (auto parsed_value = parse_shadow_value(component_values, AllowInsetKeyword::No))
return parsed_value.release_nonnull();