1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 08:18:12 +00:00

LibWeb: Implement and use BackgroundRepeatStyleValue

This wraps an x and y background-repeat value. Potentially, we could use
this in place of the background-repeat-x and background-repeat-y
pseudo-properties, but for now StyleResolver splits it into those
properties, like it did before.
This commit is contained in:
Sam Atkins 2021-08-10 10:21:42 +01:00 committed by Andreas Kling
parent e6c0cb5a7f
commit 6f9263de04
4 changed files with 114 additions and 45 deletions

View file

@ -1746,22 +1746,23 @@ RefPtr<StyleValue> Parser::parse_image_value(ParsingContext const& context, Styl
return {};
}
static inline bool is_background_repeat(StyleValue const& value)
{
switch (value.to_identifier()) {
case ValueID::NoRepeat:
case ValueID::Repeat:
case ValueID::RepeatX:
case ValueID::RepeatY:
case ValueID::Round:
case ValueID::Space:
return true;
default:
return false;
}
}
RefPtr<StyleValue> Parser::parse_background_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
{
auto is_background_repeat = [](StyleValue const& value) -> bool {
switch (value.to_identifier()) {
case CSS::ValueID::NoRepeat:
case CSS::ValueID::Repeat:
case CSS::ValueID::RepeatX:
case CSS::ValueID::RepeatY:
case CSS::ValueID::Round:
case CSS::ValueID::Space:
return true;
default:
return false;
}
};
auto is_background_image = [](StyleValue const& value) -> bool {
if (value.is_image())
return true;
@ -1848,6 +1849,50 @@ RefPtr<StyleValue> Parser::parse_background_value(ParsingContext const& context,
return BackgroundStyleValue::create(background_color.release_nonnull(), background_image.release_nonnull(), repeat_x.release_nonnull(), repeat_y.release_nonnull());
}
RefPtr<StyleValue> Parser::parse_background_repeat_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
{
auto is_directional_repeat = [](StyleValue const& value) -> bool {
auto value_id = value.to_identifier();
return value_id == ValueID::RepeatX || value_id == ValueID::RepeatY;
};
if (component_values.size() == 1) {
auto maybe_value = parse_css_value(context, PropertyID::BackgroundRepeat, component_values.first());
if (!maybe_value)
return nullptr;
auto value = maybe_value.release_nonnull();
if (!is_background_repeat(*value))
return nullptr;
if (is_directional_repeat(value)) {
auto value_id = value->to_identifier();
return BackgroundRepeatStyleValue::create(
IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::Repeat : ValueID::NoRepeat),
IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::NoRepeat : ValueID::Repeat));
}
return BackgroundRepeatStyleValue::create(value, value);
}
if (component_values.size() == 2) {
auto maybe_x_value = parse_css_value(context, PropertyID::BackgroundRepeatX, component_values[0]);
auto maybe_y_value = parse_css_value(context, PropertyID::BackgroundRepeatY, component_values[1]);
if (!maybe_x_value || !maybe_y_value)
return nullptr;
auto x_value = maybe_x_value.release_nonnull();
auto y_value = maybe_y_value.release_nonnull();
if (!is_background_repeat(x_value) || !is_background_repeat(y_value))
return nullptr;
if (is_directional_repeat(x_value) || is_directional_repeat(y_value))
return nullptr;
return BackgroundRepeatStyleValue::create(x_value, y_value);
}
// FIXME: Handle multiple sets of comma-separated values.
dbgln("CSS Parser does not yet support multiple comma-separated values for background-repeat.");
return nullptr;
}
RefPtr<StyleValue> Parser::parse_border_value(ParsingContext const& context, PropertyID property_id, Vector<StyleComponentValueRule> const& component_values)
{
auto is_line_style = [](StyleValue const& value) -> bool {
@ -2652,6 +2697,10 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S
if (auto parsed_value = parse_background_value(m_context, component_values))
return parsed_value;
break;
case PropertyID::BackgroundRepeat:
if (auto parsed_value = parse_background_repeat_value(m_context, component_values))
return parsed_value;
break;
case PropertyID::Border:
case PropertyID::BorderBottom:
case PropertyID::BorderLeft:

View file

@ -176,6 +176,7 @@ private:
static RefPtr<StyleValue> parse_string_value(ParsingContext const&, StyleComponentValueRule const&);
static RefPtr<StyleValue> parse_image_value(ParsingContext const&, StyleComponentValueRule const&);
static RefPtr<StyleValue> parse_background_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
static RefPtr<StyleValue> parse_background_repeat_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
static RefPtr<StyleValue> parse_border_value(ParsingContext const&, PropertyID, Vector<StyleComponentValueRule> const&);
static RefPtr<StyleValue> parse_border_radius_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
static RefPtr<StyleValue> parse_border_radius_shorthand_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);

View file

@ -427,41 +427,30 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
}
if (property_id == CSS::PropertyID::BackgroundRepeat) {
auto assign_background_repeat_from_single_value = [&](StyleValue const& value) {
auto value_id = value.to_identifier();
if (value_id == ValueID::RepeatX || value_id == ValueID::RepeatY) {
auto repeat_x = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::Repeat : ValueID::NoRepeat);
auto repeat_y = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::NoRepeat : ValueID::Repeat);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, repeat_x, document, true);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, repeat_y, document, true);
} else {
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, value, document, true);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, value, document, true);
}
};
if (value.is_component_value_list()) {
auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values();
NonnullRefPtrVector<StyleValue> repeat_values;
for (auto& part : parts) {
if (part.is(Token::Type::Comma)) {
// FIXME: Handle multiple backgrounds.
break;
if (value.is_value_list()) {
auto& background_repeat_list = static_cast<CSS::StyleValueList const&>(value).values();
// FIXME: Handle multiple backgrounds.
if (!background_repeat_list.is_empty()) {
auto& maybe_background_repeat = background_repeat_list.first();
if (maybe_background_repeat.is_background_repeat()) {
auto& background_repeat = static_cast<BackgroundRepeatStyleValue const&>(maybe_background_repeat);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, background_repeat.repeat_x(), document, true);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, background_repeat.repeat_y(), document, true);
}
auto parsed_value = Parser::parse_css_value(context, property_id, part);
if (parsed_value)
repeat_values.append(parsed_value.release_nonnull());
}
if (repeat_values.size() == 1) {
assign_background_repeat_from_single_value(repeat_values[0]);
} else if (repeat_values.size() == 2) {
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, repeat_values[0], document, true);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, repeat_values[1], document, true);
}
return;
}
assign_background_repeat_from_single_value(value);
if (value.is_background_repeat()) {
auto& background_repeat = static_cast<BackgroundRepeatStyleValue const&>(value);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, background_repeat.repeat_x(), document, true);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, background_repeat.repeat_y(), document, true);
return;
}
if (value.is_builtin()) {
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatX, value, document, true);
set_property_expanding_shorthands(style, PropertyID::BackgroundRepeatY, value, document, true);
return;
}
return;
}

