diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp index bfc71f75fea..a7e452bf084 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -887,7 +887,7 @@ void StyleComputer::set_property_expanding_shorthands(StyleProperties& style, CS { for_each_property_expanding_shorthands(property_id, value, AllowUnresolved::No, [&](PropertyID shorthand_id, CSSStyleValue const& shorthand_value) { if (shorthand_value.is_revert()) { - auto const& property_in_previous_cascade_origin = style_for_revert.m_property_values[to_underlying(shorthand_id)]; + auto const& property_in_previous_cascade_origin = style_for_revert.m_data->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) @@ -1826,7 +1826,7 @@ void StyleComputer::compute_cascaded_values(StyleProperties& style, DOM::Element // FIXME: This is not very efficient, we should only resolve the custom properties that are actually used. 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 = style.m_property_values[i]; + auto& property = style.m_data->m_property_values[i]; if (property && property->is_unresolved()) property = Parser::Parser::resolve_unresolved_style_value(Parser::ParsingContext { document() }, element, pseudo_element, property_id, property->as_unresolved()); } @@ -1939,7 +1939,7 @@ 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 `initial`. - auto& value_slot = style.m_property_values[to_underlying(property_id)]; + auto& value_slot = style.m_data->m_property_values[to_underlying(property_id)]; if (!value_slot) { if (is_inherited_property(property_id)) { style.set_property( @@ -2410,7 +2410,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 can't simply absolutize *all* percentage values against the font size, // because most percentages are relative to containing block metrics. - auto& line_height_value_slot = style.m_property_values[to_underlying(CSS::PropertyID::LineHeight)]; + auto& line_height_value_slot = style.m_data->m_property_values[to_underlying(CSS::PropertyID::LineHeight)]; if (line_height_value_slot && line_height_value_slot->is_percentage()) { line_height_value_slot = LengthStyleValue::create( Length::make_px(CSSPixels::nearest_value_for(font_size * static_cast(line_height_value_slot->as_percentage().percentage().as_fraction())))); @@ -2423,8 +2423,8 @@ void StyleComputer::absolutize_values(StyleProperties& style) const if (line_height_value_slot && line_height_value_slot->is_length()) line_height_value_slot = LengthStyleValue::create(Length::make_px(line_height)); - for (size_t i = 0; i < style.m_property_values.size(); ++i) { - auto& value_slot = style.m_property_values[i]; + for (size_t i = 0; i < style.m_data->m_property_values.size(); ++i) { + auto& value_slot = style.m_data->m_property_values[i]; if (!value_slot) continue; value_slot = value_slot->absolutized(viewport_rect(), font_metrics, m_root_element_font_metrics); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index 86121ef3125..b163882b611 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -37,9 +37,9 @@ namespace Web::CSS { -NonnullRefPtr StyleProperties::clone() const +NonnullRefPtr StyleProperties::Data::clone() const { - auto clone = adopt_ref(*new StyleProperties); + auto clone = adopt_ref(*new StyleProperties::Data); clone->m_property_values = m_property_values; clone->m_animated_property_values = m_animated_property_values; clone->m_property_important = m_property_important; @@ -51,74 +51,81 @@ NonnullRefPtr StyleProperties::clone() const return clone; } +NonnullRefPtr StyleProperties::clone() const +{ + auto cloned = adopt_ref(*new StyleProperties); + cloned->m_data = m_data; + return cloned; +} + bool StyleProperties::is_property_important(CSS::PropertyID property_id) const { size_t n = to_underlying(property_id); - return m_property_important[n / 8] & (1 << (n % 8)); + return m_data->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)); + m_data->m_property_important[n / 8] |= (1 << (n % 8)); else - m_property_important[n / 8] &= ~(1 << (n % 8)); + m_data->m_property_important[n / 8] &= ~(1 << (n % 8)); } bool StyleProperties::is_property_inherited(CSS::PropertyID property_id) const { size_t n = to_underlying(property_id); - return m_property_inherited[n / 8] & (1 << (n % 8)); + return m_data->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)); + m_data->m_property_inherited[n / 8] |= (1 << (n % 8)); else - m_property_inherited[n / 8] &= ~(1 << (n % 8)); + m_data->m_property_inherited[n / 8] &= ~(1 << (n % 8)); } void StyleProperties::set_property(CSS::PropertyID id, NonnullRefPtr value, Inherited inherited, Important important) { - m_property_values[to_underlying(id)] = move(value); + m_data->m_property_values[to_underlying(id)] = move(value); set_property_important(id, important); set_property_inherited(id, inherited); } void StyleProperties::revert_property(CSS::PropertyID id, StyleProperties const& style_for_revert) { - m_property_values[to_underlying(id)] = style_for_revert.m_property_values[to_underlying(id)]; + m_data->m_property_values[to_underlying(id)] = style_for_revert.m_data->m_property_values[to_underlying(id)]; set_property_important(id, style_for_revert.is_property_important(id) ? Important::Yes : Important::No); set_property_inherited(id, style_for_revert.is_property_inherited(id) ? Inherited::Yes : Inherited::No); } void StyleProperties::set_animated_property(CSS::PropertyID id, NonnullRefPtr value) { - m_animated_property_values.set(id, move(value)); + m_data->m_animated_property_values.set(id, move(value)); } void StyleProperties::reset_animated_properties() { - m_animated_property_values.clear(); + m_data->m_animated_property_values.clear(); } NonnullRefPtr StyleProperties::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_data->m_animated_property_values.get(property_id).value_or(nullptr)) return *animated_value; // By the time we call this method, all properties have values assigned. - return *m_property_values[to_underlying(property_id)]; + return *m_data->m_property_values[to_underlying(property_id)]; } RefPtr 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_data->m_animated_property_values.get(property_id).value_or(nullptr)) return *animated_value; - return m_property_values[to_underlying(property_id)]; + return m_data->m_property_values[to_underlying(property_id)]; } CSS::Size StyleProperties::size_value(CSS::PropertyID id) const @@ -242,7 +249,7 @@ CSSPixels StyleProperties::compute_line_height(CSSPixelRect const& viewport_rect auto resolved = line_height->as_calculated().resolve_number(); if (!resolved.has_value()) { dbgln("FIXME: Failed to resolve calc() line-height (number): {}", line_height->as_calculated().to_string()); - return CSSPixels::nearest_value_for(m_font_list->first().pixel_metrics().line_spacing()); + return CSSPixels::nearest_value_for(m_data->m_font_list->first().pixel_metrics().line_spacing()); } return Length(resolved.value(), Length::Type::Em).to_px(viewport_rect, font_metrics, root_font_metrics); } @@ -250,7 +257,7 @@ CSSPixels StyleProperties::compute_line_height(CSSPixelRect const& viewport_rect auto resolved = line_height->as_calculated().resolve_length(Length::ResolutionContext { viewport_rect, font_metrics, root_font_metrics }); if (!resolved.has_value()) { dbgln("FIXME: Failed to resolve calc() line-height: {}", line_height->as_calculated().to_string()); - return CSSPixels::nearest_value_for(m_font_list->first().pixel_metrics().line_spacing()); + return CSSPixels::nearest_value_for(m_data->m_font_list->first().pixel_metrics().line_spacing()); } return resolved->to_px(viewport_rect, font_metrics, root_font_metrics); } @@ -608,12 +615,12 @@ Optional StyleProperties::position() const bool StyleProperties::operator==(StyleProperties const& other) const { - if (m_property_values.size() != other.m_property_values.size()) + if (m_data->m_property_values.size() != other.m_data->m_property_values.size()) return false; - for (size_t i = 0; i < m_property_values.size(); ++i) { - auto const& my_style = m_property_values[i]; - auto const& other_style = other.m_property_values[i]; + for (size_t i = 0; i < m_data->m_property_values.size(); ++i) { + auto const& my_style = m_data->m_property_values[i]; + auto const& other_style = other.m_data->m_property_values[i]; if (!my_style) { if (other_style) return false; @@ -1122,7 +1129,7 @@ Color StyleProperties::stop_color() const void StyleProperties::set_math_depth(int math_depth) { - m_math_depth = math_depth; + m_data->m_math_depth = math_depth; // Make our children inherit our computed value, not our specified value. set_property(PropertyID::MathDepth, MathDepthStyleValue::create_integer(IntegerStyleValue::create(math_depth))); } diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index a7de0eb3656..56efb7200bf 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -20,6 +20,30 @@ namespace Web::CSS { class StyleProperties : public RefCounted { +public: + static constexpr size_t number_of_properties = to_underlying(CSS::last_property_id) + 1; + +private: + struct Data : public RefCounted { + friend class StyleComputer; + + NonnullRefPtr clone() const; + + // FIXME: This needs protection from GC! + JS::GCPtr m_animation_name_source; + + Array, number_of_properties> m_property_values; + Array m_property_important {}; + Array m_property_inherited {}; + + HashMap> m_animated_property_values; + + int m_math_depth { InitialValues::math_depth() }; + mutable RefPtr m_font_list; + + Optional m_line_height; + }; + public: StyleProperties() = default; @@ -29,9 +53,9 @@ public: template inline void for_each_property(Callback callback) const { - for (size_t i = 0; i < m_property_values.size(); ++i) { - if (m_property_values[i]) - callback((CSS::PropertyID)i, *m_property_values[i]); + for (size_t i = 0; i < m_data->m_property_values.size(); ++i) { + if (m_data->m_property_values[i]) + callback((CSS::PropertyID)i, *m_data->m_property_values[i]); } } @@ -40,9 +64,7 @@ public: Yes }; - static constexpr size_t number_of_properties = to_underlying(CSS::last_property_id) + 1; - - HashMap> const& animated_property_values() const { return m_animated_property_values; } + HashMap> const& animated_property_values() const { return m_data->m_animated_property_values; } void reset_animated_properties(); bool is_property_important(CSS::PropertyID property_id) const; @@ -56,8 +78,8 @@ public: RefPtr maybe_null_property(CSS::PropertyID) const; void revert_property(CSS::PropertyID, StyleProperties const& style_for_revert); - JS::GCPtr animation_name_source() const { return m_animation_name_source; } - void set_animation_name_source(JS::GCPtr declaration) { m_animation_name_source = declaration; } + JS::GCPtr animation_name_source() const { return m_data->m_animation_name_source; } + void set_animation_name_source(JS::GCPtr declaration) { m_data->m_animation_name_source = declaration; } CSS::Size size_value(CSS::PropertyID) const; LengthPercentage length_percentage_or_fallback(CSS::PropertyID, LengthPercentage const& fallback) const; @@ -146,23 +168,23 @@ public: Optional fill_rule() const; Optional clip_rule() const; - Gfx::Font const& first_available_computed_font() const { return m_font_list->first(); } + Gfx::Font const& first_available_computed_font() const { return m_data->m_font_list->first(); } Gfx::FontCascadeList const& computed_font_list() const { - VERIFY(m_font_list); - return *m_font_list; + VERIFY(m_data->m_font_list); + return *m_data->m_font_list; } void set_computed_font_list(NonnullRefPtr font_list) const { - m_font_list = move(font_list); + m_data->m_font_list = move(font_list); } [[nodiscard]] CSSPixels compute_line_height(CSSPixelRect const& viewport_rect, Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const; - [[nodiscard]] CSSPixels line_height() const { return *m_line_height; } - void set_line_height(Badge const&, CSSPixels line_height) { m_line_height = line_height; } + [[nodiscard]] CSSPixels line_height() const { return *m_data->m_line_height; } + void set_line_height(Badge const&, CSSPixels line_height) { m_data->m_line_height = line_height; } bool operator==(StyleProperties const&) const; @@ -170,7 +192,7 @@ public: Optional z_index() const; void set_math_depth(int math_depth); - int math_depth() const { return m_math_depth; } + int math_depth() const { return m_data->m_math_depth; } QuotesData quotes() const; Vector counter_data(PropertyID) const; @@ -184,22 +206,10 @@ public: private: friend class StyleComputer; - // FIXME: This needs protection from GC! - JS::GCPtr m_animation_name_source; - - Array, number_of_properties> m_property_values; - Array m_property_important {}; - Array m_property_inherited {}; - - HashMap> m_animated_property_values; - Optional overflow(CSS::PropertyID) const; Vector shadow(CSS::PropertyID, Layout::Node const&) const; - int m_math_depth { InitialValues::math_depth() }; - mutable RefPtr m_font_list; - - Optional m_line_height; + AK::CopyOnWrite m_data; }; }