1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-29 13:15:08 +00:00

LibWeb: Parse the content property

For now, we only understand `none`, `normal`, `<image>` and `<string>`.
The various other functions and identifiers can be added later.

We can *almost* use a StyleValueList for this, except it's divided into
two parts - the content, and the optional "alt text". So, I've added a
new StyleValue for it.
This commit is contained in:
Sam Atkins 2022-02-23 19:56:25 +00:00 committed by Andreas Kling
parent a9ad72cc0f
commit adaab23149
6 changed files with 120 additions and 0 deletions

View file

@ -3280,6 +3280,66 @@ RefPtr<StyleValue> Parser::parse_single_box_shadow_value(TokenStream<StyleCompon
return BoxShadowStyleValue::create(color.release_value(), offset_x.release_value(), offset_y.release_value(), blur_radius.release_value(), spread_distance.release_value(), placement.release_value());
}
RefPtr<StyleValue> Parser::parse_content_value(Vector<StyleComponentValueRule> const& component_values)
{
// FIXME: `content` accepts several kinds of function() type, which we don't handle in property_accepts_value() yet.
auto is_single_value_identifier = [](ValueID identifier) -> bool {
switch (identifier) {
case ValueID::None:
case ValueID::Normal:
return true;
default:
return false;
}
};
if (component_values.size() == 1) {
if (auto identifier = parse_identifier_value(component_values.first())) {
if (is_single_value_identifier(identifier->to_identifier()))
return identifier;
}
}
NonnullRefPtrVector<StyleValue> content_values;
NonnullRefPtrVector<StyleValue> alt_text_values;
bool in_alt_text = false;
for (auto const& value : component_values) {
if (value.is(Token::Type::Delim) && value.token().delim() == "/"sv) {
if (in_alt_text || content_values.is_empty())
return {};
in_alt_text = true;
continue;
}
auto style_value = parse_css_value(value);
if (style_value && property_accepts_value(PropertyID::Content, *style_value)) {
if (is_single_value_identifier(style_value->to_identifier()))
return {};
if (in_alt_text) {
alt_text_values.append(style_value.release_nonnull());
} else {
content_values.append(style_value.release_nonnull());
}
continue;
}
return {};
}
if (content_values.is_empty())
return {};
if (in_alt_text && alt_text_values.is_empty())
return {};
RefPtr<StyleValueList> alt_text;
if (!alt_text_values.is_empty())
alt_text = StyleValueList::create(move(alt_text_values), StyleValueList::Separator::Space);
return ContentStyleValue::create(StyleValueList::create(move(content_values), StyleValueList::Separator::Space), move(alt_text));
}
RefPtr<StyleValue> Parser::parse_flex_value(Vector<StyleComponentValueRule> const& component_values)
{
if (component_values.size() == 1) {
@ -3864,6 +3924,10 @@ Result<NonnullRefPtr<StyleValue>, Parser::ParsingResult> Parser::parse_css_value
if (auto parsed_value = parse_box_shadow_value(component_values))
return parsed_value.release_nonnull();
return ParsingResult::SyntaxError;
case PropertyID::Content:
if (auto parsed_value = parse_content_value(component_values))
return parsed_value.release_nonnull();
return ParsingResult::SyntaxError;
case PropertyID::Flex:
if (auto parsed_value = parse_flex_value(component_values))
return parsed_value.release_nonnull();

View file

@ -274,6 +274,7 @@ private:
RefPtr<StyleValue> parse_border_radius_shorthand_value(Vector<StyleComponentValueRule> const&);
RefPtr<StyleValue> parse_box_shadow_value(Vector<StyleComponentValueRule> const&);
RefPtr<StyleValue> parse_single_box_shadow_value(TokenStream<StyleComponentValueRule>&);
RefPtr<StyleValue> parse_content_value(Vector<StyleComponentValueRule> const&);
RefPtr<StyleValue> parse_flex_value(Vector<StyleComponentValueRule> const&);
RefPtr<StyleValue> parse_flex_flow_value(Vector<StyleComponentValueRule> const&);
RefPtr<StyleValue> parse_font_value(Vector<StyleComponentValueRule> const&);

View file

@ -510,6 +510,18 @@
"hashless-hex-color"
]
},
"content": {
"inherited": false,
"initial": "normal",
"__comment": "FIXME: This accepts a whole lot of other types and identifiers!",
"valid-types": [
"string"
],
"valid-identifiers": [
"normal",
"none"
]
},
"cursor": {
"inherited": true,
"initial": "auto",

View file

@ -81,6 +81,12 @@ ColorStyleValue const& StyleValue::as_color() const
return static_cast<ColorStyleValue const&>(*this);
}
ContentStyleValue const& StyleValue::as_content() const
{
VERIFY(is_content());
return static_cast<ContentStyleValue const&>(*this);
}
FlexStyleValue const& StyleValue::as_flex() const
{
VERIFY(is_flex());
@ -1015,6 +1021,13 @@ String CombinedBorderRadiusStyleValue::to_string() const
return String::formatted("{} {} {} {} / {} {} {} {}", m_top_left->horizontal_radius().to_string(), m_top_right->horizontal_radius().to_string(), m_bottom_right->horizontal_radius().to_string(), m_bottom_left->horizontal_radius().to_string(), m_top_left->vertical_radius().to_string(), m_top_right->vertical_radius().to_string(), m_bottom_right->vertical_radius().to_string(), m_bottom_left->vertical_radius().to_string());
}
String ContentStyleValue::to_string() const
{
if (has_alt_text())
return String::formatted("{} / {}", m_content->to_string(), m_alt_text->to_string());
return m_content->to_string();
}
String FlexStyleValue::to_string() const
{
return String::formatted("{} {} {}", m_grow->to_string(), m_shrink->to_string(), m_basis->to_string());

View file

@ -297,6 +297,7 @@ public:
Calculated,
Color,
CombinedBorderRadius,
Content,
Flex,
FlexFlow,
Font,
@ -333,6 +334,7 @@ public:
bool is_box_shadow() const { return type() == Type::BoxShadow; }
bool is_calculated() const { return type() == Type::Calculated; }
bool is_color() const { return type() == Type::Color; }
bool is_content() const { return type() == Type::Content; }
bool is_flex() const { return type() == Type::Flex; }
bool is_flex_flow() const { return type() == Type::FlexFlow; }
bool is_font() const { return type() == Type::Font; }
@ -367,6 +369,7 @@ public:
BoxShadowStyleValue const& as_box_shadow() const;
CalculatedStyleValue const& as_calculated() const;
ColorStyleValue const& as_color() const;
ContentStyleValue const& as_content() const;
FlexFlowStyleValue const& as_flex_flow() const;
FlexStyleValue const& as_flex() const;
FontStyleValue const& as_font() const;
@ -399,6 +402,7 @@ public:
BoxShadowStyleValue& as_box_shadow() { return const_cast<BoxShadowStyleValue&>(const_cast<StyleValue const&>(*this).as_box_shadow()); }
CalculatedStyleValue& as_calculated() { return const_cast<CalculatedStyleValue&>(const_cast<StyleValue const&>(*this).as_calculated()); }
ColorStyleValue& as_color() { return const_cast<ColorStyleValue&>(const_cast<StyleValue const&>(*this).as_color()); }
ContentStyleValue& as_content() { return const_cast<ContentStyleValue&>(const_cast<StyleValue const&>(*this).as_content()); }
FlexFlowStyleValue& as_flex_flow() { return const_cast<FlexFlowStyleValue&>(const_cast<StyleValue const&>(*this).as_flex_flow()); }
FlexStyleValue& as_flex() { return const_cast<FlexStyleValue&>(const_cast<StyleValue const&>(*this).as_flex()); }
FontStyleValue& as_font() { return const_cast<FontStyleValue&>(const_cast<StyleValue const&>(*this).as_font()); }
@ -969,6 +973,31 @@ private:
NonnullRefPtr<BorderRadiusStyleValue> m_bottom_left;
};
class ContentStyleValue final : public StyleValue {
public:
static NonnullRefPtr<ContentStyleValue> create(NonnullRefPtr<StyleValueList> content, RefPtr<StyleValueList> alt_text)
{
return adopt_ref(*new ContentStyleValue(move(content), move(alt_text)));
}
StyleValueList const& content() const { return *m_content; }
bool has_alt_text() const { return !m_alt_text.is_null(); }
StyleValueList const* alt_text() const { return m_alt_text; }
virtual String to_string() const override;
private:
ContentStyleValue(NonnullRefPtr<StyleValueList> content, RefPtr<StyleValueList> alt_text)
: StyleValue(Type::Content)
, m_content(move(content))
, m_alt_text(move(alt_text))
{
}
NonnullRefPtr<StyleValueList> m_content;
RefPtr<StyleValueList> m_alt_text;
};
class FlexStyleValue final : public StyleValue {
public:
static NonnullRefPtr<FlexStyleValue> create(

View file

@ -30,6 +30,7 @@ class BorderStyleValue;
class BoxShadowStyleValue;
class CalculatedStyleValue;
class ColorStyleValue;
class ContentStyleValue;
class CSSImportRule;
class CSSMediaRule;
class CSSRule;