View file

@ -230,6 +230,7 @@ public:
ComponentValueList,
Calculated,
Background,
BackgroundRepeat,
Border,
BorderRadius,
BoxShadow,
@ -256,6 +257,7 @@ public:
bool is_component_value_list() const { return type() == Type::ComponentValueList; }
bool is_calculated() const { return type() == Type::Calculated; }
bool is_background() const { return type() == Type::Background; }
bool is_background_repeat() const { return type() == Type::BackgroundRepeat; }
bool is_border() const { return type() == Type::Border; }
bool is_border_radius() const { return type() == Type::BorderRadius; }
bool is_box_shadow() const { return type() == Type::BoxShadow; }
@ -687,6 +689,34 @@ private:
// FIXME: background-origin
};
class BackgroundRepeatStyleValue final : public StyleValue {
public:
static NonnullRefPtr<BackgroundRepeatStyleValue> create(NonnullRefPtr<StyleValue> repeat_x, NonnullRefPtr<StyleValue> repeat_y)
{
return adopt_ref(*new BackgroundRepeatStyleValue(repeat_x, repeat_y));
}
virtual ~BackgroundRepeatStyleValue() override { }
NonnullRefPtr<StyleValue> repeat_x() const { return m_repeat_x; }
NonnullRefPtr<StyleValue> repeat_y() const { return m_repeat_y; }
virtual String to_string() const override
{
return String::formatted("{} {}", m_repeat_x->to_string(), m_repeat_y->to_string());
}
private:
BackgroundRepeatStyleValue(NonnullRefPtr<StyleValue> repeat_x, NonnullRefPtr<StyleValue> repeat_y)
: StyleValue(Type::BackgroundRepeat)
, m_repeat_x(repeat_x)
, m_repeat_y(repeat_y)
{
}
NonnullRefPtr<StyleValue> m_repeat_x;
NonnullRefPtr<StyleValue> m_repeat_y;
};
class BorderStyleValue final : public StyleValue {
public:
static NonnullRefPtr<BorderStyleValue> create(