diff options
author | Sam Atkins <atkinssj@gmail.com> | 2021-07-21 17:47:50 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-22 23:09:01 +0200 |
commit | 29b61123a487b5f855ee5f58756556dcec1f72ce (patch) | |
tree | 7b9c1513922c189b2d053fc2e49f3c102931c870 /Userland/Libraries/LibWeb | |
parent | 6e08b200d45cbe10baf0c5fdca68147cade647dc (diff) | |
download | serenity-29b61123a487b5f855ee5f58756556dcec1f72ce.zip |
LibWeb: Resolve background properties from ValueListStyleValue
As before, there are several sub-properties that we do not support, and
we ignore anything after the first comma.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/StyleResolver.cpp | 205 |
1 files changed, 175 insertions, 30 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp index 0a059fb50d..d0f3f42d4d 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleResolver.cpp @@ -211,7 +211,7 @@ static inline void set_property_border_style(StyleProperties& style, StyleValue style.set_property(CSS::PropertyID::BorderLeftStyle, value); } -static inline bool is_background_repeat_property(StyleValue const& value) +static inline bool is_background_repeat(StyleValue const& value) { if (value.is_builtin_or_dynamic()) return true; @@ -229,6 +229,17 @@ static inline bool is_background_repeat_property(StyleValue const& value) } } +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()) @@ -1032,11 +1043,21 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope } if (property_id == CSS::PropertyID::Background) { - if (value.is_identifier() && static_cast<IdentifierStyleValue const&>(value).id() == CSS::ValueID::None) { + if (value.to_identifier() == ValueID::None) { style.set_property(CSS::PropertyID::BackgroundColor, ColorStyleValue::create(Color::Transparent)); 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; + } + // FIXME: Remove string parsing once DeprecatedCSSParser is gone. if (value.is_string()) { auto parts = split_on_whitespace(value.to_string()); @@ -1059,8 +1080,8 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope for (auto it = values.begin(); it != values.end(); ++it) { auto& value = *it; - if (is_background_repeat_property(value)) { - if ((it + 1 != values.end()) && is_background_repeat_property(*(it + 1))) { + if (is_background_repeat(value)) { + if ((it + 1 != values.end()) && is_background_repeat(*(it + 1))) { ++it; set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, value, document, true); @@ -1077,54 +1098,160 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope return; } - // FIXME: Implement List parsing. + if (value.is_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]; + + // 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()); + 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); + + return; + } return; } if (property_id == CSS::PropertyID::BackgroundImage) { - // FIXME: Handle function StyleValues once we have them. - if (!value.is_string()) + if (is_background_image(value)) { + style.set_property(CSS::PropertyID::BackgroundImage, value); return; - auto string = value.to_string(); - if (!string.starts_with("url(")) + } + + // FIXME: Remove string parsing once DeprecatedCSSParser is gone. + if (value.is_string()) { + return; + auto string = value.to_string(); + if (!string.starts_with("url(")) + return; + if (!string.ends_with(')')) + return; + auto url = string.substring_view(4, string.length() - 5); + if (url.length() >= 2 && url.starts_with('"') && url.ends_with('"')) + url = url.substring_view(1, url.length() - 2); + else if (url.length() >= 2 && url.starts_with('\'') && url.ends_with('\'')) + url = url.substring_view(1, url.length() - 2); + + auto background_image_value = ImageStyleValue::create(document.complete_url(url), document); + style.set_property(CSS::PropertyID::BackgroundImage, move(background_image_value)); return; - if (!string.ends_with(')')) + } + + if (value.is_value_list()) { + auto parts = static_cast<CSS::ValueListStyleValue const&>(value).values(); + // FIXME: Handle multiple backgrounds. + if (!parts.is_empty()) { + auto first_value = Parser::parse_css_value(context, property_id, parts[0]); + if (first_value) + style.set_property(CSS::PropertyID::BackgroundImage, *first_value); + } return; - auto url = string.substring_view(4, string.length() - 5); - if (url.length() >= 2 && url.starts_with('"') && url.ends_with('"')) - url = url.substring_view(1, url.length() - 2); - else if (url.length() >= 2 && url.starts_with('\'') && url.ends_with('\'')) - url = url.substring_view(1, url.length() - 2); - - auto background_image_value = ImageStyleValue::create(document.complete_url(url), document); - style.set_property(CSS::PropertyID::BackgroundImage, move(background_image_value)); + } + + dbgln("Unsure what to do with CSS background-image value '{}'", value.to_string()); return; } 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 (is_background_repeat(value)) { + assign_background_repeat_from_single_value(value); + } + // FIXME: Remove string parsing once DeprecatedCSSParser is gone. if (value.is_string()) { auto parts = split_on_whitespace(value.to_string()); NonnullRefPtrVector<StyleValue> values; for (auto& part : parts) { auto value = parse_css_value(deprecated_context, part); - if (!value || !is_background_repeat_property(*value)) + if (!value || !is_background_repeat(*value)) return; values.append(value.release_nonnull()); } if (values.size() == 1) { - auto value_id = values[0].to_identifier(); - if (value_id == CSS::ValueID::RepeatX || value_id == CSS::ValueID::RepeatY) { - auto repeat_x = IdentifierStyleValue::create(value_id == CSS::ValueID::RepeatX ? CSS::ValueID::Repeat : CSS::ValueID::NoRepeat); - auto repeat_y = IdentifierStyleValue::create(value_id == CSS::ValueID::RepeatX ? CSS::ValueID::NoRepeat : CSS::ValueID::Repeat); - set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, repeat_x, document, true); - set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, repeat_y, document, true); - } else { - set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, values[0], document, true); - set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, values[0], document, true); - } + assign_background_repeat_from_single_value(values[0]); } else if (values.size() == 2) { set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatX, values[0], document, true); set_property_expanding_shorthands(style, CSS::PropertyID::BackgroundRepeatY, values[1], document, true); @@ -1133,7 +1260,25 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope return; } - // FIXME: Implement List parsing. + if (value.is_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; + } + 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; } |