mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:37:34 +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
|
@ -121,7 +121,7 @@ public:
|
|||
Optional<int> const& z_index() const { return m_noninherited.z_index; }
|
||||
CSS::TextAlign text_align() const { return m_inherited.text_align; }
|
||||
CSS::TextJustify text_justify() const { return m_inherited.text_justify; }
|
||||
CSS::TextDecorationLine text_decoration_line() const { return m_noninherited.text_decoration_line; }
|
||||
Vector<CSS::TextDecorationLine> text_decoration_line() const { return m_noninherited.text_decoration_line; }
|
||||
CSS::LengthPercentage text_decoration_thickness() const { return m_noninherited.text_decoration_thickness; }
|
||||
CSS::TextDecorationStyle text_decoration_style() const { return m_noninherited.text_decoration_style; }
|
||||
Color text_decoration_color() const { return m_noninherited.text_decoration_color; }
|
||||
|
@ -217,7 +217,8 @@ protected:
|
|||
CSS::Clear clear { InitialValues::clear() };
|
||||
CSS::Display display { InitialValues::display() };
|
||||
Optional<int> z_index;
|
||||
CSS::TextDecorationLine text_decoration_line { InitialValues::text_decoration_line() };
|
||||
// FIXME: Store this as flags in a u8.
|
||||
Vector<CSS::TextDecorationLine> text_decoration_line { InitialValues::text_decoration_line() };
|
||||
CSS::LengthPercentage text_decoration_thickness { InitialValues::text_decoration_thickness() };
|
||||
CSS::TextDecorationStyle text_decoration_style { InitialValues::text_decoration_style() };
|
||||
Color text_decoration_color { InitialValues::color() };
|
||||
|
@ -282,7 +283,7 @@ public:
|
|||
void set_z_index(Optional<int> value) { m_noninherited.z_index = value; }
|
||||
void set_text_align(CSS::TextAlign text_align) { m_inherited.text_align = text_align; }
|
||||
void set_text_justify(CSS::TextJustify text_justify) { m_inherited.text_justify = text_justify; }
|
||||
void set_text_decoration_line(CSS::TextDecorationLine value) { m_noninherited.text_decoration_line = value; }
|
||||
void set_text_decoration_line(Vector<CSS::TextDecorationLine> value) { m_noninherited.text_decoration_line = move(value); }
|
||||
void set_text_decoration_thickness(CSS::LengthPercentage value) { m_noninherited.text_decoration_thickness = value; }
|
||||
void set_text_decoration_style(CSS::TextDecorationStyle value) { m_noninherited.text_decoration_style = value; }
|
||||
void set_text_decoration_color(Color value) { m_noninherited.text_decoration_color = value; }
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -319,6 +319,7 @@ private:
|
|||
RefPtr<StyleValue> parse_shadow_value(Vector<ComponentValue> const&, AllowInsetKeyword);
|
||||
RefPtr<StyleValue> parse_single_shadow_value(TokenStream<ComponentValue>&, AllowInsetKeyword);
|
||||
RefPtr<StyleValue> parse_text_decoration_value(Vector<ComponentValue> const&);
|
||||
RefPtr<StyleValue> parse_text_decoration_line_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue> parse_transform_value(Vector<ComponentValue> const&);
|
||||
RefPtr<StyleValue> parse_transform_origin_value(Vector<ComponentValue> const&);
|
||||
|
||||
|
|
|
@ -140,8 +140,16 @@ RefPtr<StyleValue> ResolvedCSSStyleDeclaration::style_value_for_property(Layout:
|
|||
}
|
||||
case CSS::PropertyID::TextAlign:
|
||||
return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().text_align()));
|
||||
case CSS::PropertyID::TextDecorationLine:
|
||||
return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().text_decoration_line()));
|
||||
case CSS::PropertyID::TextDecorationLine: {
|
||||
auto text_decoration_lines = layout_node.computed_values().text_decoration_line();
|
||||
if (text_decoration_lines.is_empty())
|
||||
return IdentifierStyleValue::create(ValueID::None);
|
||||
NonnullRefPtrVector<StyleValue> style_values;
|
||||
for (auto const& line : text_decoration_lines) {
|
||||
style_values.append(IdentifierStyleValue::create(to_value_id(line)));
|
||||
}
|
||||
return StyleValueList::create(move(style_values), StyleValueList::Separator::Space);
|
||||
}
|
||||
case CSS::PropertyID::TextDecorationStyle:
|
||||
return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().text_decoration_style()));
|
||||
case CSS::PropertyID::TextTransform:
|
||||
|
|
|
@ -490,10 +490,23 @@ CSS::Display StyleProperties::display() const
|
|||
}
|
||||
}
|
||||
|
||||
Optional<CSS::TextDecorationLine> StyleProperties::text_decoration_line() const
|
||||
Vector<CSS::TextDecorationLine> StyleProperties::text_decoration_line() const
|
||||
{
|
||||
auto value = property(CSS::PropertyID::TextDecorationLine);
|
||||
return value_id_to_text_decoration_line(value->to_identifier());
|
||||
|
||||
if (value->is_value_list()) {
|
||||
Vector<CSS::TextDecorationLine> lines;
|
||||
auto& values = value->as_value_list().values();
|
||||
for (auto const& item : values) {
|
||||
lines.append(value_id_to_text_decoration_line(item.to_identifier()).value());
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
if (value->is_identifier() && value->to_identifier() == ValueID::None)
|
||||
return {};
|
||||
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
Optional<CSS::TextDecorationStyle> StyleProperties::text_decoration_style() const
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
Optional<CSS::Cursor> cursor() const;
|
||||
Optional<CSS::WhiteSpace> white_space() const;
|
||||
Optional<CSS::LineStyle> line_style(CSS::PropertyID) const;
|
||||
Optional<CSS::TextDecorationLine> text_decoration_line() const;
|
||||
Vector<CSS::TextDecorationLine> text_decoration_line() const;
|
||||
Optional<CSS::TextDecorationStyle> text_decoration_style() const;
|
||||
Optional<CSS::TextTransform> text_transform() const;
|
||||
Vector<CSS::ShadowData> text_shadow() const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue