mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 19:57:41 +00:00
LibWeb: Implement and use BackgroundStyleValue
This one represents one secton of a `background` property, since it can have multiple background values separated by commas. Eventually, we will represent that as a List of BackgroundStyleValues. Also modified some background-foo properties in StyleResolver so that the is_background_x() functions could be removed. I realized that our handling of var() in shorthand properties is wrong, so have been removing the is_builtin_or_dynamic() calls from the parsing code for shorthands. This broke our var() test page, so I have replaced the use of 'background' with 'background-color' there.
This commit is contained in:
parent
59501f1940
commit
dcbfb61816
5 changed files with 184 additions and 130 deletions
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
|
||||
.test {
|
||||
background: var(--my-color);
|
||||
background-color: var(--my-color);
|
||||
}
|
||||
|
||||
.test-parent {
|
||||
|
@ -37,7 +37,7 @@
|
|||
}
|
||||
|
||||
.test {
|
||||
background: var(--my-color);
|
||||
background-color: var(--my-color);
|
||||
}
|
||||
|
||||
.test-parent {
|
||||
|
|
|
@ -1746,6 +1746,108 @@ RefPtr<StyleValue> Parser::parse_image_value(ParsingContext const& context, Styl
|
|||
return {};
|
||||
}
|
||||
|
||||
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;
|
||||
if (value.to_identifier() == ValueID::None)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
RefPtr<StyleValue> background_color;
|
||||
RefPtr<StyleValue> background_image;
|
||||
RefPtr<StyleValue> repeat_x;
|
||||
RefPtr<StyleValue> repeat_y;
|
||||
// FIXME: Implement background-position.
|
||||
// FIXME: Implement background-size.
|
||||
// FIXME: Implement background-attachment.
|
||||
// FIXME: Implement background-clip.
|
||||
// FIXME: Implement background-origin.
|
||||
|
||||
for (size_t i = 0; i < component_values.size(); ++i) {
|
||||
auto& part = component_values[i];
|
||||
|
||||
// FIXME: Handle multiple backgrounds, by returning a List of BackgroundStyleValues.
|
||||
if (part.is(Token::Type::Comma)) {
|
||||
dbgln("CSS Parser does not yet support multiple comma-separated values for background.");
|
||||
break;
|
||||
}
|
||||
|
||||
auto value = parse_css_value(context, PropertyID::Background, part);
|
||||
if (!value) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (value->is_color()) {
|
||||
if (background_color)
|
||||
return nullptr;
|
||||
background_color = value.release_nonnull();
|
||||
continue;
|
||||
}
|
||||
if (is_background_image(*value)) {
|
||||
if (background_image)
|
||||
return nullptr;
|
||||
background_image = value.release_nonnull();
|
||||
continue;
|
||||
}
|
||||
if (is_background_repeat(*value)) {
|
||||
if (repeat_x)
|
||||
return nullptr;
|
||||
|
||||
auto value_id = value->to_identifier();
|
||||
if (value_id == ValueID::RepeatX || value_id == ValueID::RepeatY) {
|
||||
repeat_x = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::Repeat : ValueID::NoRepeat);
|
||||
repeat_y = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::NoRepeat : ValueID::Repeat);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check following value, if it's also a repeat, set both.
|
||||
if (i + 1 < component_values.size()) {
|
||||
auto next_value = parse_css_value(context, PropertyID::Background, component_values[i + 1]);
|
||||
if (next_value && is_background_repeat(*next_value)) {
|
||||
++i;
|
||||
repeat_x = value.release_nonnull();
|
||||
repeat_y = next_value.release_nonnull();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
auto repeat = value.release_nonnull();
|
||||
repeat_x = repeat;
|
||||
repeat_y = repeat;
|
||||
continue;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!background_color)
|
||||
background_color = ColorStyleValue::create(Color::Transparent);
|
||||
if (!background_image)
|
||||
background_image = IdentifierStyleValue::create(ValueID::None);
|
||||
if (!repeat_x)
|
||||
repeat_x = IdentifierStyleValue::create(ValueID::Repeat);
|
||||
if (!repeat_y)
|
||||
repeat_y = IdentifierStyleValue::create(ValueID::Repeat);
|
||||
|
||||
return BackgroundStyleValue::create(background_color.release_nonnull(), background_image.release_nonnull(), repeat_x.release_nonnull(), repeat_y.release_nonnull());
|
||||
}
|
||||
|
||||
RefPtr<StyleValue> Parser::parse_box_shadow_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
|
||||
{
|
||||
// FIXME: Also support inset, spread-radius and multiple comma-seperated box-shadows
|
||||
|
@ -1991,6 +2093,10 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S
|
|||
|
||||
// Special-case property handling
|
||||
switch (property_id) {
|
||||
case PropertyID::Background:
|
||||
if (auto parsed_value = parse_background_value(m_context, component_values))
|
||||
return parsed_value;
|
||||
break;
|
||||
case PropertyID::BoxShadow:
|
||||
if (auto parsed_box_shadow = parse_box_shadow_value(m_context, component_values))
|
||||
return parsed_box_shadow;
|
||||
|
|
|
@ -175,6 +175,7 @@ private:
|
|||
static RefPtr<StyleValue> parse_color_value(ParsingContext const&, StyleComponentValueRule const&);
|
||||
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_box_shadow_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
static RefPtr<StyleValue> parse_font_value(ParsingContext const&, Vector<StyleComponentValueRule> const&);
|
||||
|
||||
|
|
|
@ -208,35 +208,6 @@ static inline void set_property_border_style(StyleProperties& style, StyleValue
|
|||
style.set_property(CSS::PropertyID::BorderLeftStyle, value);
|
||||
}
|
||||
|
||||
static inline bool is_background_repeat(StyleValue const& value)
|
||||
{
|
||||
if (value.is_builtin_or_dynamic())
|
||||
return true;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_background_image(StyleValue const& value)
|
||||
{
|
||||
if (value.is_builtin_or_dynamic())
|
||||
return true;
|
||||
if (value.is_image())
|
||||
return true;
|
||||
if (value.to_identifier() == ValueID::None)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_color(StyleValue const& value)
|
||||
{
|
||||
if (value.is_builtin_or_dynamic())
|
||||
|
@ -748,98 +719,33 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
|||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::Background) {
|
||||
if (value.to_identifier() == ValueID::None) {
|
||||
style.set_property(CSS::PropertyID::BackgroundColor, ColorStyleValue::create(Color::Transparent));
|
||||
auto set_single_background = [&](CSS::BackgroundStyleValue const& background) {
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundColor, background.color(), document);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, background.image(), document);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, background.repeat_x(), document, true);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, background.repeat_y(), document, true);
|
||||
};
|
||||
|
||||
if (value.is_background()) {
|
||||
auto& background = static_cast<CSS::BackgroundStyleValue const&>(value);
|
||||
set_single_background(background);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_background_image(value)) {
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, value, document);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_color(value)) {
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundColor, value, document);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.is_component_value_list()) {
|
||||
auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values();
|
||||
|
||||
RefPtr<StyleValue> background_color_value;
|
||||
RefPtr<StyleValue> background_image_value;
|
||||
RefPtr<StyleValue> repeat_x_value;
|
||||
RefPtr<StyleValue> repeat_y_value;
|
||||
// FIXME: Implement background-position.
|
||||
// FIXME: Implement background-size.
|
||||
// FIXME: Implement background-attachment.
|
||||
// FIXME: Implement background-clip.
|
||||
// FIXME: Implement background-origin.
|
||||
|
||||
for (size_t i = 0; i < parts.size(); ++i) {
|
||||
auto& part = parts[i];
|
||||
|
||||
if (value.is_value_list()) {
|
||||
auto& background_list = static_cast<CSS::StyleValueList const&>(value).values();
|
||||
// FIXME: Handle multiple backgrounds.
|
||||
if (part.is(Token::Type::Comma))
|
||||
break;
|
||||
|
||||
auto value = Parser::parse_css_value(context, property_id, part);
|
||||
if (!value) {
|
||||
dbgln("Unable to parse token in `background` as a CSS value: '{}'", part.to_debug_string());
|
||||
if (!background_list.is_empty()) {
|
||||
auto& background = background_list.first();
|
||||
if (background.is_background())
|
||||
set_single_background(static_cast<CSS::BackgroundStyleValue const&>(background));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (value->is_color()) {
|
||||
if (background_color_value)
|
||||
return;
|
||||
background_color_value = move(value);
|
||||
continue;
|
||||
}
|
||||
if (is_background_image(*value)) {
|
||||
if (background_image_value)
|
||||
return;
|
||||
background_image_value = move(value);
|
||||
continue;
|
||||
}
|
||||
if (is_background_repeat(*value)) {
|
||||
if (repeat_x_value)
|
||||
return;
|
||||
|
||||
auto value_id = value->to_identifier();
|
||||
if (value_id == ValueID::RepeatX || value_id == ValueID::RepeatY) {
|
||||
repeat_x_value = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::Repeat : ValueID::NoRepeat);
|
||||
repeat_y_value = IdentifierStyleValue::create(value_id == ValueID::RepeatX ? ValueID::NoRepeat : ValueID::Repeat);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check following value, if it's also a repeat, set both.
|
||||
if (i + 1 < parts.size()) {
|
||||
auto next_value = Parser::parse_css_value(context, property_id, parts[i + 1]);
|
||||
if (next_value && is_background_repeat(*next_value)) {
|
||||
++i;
|
||||
repeat_x_value = move(value);
|
||||
repeat_y_value = move(next_value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
repeat_x_value = value;
|
||||
repeat_y_value = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
dbgln("Unhandled token in `background` declaration: '{}'", part.to_debug_string());
|
||||
return;
|
||||
}
|
||||
|
||||
if (background_color_value)
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundColor, background_color_value.release_nonnull(), document);
|
||||
if (background_image_value)
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, background_image_value.release_nonnull(), document);
|
||||
if (repeat_x_value)
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, repeat_x_value.release_nonnull(), document, true);
|
||||
if (repeat_y_value)
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, repeat_y_value.release_nonnull(), document, true);
|
||||
|
||||
if (value.is_builtin()) {
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundColor, value, document);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundImage, value, document);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, value, document, true);
|
||||
set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, value, document, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -847,11 +753,6 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
|||
}
|
||||
|
||||
if (property_id == CSS::PropertyID::BackgroundImage) {
|
||||
if (is_background_image(value)) {
|
||||
style.set_property(CSS::PropertyID::BackgroundImage, value);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Remove string parsing once DeprecatedCSSParser is gone.
|
||||
if (value.is_string()) {
|
||||
return;
|
||||
|
@ -882,7 +783,7 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
|||
return;
|
||||
}
|
||||
|
||||
dbgln("Unsure what to do with CSS background-image value '{}'", value.to_string());
|
||||
style.set_property(CSS::PropertyID::BackgroundImage, value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -900,10 +801,6 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
|||
}
|
||||
};
|
||||
|
||||
if (is_background_repeat(value)) {
|
||||
assign_background_repeat_from_single_value(value);
|
||||
}
|
||||
|
||||
if (value.is_component_value_list()) {
|
||||
auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values();
|
||||
NonnullRefPtrVector<StyleValue> repeat_values;
|
||||
|
@ -922,8 +819,10 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
|
|||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -229,6 +229,7 @@ public:
|
|||
ValueList,
|
||||
ComponentValueList,
|
||||
Calculated,
|
||||
Background,
|
||||
BoxShadow,
|
||||
Font,
|
||||
};
|
||||
|
@ -247,6 +248,7 @@ public:
|
|||
bool is_value_list() const { return type() == Type::ValueList; }
|
||||
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_box_shadow() const { return type() == Type::BoxShadow; }
|
||||
bool is_font() const { return type() == Type::Font; }
|
||||
|
||||
|
@ -625,6 +627,52 @@ private:
|
|||
RefPtr<Gfx::Bitmap> m_bitmap;
|
||||
};
|
||||
|
||||
class BackgroundStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<BackgroundStyleValue> create(
|
||||
NonnullRefPtr<StyleValue> color,
|
||||
NonnullRefPtr<StyleValue> image,
|
||||
NonnullRefPtr<StyleValue> repeat_x,
|
||||
NonnullRefPtr<StyleValue> repeat_y)
|
||||
{
|
||||
return adopt_ref(*new BackgroundStyleValue(color, image, repeat_x, repeat_y));
|
||||
}
|
||||
virtual ~BackgroundStyleValue() override { }
|
||||
|
||||
NonnullRefPtr<StyleValue> color() const { return m_color; }
|
||||
NonnullRefPtr<StyleValue> image() const { return m_image; }
|
||||
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("Background color: {}, image: {}, repeat: {}/{}", m_color->to_string(), m_image->to_string(), m_repeat_x->to_string(), m_repeat_y->to_string());
|
||||
}
|
||||
|
||||
private:
|
||||
BackgroundStyleValue(
|
||||
NonnullRefPtr<StyleValue> color,
|
||||
NonnullRefPtr<StyleValue> image,
|
||||
NonnullRefPtr<StyleValue> repeat_x,
|
||||
NonnullRefPtr<StyleValue> repeat_y)
|
||||
: StyleValue(Type::Background)
|
||||
, m_color(color)
|
||||
, m_image(image)
|
||||
, m_repeat_x(repeat_x)
|
||||
, m_repeat_y(repeat_y)
|
||||
{
|
||||
}
|
||||
NonnullRefPtr<StyleValue> m_color;
|
||||
NonnullRefPtr<StyleValue> m_image;
|
||||
// FIXME: background-position
|
||||
// FIXME: background-size
|
||||
NonnullRefPtr<StyleValue> m_repeat_x;
|
||||
NonnullRefPtr<StyleValue> m_repeat_y;
|
||||
// FIXME: background-attachment
|
||||
// FIXME: background-clip
|
||||
// FIXME: background-origin
|
||||
};
|
||||
|
||||
class FontStyleValue final : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<FontStyleValue> create(NonnullRefPtr<StyleValue> font_style, NonnullRefPtr<StyleValue> font_weight, NonnullRefPtr<StyleValue> font_size, NonnullRefPtr<StyleValue> line_height, NonnullRefPtrVector<StyleValue>&& font_families) { return adopt_ref(*new FontStyleValue(font_style, font_weight, font_size, line_height, move(font_families))); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue