diff --git a/Libraries/LibHTML/CSS/Length.h b/Libraries/LibHTML/CSS/Length.h index 5289d4d718..c557df974f 100644 --- a/Libraries/LibHTML/CSS/Length.h +++ b/Libraries/LibHTML/CSS/Length.h @@ -25,8 +25,8 @@ public: String to_string() const { if (is_auto()) - return "auto"; - return String::format("%d [Length/Absolute]", m_value); + return "[Length/auto]"; + return String::format("%d [Length/px]", m_value); } int to_px() const diff --git a/Libraries/LibHTML/CSS/StyleResolver.cpp b/Libraries/LibHTML/CSS/StyleResolver.cpp index 9377943ca5..b26324e903 100644 --- a/Libraries/LibHTML/CSS/StyleResolver.cpp +++ b/Libraries/LibHTML/CSS/StyleResolver.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include StyleResolver::StyleResolver(Document& document) @@ -93,6 +94,79 @@ bool StyleResolver::is_inherited_property(CSS::PropertyID property_id) return inherited_properties.contains(property_id); } +static Vector split_on_whitespace(const StringView& string) +{ + if (string.is_empty()) + return {}; + + Vector v; + int substart = 0; + for (int i = 0; i < string.length(); ++i) { + char ch = string.characters_without_null_termination()[i]; + if (isspace(ch)) { + int sublen = i - substart; + if (sublen != 0) + v.append(string.substring_view(substart, sublen)); + substart = i + 1; + } + } + int taillen = string.length() - substart; + if (taillen != 0) + v.append(string.substring_view(substart, taillen)); + return v; +} + +static void set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, const StyleValue& value) +{ + if (property_id == CSS::PropertyID::Margin) { + if (value.is_length()) { + style.set_property(CSS::PropertyID::MarginTop, value); + style.set_property(CSS::PropertyID::MarginRight, value); + style.set_property(CSS::PropertyID::MarginBottom, value); + style.set_property(CSS::PropertyID::MarginLeft, value); + return; + } + if (value.is_string()) { + auto parts = split_on_whitespace(value.to_string()); + if (parts.size() == 2) { + auto vertical = parse_css_value(parts[0]); + auto horizontal = parse_css_value(parts[1]); + style.set_property(CSS::PropertyID::MarginTop, vertical); + style.set_property(CSS::PropertyID::MarginBottom, vertical); + style.set_property(CSS::PropertyID::MarginLeft, horizontal); + style.set_property(CSS::PropertyID::MarginRight, horizontal); + return; + } + if (parts.size() == 3) { + auto top = parse_css_value(parts[0]); + auto horizontal = parse_css_value(parts[1]); + auto bottom = parse_css_value(parts[2]); + style.set_property(CSS::PropertyID::MarginTop, top); + style.set_property(CSS::PropertyID::MarginBottom, bottom); + style.set_property(CSS::PropertyID::MarginLeft, horizontal); + style.set_property(CSS::PropertyID::MarginRight, horizontal); + return; + } + if (parts.size() == 4) { + auto top = parse_css_value(parts[0]); + auto right = parse_css_value(parts[1]); + auto bottom = parse_css_value(parts[2]); + auto left = parse_css_value(parts[3]); + style.set_property(CSS::PropertyID::MarginTop, top); + style.set_property(CSS::PropertyID::MarginBottom, bottom); + style.set_property(CSS::PropertyID::MarginLeft, left); + style.set_property(CSS::PropertyID::MarginRight, right); + return; + } + dbg() << "Unsure what to do with CSS margin value '" << value.to_string() << "'"; + return; + } + return; + } + + style.set_property(property_id, value); +} + NonnullRefPtr StyleResolver::resolve_style(const Element& element, const StyleProperties* parent_style) const { auto style = StyleProperties::create(); @@ -100,7 +174,7 @@ NonnullRefPtr StyleResolver::resolve_style(const Element& eleme if (parent_style) { parent_style->for_each_property([&](auto property_id, auto& value) { if (is_inherited_property(property_id)) - style->set_property(property_id, value); + set_property_expanding_shorthands(style, property_id, value); }); } @@ -109,7 +183,7 @@ NonnullRefPtr StyleResolver::resolve_style(const Element& eleme auto matching_rules = collect_matching_rules(element); for (auto& rule : matching_rules) { for (auto& property : rule.declaration().properties()) { - style->set_property(property.property_id, property.value); + set_property_expanding_shorthands(style, property.property_id, property.value); } } @@ -117,7 +191,7 @@ NonnullRefPtr StyleResolver::resolve_style(const Element& eleme if (!style_attribute.is_null()) { if (auto declaration = parse_css_declaration(style_attribute)) { for (auto& property : declaration->properties()) { - style->set_property(property.property_id, property.value); + set_property_expanding_shorthands(style, property.property_id, property.value); } } } diff --git a/Libraries/LibHTML/CSS/StyleValue.h b/Libraries/LibHTML/CSS/StyleValue.h index 02c66d724c..fdec0847f2 100644 --- a/Libraries/LibHTML/CSS/StyleValue.h +++ b/Libraries/LibHTML/CSS/StyleValue.h @@ -46,6 +46,8 @@ public: bool is_color() const { return type() == Type::Color; } bool is_identifier() const { return type() == Type::Identifier; } bool is_image() const { return type() == Type::Image; } + bool is_string() const { return type() == Type::String; } + bool is_length() const { return type() == Type::Length; } virtual String to_string() const = 0; virtual Length to_length() const { return {}; } diff --git a/Libraries/LibHTML/Parser/CSSParser.h b/Libraries/LibHTML/Parser/CSSParser.h index 050b0dd8c7..5ed90467d7 100644 --- a/Libraries/LibHTML/Parser/CSSParser.h +++ b/Libraries/LibHTML/Parser/CSSParser.h @@ -5,4 +5,4 @@ RefPtr parse_css(const StringView&); RefPtr parse_css_declaration(const StringView&); - +NonnullRefPtr parse_css_value(const StringView&);