LibWeb: Parse and compute CSS quotes property

This commit is contained in:
Sam Atkins 2023-09-12 11:34:26 +01:00 committed by Andrew Kaster
parent 1bc081398e
commit dc7a52957e
Notes: sideshowbarker 2024-07-17 09:39:38 +09:00
7 changed files with 90 additions and 0 deletions

View File

@ -38,6 +38,15 @@ struct GridAutoFlow {
bool dense { false };
};
struct QuotesData {
enum class Type {
None,
Auto,
Specified,
} type;
Vector<Array<String, 2>> strings {};
};
class InitialValues {
public:
static AspectRatio aspect_ratio() { return AspectRatio { true, {} }; }
@ -120,6 +129,7 @@ public:
static CSS::OutlineStyle outline_style() { return CSS::OutlineStyle::None; }
static CSS::Length outline_width() { return CSS::Length::make_px(3); }
static CSS::TableLayout table_layout() { return CSS::TableLayout::Auto; }
static QuotesData quotes() { return QuotesData { .type = QuotesData::Type::Auto }; }
static CSS::MathShift math_shift() { return CSS::MathShift::Normal; }
static CSS::MathStyle math_style() { return CSS::MathStyle::Normal; }
@ -350,6 +360,8 @@ public:
CSS::TableLayout table_layout() const { return m_noninherited.table_layout; }
CSS::QuotesData quotes() const { return m_inherited.quotes; }
CSS::MathShift math_shift() const { return m_inherited.math_shift; }
CSS::MathStyle math_style() const { return m_inherited.math_style; }
int math_depth() const { return m_inherited.math_depth; }
@ -383,6 +395,7 @@ protected:
CSS::ListStyleType list_style_type { InitialValues::list_style_type() };
CSS::ListStylePosition list_style_position { InitialValues::list_style_position() };
CSS::Visibility visibility { InitialValues::visibility() };
CSS::QuotesData quotes { InitialValues::quotes() };
Optional<SVGPaint> fill;
CSS::FillRule fill_rule { InitialValues::fill_rule() };
@ -577,6 +590,7 @@ public:
void set_grid_auto_flow(CSS::GridAutoFlow grid_auto_flow) { m_noninherited.grid_auto_flow = grid_auto_flow; }
void set_transition_delay(CSS::Time const& transition_delay) { m_noninherited.transition_delay = transition_delay; }
void set_table_layout(CSS::TableLayout value) { m_noninherited.table_layout = value; }
void set_quotes(CSS::QuotesData value) { m_inherited.quotes = value; }
void set_fill(SVGPaint value) { m_inherited.fill = value; }
void set_stroke(SVGPaint value) { m_inherited.stroke = value; }

View File

@ -4586,6 +4586,35 @@ RefPtr<StyleValue> Parser::parse_place_self_value(Vector<ComponentValue> const&
return PlaceItemsStyleValue::create(*maybe_align_self_value, *maybe_justify_self_value);
}
RefPtr<StyleValue> Parser::parse_quotes_value(Vector<ComponentValue> const& component_values)
{
// https://www.w3.org/TR/css-content-3/#quotes-property
// auto | none | [ <string> <string> ]+
if (component_values.size() == 1) {
auto identifier = parse_identifier_value(component_values.first());
if (identifier && property_accepts_identifier(PropertyID::Quotes, identifier->to_identifier()))
return identifier;
return nullptr;
}
// Parse an even number of <string> values.
if (component_values.size() % 2 != 0)
return nullptr;
auto tokens = TokenStream { component_values };
StyleValueVector string_values;
while (tokens.has_next_token()) {
auto maybe_string = parse_string_value(tokens.next_token());
if (!maybe_string)
return nullptr;
string_values.append(maybe_string.release_nonnull());
}
return StyleValueList::create(move(string_values), StyleValueList::Separator::Space);
}
RefPtr<StyleValue> Parser::parse_text_decoration_value(Vector<ComponentValue> const& component_values)
{
RefPtr<StyleValue> decoration_line;
@ -5869,6 +5898,10 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
if (auto parsed_value = parse_place_self_value(component_values))
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::Quotes:
if (auto parsed_value = parse_quotes_value(component_values))
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::TextDecoration:
if (auto parsed_value = parse_text_decoration_value(component_values))
return parsed_value.release_nonnull();

View File

@ -243,6 +243,7 @@ private:
RefPtr<StyleValue> parse_place_content_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_place_items_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_place_self_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_quotes_value(Vector<ComponentValue> const&);
enum class AllowInsetKeyword {
No,
Yes,

View File

@ -1836,6 +1836,17 @@
"position"
]
},
"quotes": {
"inherited": true,
"initial": "auto",
"valid-types": [
"string"
],
"valid-identifiers": [
"auto",
"none"
]
},
"right": {
"inherited": false,
"initial": "auto",

View File

@ -990,4 +990,32 @@ void StyleProperties::set_math_depth(int math_depth)
set_property(PropertyID::MathDepth, MathDepthStyleValue::create_integer(IntegerStyleValue::create(math_depth)));
}
QuotesData StyleProperties::quotes() const
{
auto value = property(CSS::PropertyID::Quotes);
if (value->is_identifier()) {
switch (value->to_identifier()) {
case ValueID::Auto:
return QuotesData { .type = QuotesData::Type::Auto };
case ValueID::None:
return QuotesData { .type = QuotesData::Type::None };
default:
break;
}
}
if (value->is_value_list()) {
auto& value_list = value->as_value_list();
QuotesData quotes_data { .type = QuotesData::Type::Specified };
VERIFY(value_list.size() % 2 == 0);
for (auto i = 0u; i < value_list.size(); i += 2) {
quotes_data.strings.empend(
value_list.value_at(i, false)->as_string().string_value(),
value_list.value_at(i + 1, false)->as_string().string_value());
}
return quotes_data;
}
return InitialValues::quotes();
}
}

View File

@ -146,6 +146,8 @@ public:
void set_math_depth(int math_depth);
int math_depth() const { return m_math_depth; }
QuotesData quotes() const;
static NonnullRefPtr<Gfx::Font const> font_fallback(bool monospace, bool bold);
private:

View File

@ -806,6 +806,7 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
computed_values.set_math_style(math_style.value());
computed_values.set_math_depth(computed_style.math_depth());
computed_values.set_quotes(computed_style.quotes());
// Update any anonymous children that inherit from this node.
// FIXME: This is pretty hackish. It would be nicer if they shared the inherited style