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:
parent
85da8cbb07
commit
7c91fda088
9 changed files with 142 additions and 66 deletions
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue