Browse Source

LibWeb: Use bitmaps for important/inherited bits in StyleProperties

This avoids padding the style value array, shrinking StyleProperties
from 4368 bytes to 2288 bytes per instance.
Andreas Kling 11 months ago
parent
commit
b42b7c8dd0

+ 58 - 41
Userland/Libraries/LibWeb/CSS/StyleComputer.cpp

@@ -835,15 +835,15 @@ void StyleComputer::for_each_property_expanding_shorthands(PropertyID property_i
     set_longhand_property(property_id, value);
     set_longhand_property(property_id, value);
 }
 }
 
 
-void StyleComputer::set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, StyleValue const& value, CSS::CSSStyleDeclaration const* declaration, StyleProperties::PropertyValues const& properties_for_revert, CSS::CSSStyleDeclaration const* animation_name_source_for_revert, StyleProperties::Important important)
+void StyleComputer::set_property_expanding_shorthands(StyleProperties& style, CSS::PropertyID property_id, StyleValue const& value, CSS::CSSStyleDeclaration const* declaration, StyleProperties const& style_for_revert, Important important)
 {
 {
     for_each_property_expanding_shorthands(property_id, value, AllowUnresolved::No, [&](PropertyID shorthand_id, StyleValue const& shorthand_value) {
     for_each_property_expanding_shorthands(property_id, value, AllowUnresolved::No, [&](PropertyID shorthand_id, StyleValue const& shorthand_value) {
         if (shorthand_value.is_revert()) {
         if (shorthand_value.is_revert()) {
-            auto& property_in_previous_cascade_origin = properties_for_revert[to_underlying(shorthand_id)];
-            if (property_in_previous_cascade_origin.style) {
-                style.set_property(shorthand_id, *property_in_previous_cascade_origin.style, StyleProperties::Inherited::No, important);
+            auto const& property_in_previous_cascade_origin = style_for_revert.m_property_values[to_underlying(shorthand_id)];
+            if (property_in_previous_cascade_origin) {
+                style.set_property(shorthand_id, *property_in_previous_cascade_origin, StyleProperties::Inherited::No, important);
                 if (shorthand_id == CSS::PropertyID::AnimationName)
                 if (shorthand_id == CSS::PropertyID::AnimationName)
-                    style.set_animation_name_source(animation_name_source_for_revert);
+                    style.set_animation_name_source(style_for_revert.animation_name_source());
             }
             }
         } else {
         } else {
             style.set_property(shorthand_id, shorthand_value, StyleProperties::Inherited::No, important);
             style.set_property(shorthand_id, shorthand_value, StyleProperties::Inherited::No, important);
@@ -853,23 +853,36 @@ void StyleComputer::set_property_expanding_shorthands(StyleProperties& style, CS
     });
     });
 }
 }
 
 
-void StyleComputer::set_all_properties(DOM::Element& element, Optional<CSS::Selector::PseudoElement::Type> pseudo_element, StyleProperties& style, StyleValue const& value, DOM::Document& document, CSS::CSSStyleDeclaration const* declaration, StyleProperties::PropertyValues const& properties_for_revert, CSS::CSSStyleDeclaration const* animation_name_source_for_revert, StyleProperties::Important important) const
+void StyleComputer::set_all_properties(DOM::Element& element, Optional<CSS::Selector::PseudoElement::Type> pseudo_element, StyleProperties& style, StyleValue const& value, DOM::Document& document, CSS::CSSStyleDeclaration const* declaration, StyleProperties const& style_for_revert, Important important) const
 {
 {
     for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) {
     for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) {
         auto property_id = (CSS::PropertyID)i;
         auto property_id = (CSS::PropertyID)i;
 
 
         if (value.is_revert()) {
         if (value.is_revert()) {
-            style.m_property_values[to_underlying(property_id)] = properties_for_revert[to_underlying(property_id)];
-            style.m_property_values[to_underlying(property_id)].important = important;
+            style.set_property(
+                property_id,
+                style_for_revert.property(property_id),
+                style_for_revert.is_property_inherited(property_id)
+                    ? StyleProperties::Inherited::Yes
+                    : StyleProperties::Inherited::No,
+                important);
             continue;
             continue;
         }
         }
 
 
         if (value.is_unset()) {
         if (value.is_unset()) {
-            if (is_inherited_property(property_id))
-                style.m_property_values[to_underlying(property_id)] = { get_inherit_value(document.realm(), property_id, &element, pseudo_element) };
-            else
-                style.m_property_values[to_underlying(property_id)] = { property_initial_value(document.realm(), property_id) };
-            style.m_property_values[to_underlying(property_id)].important = important;
+            if (is_inherited_property(property_id)) {
+                style.set_property(
+                    property_id,
+                    get_inherit_value(document.realm(), property_id, &element, pseudo_element),
+                    StyleProperties::Inherited::Yes,
+                    important);
+            } else {
+                style.set_property(
+                    property_id,
+                    property_initial_value(document.realm(), property_id),
+                    StyleProperties::Inherited::No,
+                    important);
+            }
             continue;
             continue;
         }
         }
 
 
@@ -877,18 +890,17 @@ void StyleComputer::set_all_properties(DOM::Element& element, Optional<CSS::Sele
         if (property_value->is_unresolved())
         if (property_value->is_unresolved())
             property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document }, element, pseudo_element, property_id, property_value->as_unresolved());
             property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document }, element, pseudo_element, property_id, property_value->as_unresolved());
         if (!property_value->is_unresolved())
         if (!property_value->is_unresolved())
-            set_property_expanding_shorthands(style, property_id, property_value, declaration, properties_for_revert, animation_name_source_for_revert);
+            set_property_expanding_shorthands(style, property_id, property_value, declaration, style_for_revert);
 
 
-        style.m_property_values[to_underlying(property_id)].important = important;
+        style.set_property_important(property_id, important);
 
 
-        set_property_expanding_shorthands(style, property_id, value, declaration, properties_for_revert, animation_name_source_for_revert, important);
+        set_property_expanding_shorthands(style, property_id, value, declaration, style_for_revert, important);
     }
     }
 }
 }
 
 
 void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& element, Optional<CSS::Selector::PseudoElement::Type> pseudo_element, Vector<MatchingRule> const& matching_rules, CascadeOrigin cascade_origin, Important important) const
 void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& element, Optional<CSS::Selector::PseudoElement::Type> pseudo_element, Vector<MatchingRule> const& matching_rules, CascadeOrigin cascade_origin, Important important) const
 {
 {
-    auto animation_name_source_for_revert = style.animation_name_source();
-    auto properties_for_revert = style.properties();
+    auto style_for_revert = style.clone();
 
 
     for (auto const& match : matching_rules) {
     for (auto const& match : matching_rules) {
         for (auto const& property : match.rule->declaration().properties()) {
         for (auto const& property : match.rule->declaration().properties()) {
@@ -896,7 +908,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e
                 continue;
                 continue;
 
 
             if (property.property_id == CSS::PropertyID::All) {
             if (property.property_id == CSS::PropertyID::All) {
-                set_all_properties(element, pseudo_element, style, property.value, m_document, &match.rule->declaration(), properties_for_revert, animation_name_source_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No);
+                set_all_properties(element, pseudo_element, style, property.value, m_document, &match.rule->declaration(), style_for_revert, important);
                 continue;
                 continue;
             }
             }
 
 
@@ -904,7 +916,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e
             if (property.value->is_unresolved())
             if (property.value->is_unresolved())
                 property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document() }, element, pseudo_element, property.property_id, property.value->as_unresolved());
                 property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document() }, element, pseudo_element, property.property_id, property.value->as_unresolved());
             if (!property_value->is_unresolved())
             if (!property_value->is_unresolved())
-                set_property_expanding_shorthands(style, property.property_id, property_value, &match.rule->declaration(), properties_for_revert, animation_name_source_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No);
+                set_property_expanding_shorthands(style, property.property_id, property_value, &match.rule->declaration(), style_for_revert, important);
         }
         }
     }
     }
 
 
@@ -915,7 +927,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e
                     continue;
                     continue;
 
 
                 if (property.property_id == CSS::PropertyID::All) {
                 if (property.property_id == CSS::PropertyID::All) {
-                    set_all_properties(element, pseudo_element, style, property.value, m_document, inline_style, properties_for_revert, animation_name_source_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No);
+                    set_all_properties(element, pseudo_element, style, property.value, m_document, inline_style, style_for_revert, important);
                     continue;
                     continue;
                 }
                 }
 
 
@@ -923,7 +935,7 @@ void StyleComputer::cascade_declarations(StyleProperties& style, DOM::Element& e
                 if (property.value->is_unresolved())
                 if (property.value->is_unresolved())
                     property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document() }, element, pseudo_element, property.property_id, property.value->as_unresolved());
                     property_value = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document() }, element, pseudo_element, property.property_id, property.value->as_unresolved());
                 if (!property_value->is_unresolved())
                 if (!property_value->is_unresolved())
-                    set_property_expanding_shorthands(style, property.property_id, property_value, inline_style, properties_for_revert, animation_name_source_for_revert, important == Important::Yes ? StyleProperties::Important::Yes : StyleProperties::Important::No);
+                    set_property_expanding_shorthands(style, property.property_id, property_value, inline_style, style_for_revert, important);
             }
             }
         }
         }
     }
     }
@@ -1757,8 +1769,8 @@ void StyleComputer::compute_cascaded_values(StyleProperties& style, DOM::Element
             for (auto i = to_underlying(CSS::first_property_id); i <= to_underlying(CSS::last_property_id); ++i) {
             for (auto i = to_underlying(CSS::first_property_id); i <= to_underlying(CSS::last_property_id); ++i) {
                 auto property_id = (CSS::PropertyID)i;
                 auto property_id = (CSS::PropertyID)i;
                 auto& property = style.m_property_values[i];
                 auto& property = style.m_property_values[i];
-                if (property.style && property.style->is_unresolved())
-                    property.style = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document() }, element, pseudo_element, property_id, property.style->as_unresolved());
+                if (property && property->is_unresolved())
+                    property = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document() }, element, pseudo_element, property_id, property->as_unresolved());
             }
             }
         }
         }
     }
     }
@@ -1866,35 +1878,40 @@ void StyleComputer::compute_defaulted_property_value(StyleProperties& style, DOM
     // FIXME: If we don't know the correct initial value for a property, we fall back to InitialStyleValue.
     // FIXME: If we don't know the correct initial value for a property, we fall back to InitialStyleValue.
 
 
     auto& value_slot = style.m_property_values[to_underlying(property_id)];
     auto& value_slot = style.m_property_values[to_underlying(property_id)];
-    if (!value_slot.style) {
-        if (is_inherited_property(property_id))
-            style.m_property_values[to_underlying(property_id)] = { get_inherit_value(document().realm(), property_id, element, pseudo_element), StyleProperties::Important::No, StyleProperties::Inherited::Yes };
-        else
-            style.m_property_values[to_underlying(property_id)] = { property_initial_value(document().realm(), property_id) };
+    if (!value_slot) {
+        if (is_inherited_property(property_id)) {
+            style.set_property(
+                property_id,
+                get_inherit_value(document().realm(), property_id, element, pseudo_element),
+                StyleProperties::Inherited::Yes,
+                Important::No);
+        } else {
+            style.set_property(property_id, property_initial_value(document().realm(), property_id));
+        }
         return;
         return;
     }
     }
 
 
-    if (value_slot.style->is_initial()) {
-        value_slot.style = property_initial_value(document().realm(), property_id);
+    if (value_slot->is_initial()) {
+        value_slot = property_initial_value(document().realm(), property_id);
         return;
         return;
     }
     }
 
 
-    if (value_slot.style->is_inherit()) {
-        value_slot.style = get_inherit_value(document().realm(), property_id, element, pseudo_element);
-        value_slot.inherited = StyleProperties::Inherited::Yes;
+    if (value_slot->is_inherit()) {
+        value_slot = get_inherit_value(document().realm(), property_id, element, pseudo_element);
+        style.set_property_inherited(property_id, StyleProperties::Inherited::Yes);
         return;
         return;
     }
     }
 
 
     // https://www.w3.org/TR/css-cascade-4/#inherit-initial
     // https://www.w3.org/TR/css-cascade-4/#inherit-initial
     // If the cascaded value of a property is the unset keyword,
     // If the cascaded value of a property is the unset keyword,
-    if (value_slot.style->is_unset()) {
+    if (value_slot->is_unset()) {
         if (is_inherited_property(property_id)) {
         if (is_inherited_property(property_id)) {
             // then if it is an inherited property, this is treated as inherit,
             // then if it is an inherited property, this is treated as inherit,
-            value_slot.style = get_inherit_value(document().realm(), property_id, element, pseudo_element);
-            value_slot.inherited = StyleProperties::Inherited::Yes;
+            value_slot = get_inherit_value(document().realm(), property_id, element, pseudo_element);
+            style.set_property_inherited(property_id, StyleProperties::Inherited::Yes);
         } else {
         } else {
             // and if it is not, this is treated as initial.
             // and if it is not, this is treated as initial.
-            value_slot.style = property_initial_value(document().realm(), property_id);
+            value_slot = property_initial_value(document().realm(), property_id);
         }
         }
     }
     }
 }
 }
@@ -2327,7 +2344,7 @@ void StyleComputer::absolutize_values(StyleProperties& style) const
     //       We have to resolve them right away, so that the *computed* line-height is ready for inheritance.
     //       We have to resolve them right away, so that the *computed* line-height is ready for inheritance.
     //       We can't simply absolutize *all* percentage values against the font size,
     //       We can't simply absolutize *all* percentage values against the font size,
     //       because most percentages are relative to containing block metrics.
     //       because most percentages are relative to containing block metrics.
-    auto& line_height_value_slot = style.m_property_values[to_underlying(CSS::PropertyID::LineHeight)].style;
+    auto& line_height_value_slot = style.m_property_values[to_underlying(CSS::PropertyID::LineHeight)];
     if (line_height_value_slot && line_height_value_slot->is_percentage()) {
     if (line_height_value_slot && line_height_value_slot->is_percentage()) {
         line_height_value_slot = LengthStyleValue::create(
         line_height_value_slot = LengthStyleValue::create(
             Length::make_px(CSSPixels::nearest_value_for(font_size * static_cast<double>(line_height_value_slot->as_percentage().percentage().as_fraction()))));
             Length::make_px(CSSPixels::nearest_value_for(font_size * static_cast<double>(line_height_value_slot->as_percentage().percentage().as_fraction()))));
@@ -2342,9 +2359,9 @@ void StyleComputer::absolutize_values(StyleProperties& style) const
 
 
     for (size_t i = 0; i < style.m_property_values.size(); ++i) {
     for (size_t i = 0; i < style.m_property_values.size(); ++i) {
         auto& value_slot = style.m_property_values[i];
         auto& value_slot = style.m_property_values[i];
-        if (!value_slot.style)
+        if (!value_slot)
             continue;
             continue;
-        value_slot.style = value_slot.style->absolutized(viewport_rect(), font_metrics, m_root_element_font_metrics);
+        value_slot = value_slot->absolutized(viewport_rect(), font_metrics, m_root_element_font_metrics);
     }
     }
 
 
     style.set_line_height({}, line_height);
     style.set_line_height({}, line_height);

+ 2 - 2
Userland/Libraries/LibWeb/CSS/StyleComputer.h

@@ -113,7 +113,7 @@ public:
         No,
         No,
     };
     };
     static void for_each_property_expanding_shorthands(PropertyID, StyleValue const&, AllowUnresolved, Function<void(PropertyID, StyleValue const&)> const& set_longhand_property);
     static void for_each_property_expanding_shorthands(PropertyID, StyleValue const&, AllowUnresolved, Function<void(PropertyID, StyleValue const&)> const& set_longhand_property);
-    static void set_property_expanding_shorthands(StyleProperties&, PropertyID, StyleValue const&, CSS::CSSStyleDeclaration const*, StyleProperties::PropertyValues const& properties_for_revert, CSS::CSSStyleDeclaration const* animation_name_source_for_revert, StyleProperties::Important = StyleProperties::Important::No);
+    static void set_property_expanding_shorthands(StyleProperties&, PropertyID, StyleValue const&, CSS::CSSStyleDeclaration const*, StyleProperties const& style_for_revert, Important = Important::No);
     static NonnullRefPtr<StyleValue const> get_inherit_value(JS::Realm& initial_value_context_realm, CSS::PropertyID, DOM::Element const*, Optional<CSS::Selector::PseudoElement::Type> = {});
     static NonnullRefPtr<StyleValue const> get_inherit_value(JS::Realm& initial_value_context_realm, CSS::PropertyID, DOM::Element const*, Optional<CSS::Selector::PseudoElement::Type> = {});
 
 
     explicit StyleComputer(DOM::Document&);
     explicit StyleComputer(DOM::Document&);
@@ -177,7 +177,7 @@ private:
 
 
     void compute_defaulted_property_value(StyleProperties&, DOM::Element const*, CSS::PropertyID, Optional<CSS::Selector::PseudoElement::Type>) const;
     void compute_defaulted_property_value(StyleProperties&, DOM::Element const*, CSS::PropertyID, Optional<CSS::Selector::PseudoElement::Type>) const;
 
 
-    void set_all_properties(DOM::Element&, Optional<CSS::Selector::PseudoElement::Type>, StyleProperties&, StyleValue const&, DOM::Document&, CSS::CSSStyleDeclaration const*, StyleProperties::PropertyValues const& properties_for_revert, CSS::CSSStyleDeclaration const* animation_name_source_for_revert, StyleProperties::Important = StyleProperties::Important::No) const;
+    void set_all_properties(DOM::Element&, Optional<CSS::Selector::PseudoElement::Type>, StyleProperties&, StyleValue const&, DOM::Document&, CSS::CSSStyleDeclaration const*, StyleProperties const& style_for_revert, Important = Important::No) const;
 
 
     template<typename Callback>
     template<typename Callback>
     void for_each_stylesheet(CascadeOrigin, Callback) const;
     void for_each_stylesheet(CascadeOrigin, Callback) const;

+ 47 - 11
Userland/Libraries/LibWeb/CSS/StyleProperties.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
  * Copyright (c) 2021-2024, Sam Atkins <atkinssj@serenityos.org>
  * Copyright (c) 2021-2024, Sam Atkins <atkinssj@serenityos.org>
  *
  *
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
@@ -37,19 +37,55 @@
 
 
 namespace Web::CSS {
 namespace Web::CSS {
 
 
+NonnullRefPtr<StyleProperties> StyleProperties::clone() const
+{
+    auto clone = adopt_ref(*new StyleProperties);
+    clone->m_property_values = m_property_values;
+    clone->m_animated_property_values = m_animated_property_values;
+    clone->m_property_important = m_property_important;
+    clone->m_property_inherited = m_property_inherited;
+    clone->m_font_list = m_font_list;
+    clone->m_line_height = m_line_height;
+    clone->m_animation_name_source = m_animation_name_source;
+    clone->m_math_depth = m_math_depth;
+    return clone;
+}
+
 bool StyleProperties::is_property_important(CSS::PropertyID property_id) const
 bool StyleProperties::is_property_important(CSS::PropertyID property_id) const
 {
 {
-    return m_property_values[to_underlying(property_id)].style && m_property_values[to_underlying(property_id)].important == Important::Yes;
+    size_t n = to_underlying(property_id);
+    return m_property_important[n / 8] & (1 << (n % 8));
+}
+
+void StyleProperties::set_property_important(CSS::PropertyID property_id, Important important)
+{
+    size_t n = to_underlying(property_id);
+    if (important == Important::Yes)
+        m_property_important[n / 8] |= (1 << (n % 8));
+    else
+        m_property_important[n / 8] &= ~(1 << (n % 8));
 }
 }
 
 
 bool StyleProperties::is_property_inherited(CSS::PropertyID property_id) const
 bool StyleProperties::is_property_inherited(CSS::PropertyID property_id) const
 {
 {
-    return m_property_values[to_underlying(property_id)].style && m_property_values[to_underlying(property_id)].inherited == Inherited::Yes;
+    size_t n = to_underlying(property_id);
+    return m_property_inherited[n / 8] & (1 << (n % 8));
+}
+
+void StyleProperties::set_property_inherited(CSS::PropertyID property_id, Inherited inherited)
+{
+    size_t n = to_underlying(property_id);
+    if (inherited == Inherited::Yes)
+        m_property_inherited[n / 8] |= (1 << (n % 8));
+    else
+        m_property_inherited[n / 8] &= ~(1 << (n % 8));
 }
 }
 
 
 void StyleProperties::set_property(CSS::PropertyID id, NonnullRefPtr<StyleValue const> value, Inherited inherited, Important important)
 void StyleProperties::set_property(CSS::PropertyID id, NonnullRefPtr<StyleValue const> value, Inherited inherited, Important important)
 {
 {
-    m_property_values[to_underlying(id)] = StyleValueAndMetadata { move(value), important, inherited };
+    m_property_values[to_underlying(id)] = move(value);
+    set_property_important(id, important);
+    set_property_inherited(id, inherited);
 }
 }
 
 
 void StyleProperties::set_animated_property(CSS::PropertyID id, NonnullRefPtr<StyleValue const> value)
 void StyleProperties::set_animated_property(CSS::PropertyID id, NonnullRefPtr<StyleValue const> value)
@@ -68,14 +104,14 @@ NonnullRefPtr<StyleValue const> StyleProperties::property(CSS::PropertyID proper
         return *animated_value;
         return *animated_value;
 
 
     // By the time we call this method, all properties have values assigned.
     // By the time we call this method, all properties have values assigned.
-    return *m_property_values[to_underlying(property_id)].style;
+    return *m_property_values[to_underlying(property_id)];
 }
 }
 
 
 RefPtr<StyleValue const> StyleProperties::maybe_null_property(CSS::PropertyID property_id) const
 RefPtr<StyleValue const> StyleProperties::maybe_null_property(CSS::PropertyID property_id) const
 {
 {
     if (auto animated_value = m_animated_property_values.get(property_id).value_or(nullptr))
     if (auto animated_value = m_animated_property_values.get(property_id).value_or(nullptr))
         return *animated_value;
         return *animated_value;
-    return m_property_values[to_underlying(property_id)].style;
+    return m_property_values[to_underlying(property_id)];
 }
 }
 
 
 CSS::Size StyleProperties::size_value(CSS::PropertyID id) const
 CSS::Size StyleProperties::size_value(CSS::PropertyID id) const
@@ -571,15 +607,15 @@ bool StyleProperties::operator==(StyleProperties const& other) const
     for (size_t i = 0; i < m_property_values.size(); ++i) {
     for (size_t i = 0; i < m_property_values.size(); ++i) {
         auto const& my_style = m_property_values[i];
         auto const& my_style = m_property_values[i];
         auto const& other_style = other.m_property_values[i];
         auto const& other_style = other.m_property_values[i];
-        if (!my_style.style) {
-            if (other_style.style)
+        if (!my_style) {
+            if (other_style)
                 return false;
                 return false;
             continue;
             continue;
         }
         }
-        if (!other_style.style)
+        if (!other_style)
             return false;
             return false;
-        auto const& my_value = *my_style.style;
-        auto const& other_value = *other_style.style;
+        auto const& my_value = *my_style;
+        auto const& other_value = *other_style;
         if (my_value.type() != other_value.type())
         if (my_value.type() != other_value.type())
             return false;
             return false;
         if (my_value != other_value)
         if (my_value != other_value)

+ 11 - 17
Userland/Libraries/LibWeb/CSS/StyleProperties.h

@@ -15,6 +15,7 @@
 #include <LibWeb/CSS/ComputedValues.h>
 #include <LibWeb/CSS/ComputedValues.h>
 #include <LibWeb/CSS/LengthBox.h>
 #include <LibWeb/CSS/LengthBox.h>
 #include <LibWeb/CSS/PropertyID.h>
 #include <LibWeb/CSS/PropertyID.h>
+#include <LibWeb/CSS/StyleProperty.h>
 
 
 namespace Web::CSS {
 namespace Web::CSS {
 
 
@@ -23,41 +24,31 @@ public:
     StyleProperties() = default;
     StyleProperties() = default;
 
 
     static NonnullRefPtr<StyleProperties> create() { return adopt_ref(*new StyleProperties); }
     static NonnullRefPtr<StyleProperties> create() { return adopt_ref(*new StyleProperties); }
+    NonnullRefPtr<StyleProperties> clone() const;
 
 
     template<typename Callback>
     template<typename Callback>
     inline void for_each_property(Callback callback) const
     inline void for_each_property(Callback callback) const
     {
     {
         for (size_t i = 0; i < m_property_values.size(); ++i) {
         for (size_t i = 0; i < m_property_values.size(); ++i) {
-            if (m_property_values[i].style)
-                callback((CSS::PropertyID)i, *m_property_values[i].style);
+            if (m_property_values[i])
+                callback((CSS::PropertyID)i, *m_property_values[i]);
         }
         }
     }
     }
 
 
-    enum class Important {
-        No,
-        Yes
-    };
-
     enum class Inherited {
     enum class Inherited {
         No,
         No,
         Yes
         Yes
     };
     };
 
 
-    struct StyleValueAndMetadata {
-        RefPtr<StyleValue const> style;
-        Important important { Important::No };
-        Inherited inherited { Inherited::No };
-    };
-    using PropertyValues = Array<StyleValueAndMetadata, to_underlying(CSS::last_property_id) + 1>;
-
-    auto& properties() { return m_property_values; }
-    auto const& properties() const { return m_property_values; }
+    static constexpr size_t number_of_properties = to_underlying(CSS::last_property_id) + 1;
 
 
     HashMap<CSS::PropertyID, NonnullRefPtr<StyleValue const>> const& animated_property_values() const { return m_animated_property_values; }
     HashMap<CSS::PropertyID, NonnullRefPtr<StyleValue const>> const& animated_property_values() const { return m_animated_property_values; }
     void reset_animated_properties();
     void reset_animated_properties();
 
 
     bool is_property_important(CSS::PropertyID property_id) const;
     bool is_property_important(CSS::PropertyID property_id) const;
     bool is_property_inherited(CSS::PropertyID property_id) const;
     bool is_property_inherited(CSS::PropertyID property_id) const;
+    void set_property_important(CSS::PropertyID, Important);
+    void set_property_inherited(CSS::PropertyID, Inherited);
 
 
     void set_property(CSS::PropertyID, NonnullRefPtr<StyleValue const> value, Inherited = Inherited::No, Important = Important::No);
     void set_property(CSS::PropertyID, NonnullRefPtr<StyleValue const> value, Inherited = Inherited::No, Important = Important::No);
     void set_animated_property(CSS::PropertyID, NonnullRefPtr<StyleValue const> value);
     void set_animated_property(CSS::PropertyID, NonnullRefPtr<StyleValue const> value);
@@ -192,7 +183,10 @@ private:
     // FIXME: This needs protection from GC!
     // FIXME: This needs protection from GC!
     JS::GCPtr<CSS::CSSStyleDeclaration const> m_animation_name_source;
     JS::GCPtr<CSS::CSSStyleDeclaration const> m_animation_name_source;
 
 
-    PropertyValues m_property_values;
+    Array<RefPtr<CSS::StyleValue const>, number_of_properties> m_property_values;
+    Array<u8, ceil_div(number_of_properties, 8uz)> m_property_important {};
+    Array<u8, ceil_div(number_of_properties, 8uz)> m_property_inherited {};
+
     HashMap<CSS::PropertyID, NonnullRefPtr<StyleValue const>> m_animated_property_values;
     HashMap<CSS::PropertyID, NonnullRefPtr<StyleValue const>> m_animated_property_values;
 
 
     Optional<CSS::Overflow> overflow(CSS::PropertyID) const;
     Optional<CSS::Overflow> overflow(CSS::PropertyID) const;

+ 4 - 3
Userland/Services/WebContent/ConnectionFromClient.cpp

@@ -332,9 +332,10 @@ void ConnectionFromClient::debug_request(u64 page_id, ByteString const& request,
                 if (element->is_element()) {
                 if (element->is_element()) {
                     auto styles = doc->style_computer().compute_style(*static_cast<Web::DOM::Element*>(element));
                     auto styles = doc->style_computer().compute_style(*static_cast<Web::DOM::Element*>(element));
                     dbgln("+ Element {}", element->debug_description());
                     dbgln("+ Element {}", element->debug_description());
-                    auto& properties = styles->properties();
-                    for (size_t i = 0; i < properties.size(); ++i)
-                        dbgln("|  {} = {}", Web::CSS::string_from_property_id(static_cast<Web::CSS::PropertyID>(i)), properties[i].style ? properties[i].style->to_string() : ""_string);
+                    for (size_t i = 0; i < Web::CSS::StyleProperties::number_of_properties; ++i) {
+                        auto property = styles->maybe_null_property(static_cast<Web::CSS::PropertyID>(i));
+                        dbgln("|  {} = {}", Web::CSS::string_from_property_id(static_cast<Web::CSS::PropertyID>(i)), property ? property->to_string() : ""_string);
+                    }
                     dbgln("---");
                     dbgln("---");
                 }
                 }
             }
             }