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:
parent
a9ad72cc0f
commit
adaab23149
6 changed files with 120 additions and 0 deletions
|
@ -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());
|
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)
|
RefPtr<StyleValue> Parser::parse_flex_value(Vector<StyleComponentValueRule> const& component_values)
|
||||||
{
|
{
|
||||||
if (component_values.size() == 1) {
|
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))
|
if (auto parsed_value = parse_box_shadow_value(component_values))
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
return ParsingResult::SyntaxError;
|
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:
|
case PropertyID::Flex:
|
||||||
if (auto parsed_value = parse_flex_value(component_values))
|
if (auto parsed_value = parse_flex_value(component_values))
|
||||||
return parsed_value.release_nonnull();
|
return parsed_value.release_nonnull();
|
||||||
|
|
|
@ -274,6 +274,7 @@ private:
|
||||||
RefPtr<StyleValue> parse_border_radius_shorthand_value(Vector<StyleComponentValueRule> const&);
|
RefPtr<StyleValue> parse_border_radius_shorthand_value(Vector<StyleComponentValueRule> const&);
|
||||||
RefPtr<StyleValue> parse_box_shadow_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_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_value(Vector<StyleComponentValueRule> const&);
|
||||||
RefPtr<StyleValue> parse_flex_flow_value(Vector<StyleComponentValueRule> const&);
|
RefPtr<StyleValue> parse_flex_flow_value(Vector<StyleComponentValueRule> const&);
|
||||||
RefPtr<StyleValue> parse_font_value(Vector<StyleComponentValueRule> const&);
|
RefPtr<StyleValue> parse_font_value(Vector<StyleComponentValueRule> const&);
|
||||||
|
|
|
@ -510,6 +510,18 @@
|
||||||
"hashless-hex-color"
|
"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": {
|
"cursor": {
|
||||||
"inherited": true,
|
"inherited": true,
|
||||||
"initial": "auto",
|
"initial": "auto",
|
||||||
|
|
|
@ -81,6 +81,12 @@ ColorStyleValue const& StyleValue::as_color() const
|
||||||
return static_cast<ColorStyleValue const&>(*this);
|
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
|
FlexStyleValue const& StyleValue::as_flex() const
|
||||||
{
|
{
|
||||||
VERIFY(is_flex());
|
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());
|
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
|
String FlexStyleValue::to_string() const
|
||||||
{
|
{
|
||||||
return String::formatted("{} {} {}", m_grow->to_string(), m_shrink->to_string(), m_basis->to_string());
|
return String::formatted("{} {} {}", m_grow->to_string(), m_shrink->to_string(), m_basis->to_string());
|
||||||
|
|
|
@ -297,6 +297,7 @@ public:
|
||||||
Calculated,
|
Calculated,
|
||||||
Color,
|
Color,
|
||||||
CombinedBorderRadius,
|
CombinedBorderRadius,
|
||||||
|
Content,
|
||||||
Flex,
|
Flex,
|
||||||
FlexFlow,
|
FlexFlow,
|
||||||
Font,
|
Font,
|
||||||
|
@ -333,6 +334,7 @@ public:
|
||||||
bool is_box_shadow() const { return type() == Type::BoxShadow; }
|
bool is_box_shadow() const { return type() == Type::BoxShadow; }
|
||||||
bool is_calculated() const { return type() == Type::Calculated; }
|
bool is_calculated() const { return type() == Type::Calculated; }
|
||||||
bool is_color() const { return type() == Type::Color; }
|
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() const { return type() == Type::Flex; }
|
||||||
bool is_flex_flow() const { return type() == Type::FlexFlow; }
|
bool is_flex_flow() const { return type() == Type::FlexFlow; }
|
||||||
bool is_font() const { return type() == Type::Font; }
|
bool is_font() const { return type() == Type::Font; }
|
||||||
|
@ -367,6 +369,7 @@ public:
|
||||||
BoxShadowStyleValue const& as_box_shadow() const;
|
BoxShadowStyleValue const& as_box_shadow() const;
|
||||||
CalculatedStyleValue const& as_calculated() const;
|
CalculatedStyleValue const& as_calculated() const;
|
||||||
ColorStyleValue const& as_color() const;
|
ColorStyleValue const& as_color() const;
|
||||||
|
ContentStyleValue const& as_content() const;
|
||||||
FlexFlowStyleValue const& as_flex_flow() const;
|
FlexFlowStyleValue const& as_flex_flow() const;
|
||||||
FlexStyleValue const& as_flex() const;
|
FlexStyleValue const& as_flex() const;
|
||||||
FontStyleValue const& as_font() 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()); }
|
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()); }
|
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()); }
|
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()); }
|
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()); }
|
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()); }
|
FontStyleValue& as_font() { return const_cast<FontStyleValue&>(const_cast<StyleValue const&>(*this).as_font()); }
|
||||||
|
@ -969,6 +973,31 @@ private:
|
||||||
NonnullRefPtr<BorderRadiusStyleValue> m_bottom_left;
|
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 {
|
class FlexStyleValue final : public StyleValue {
|
||||||
public:
|
public:
|
||||||
static NonnullRefPtr<FlexStyleValue> create(
|
static NonnullRefPtr<FlexStyleValue> create(
|
||||||
|
|
|
@ -30,6 +30,7 @@ class BorderStyleValue;
|
||||||
class BoxShadowStyleValue;
|
class BoxShadowStyleValue;
|
||||||
class CalculatedStyleValue;
|
class CalculatedStyleValue;
|
||||||
class ColorStyleValue;
|
class ColorStyleValue;
|
||||||
|
class ContentStyleValue;
|
||||||
class CSSImportRule;
|
class CSSImportRule;
|
||||||
class CSSMediaRule;
|
class CSSMediaRule;
|
||||||
class CSSRule;
|
class CSSRule;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue