mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-06-27 19:51:03 +00:00
Move ComputedProperties and CascadedProperties out of the GC. They no longer contain strong references to GC-managed data. Keep computed styles alive from DOM elements and animation updates with RefPtr. Pass style into layout constructors by reference, since layout only copies the values it needs while building nodes. Use GC::Weak for cascade source links, so entries no longer keep the style declaration or shadow root alive.
148 lines
5.4 KiB
C++
148 lines
5.4 KiB
C++
/*
|
|
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGC/WeakInlines.h>
|
|
#include <LibWeb/CSS/CSSStyleDeclaration.h>
|
|
#include <LibWeb/CSS/CascadedProperties.h>
|
|
#include <LibWeb/CSS/PropertyID.h>
|
|
#include <LibWeb/DOM/Element.h>
|
|
#include <LibWeb/DOM/ShadowRoot.h>
|
|
|
|
namespace Web::CSS {
|
|
|
|
CascadedProperties::CascadedProperties() = default;
|
|
|
|
CascadedProperties::~CascadedProperties() = default;
|
|
|
|
NonnullRefPtr<CascadedProperties> CascadedProperties::create()
|
|
{
|
|
return adopt_ref(*new CascadedProperties);
|
|
}
|
|
|
|
void CascadedProperties::revert_property(PropertyID property_id, Important important, CascadeOrigin cascade_origin)
|
|
{
|
|
auto it = m_properties.find(property_id);
|
|
if (it == m_properties.end())
|
|
return;
|
|
auto& entries = it->value;
|
|
entries.remove_all_matching([&](auto& entry) {
|
|
// https://drafts.csswg.org/css-cascade-5/#author-presentational-hint-origin
|
|
// For the purpose of cascading this author presentational hint origin is treated as an independent origin, but
|
|
// for the purpose of the revert keyword it is considered part of the author origin.
|
|
auto origin_matches = entry.origin == cascade_origin
|
|
|| (cascade_origin == CascadeOrigin::Author && entry.origin == CascadeOrigin::AuthorPresentationalHint);
|
|
return entry.property.property_id == property_id
|
|
&& entry.property.important == important
|
|
&& origin_matches;
|
|
});
|
|
if (entries.is_empty()) {
|
|
m_contained_properties_cache.set(to_underlying(property_id), false);
|
|
m_properties.remove(it);
|
|
}
|
|
}
|
|
|
|
void CascadedProperties::revert_layer_property(PropertyID property_id, Important important, CascadeOrigin cascade_origin, Optional<FlyString> layer_name, GC::Ptr<DOM::ShadowRoot const> source_shadow_root)
|
|
{
|
|
auto it = m_properties.find(property_id);
|
|
if (it == m_properties.end())
|
|
return;
|
|
auto& entries = it->value;
|
|
entries.remove_all_matching([&](auto& entry) {
|
|
return entry.property.property_id == property_id
|
|
&& entry.property.important == important
|
|
&& entry.origin == cascade_origin
|
|
&& entry.source_shadow_root.ptr() == source_shadow_root
|
|
&& layer_name == entry.layer_name;
|
|
});
|
|
if (entries.is_empty()) {
|
|
m_contained_properties_cache.set(to_underlying(property_id), false);
|
|
m_properties.remove(it);
|
|
}
|
|
}
|
|
|
|
void CascadedProperties::set_property(PropertyID property_id, NonnullRefPtr<StyleValue const> value, Important important, CascadeOrigin origin, Optional<FlyString> layer_name, GC::Ptr<CSS::CSSStyleDeclaration const> source, GC::Ptr<DOM::ShadowRoot const> source_shadow_root)
|
|
{
|
|
m_contained_properties_cache.set(to_underlying(property_id), true);
|
|
|
|
auto& entries = m_properties.ensure(property_id);
|
|
|
|
for (auto& entry : entries.in_reverse()) {
|
|
if (entry.origin == origin && entry.layer_name == layer_name && entry.source_shadow_root.ptr() == source_shadow_root) {
|
|
if (entry.property.important == Important::Yes && important == Important::No)
|
|
return;
|
|
entry.property = StyleProperty {
|
|
.important = important,
|
|
.property_id = property_id,
|
|
.value = value,
|
|
};
|
|
entry.cascade_index = m_next_cascade_index++;
|
|
entry.source = source.ptr();
|
|
entry.source_shadow_root = source_shadow_root.ptr();
|
|
return;
|
|
}
|
|
}
|
|
|
|
entries.append(Entry {
|
|
.property = StyleProperty {
|
|
.important = important,
|
|
.property_id = property_id,
|
|
.value = value,
|
|
},
|
|
.cascade_index = m_next_cascade_index++,
|
|
.origin = origin,
|
|
.layer_name = move(layer_name),
|
|
.source = source.ptr(),
|
|
.source_shadow_root = source_shadow_root.ptr(),
|
|
});
|
|
}
|
|
|
|
RefPtr<StyleValue const> CascadedProperties::property(PropertyID property_id) const
|
|
{
|
|
if (!m_contained_properties_cache.get(to_underlying(property_id)))
|
|
return nullptr;
|
|
|
|
return m_properties.get(property_id)->last().property.value;
|
|
}
|
|
|
|
PropertyID CascadedProperties::property_with_higher_priority(PropertyID first_property_id, PropertyID second_property_id) const
|
|
{
|
|
if (!m_contained_properties_cache.get(to_underlying(first_property_id)))
|
|
return second_property_id;
|
|
|
|
if (!m_contained_properties_cache.get(to_underlying(second_property_id)))
|
|
return first_property_id;
|
|
|
|
if (m_properties.get(first_property_id)->last().cascade_index >= m_properties.get(second_property_id)->last().cascade_index)
|
|
return first_property_id;
|
|
|
|
return second_property_id;
|
|
}
|
|
|
|
GC::Ptr<CSSStyleDeclaration const> CascadedProperties::property_source(PropertyID property_id) const
|
|
{
|
|
if (!m_contained_properties_cache.get(to_underlying(property_id)))
|
|
return nullptr;
|
|
|
|
return m_properties.get(property_id)->last().source.ptr();
|
|
}
|
|
|
|
GC::Ptr<DOM::ShadowRoot const> CascadedProperties::property_source_shadow_root(PropertyID property_id) const
|
|
{
|
|
if (!m_contained_properties_cache.get(to_underlying(property_id)))
|
|
return nullptr;
|
|
|
|
return m_properties.get(property_id)->last().source_shadow_root.ptr();
|
|
}
|
|
|
|
Optional<StyleProperty> CascadedProperties::style_property(PropertyID property_id) const
|
|
{
|
|
if (!m_contained_properties_cache.get(to_underlying(property_id)))
|
|
return {};
|
|
|
|
return m_properties.get(property_id)->last().property;
|
|
}
|
|
|
|
}
|