ladybird/Libraries/LibWeb/CSS/CustomPropertyData.h
Andreas Kling 9e8e568b43 LibWeb: Use structural sharing for CSS custom properties
Replace per-element OrderedHashMap storage for custom properties with
a RefCounted chain (CustomPropertyData) that enables structural
sharing. Each chain node stores only the properties declared directly
on its element, with a parent pointer to the inherited chain.

Elements that don't override any custom properties share the parent's
data directly (just a RefPtr copy). During cascade, only entries that
actually differ from the parent are stored in own_values - the rest
are inherited through the chain. During var() resolution, resolved
values are compared against the parent's and matching entries are
dropped, enabling further sharing.

The chain uses a depth limit (max 32) with flattening, plus
absorption of small parent nodes (threshold 8) to keep lookups fast.

This reduces custom property memory from ~79 MB to ~5.7 MB on
cloudflare.com.
2026-02-13 14:57:15 +01:00

45 lines
1.4 KiB
C++

/*
* Copyright (c) 2026, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <LibWeb/CSS/StyleProperty.h>
#include <LibWeb/Export.h>
namespace Web::CSS {
// Chain of custom property maps with structural sharing.
// Each node stores only the properties declared directly on its element,
// with a parent pointer to the inherited chain.
class WEB_API CustomPropertyData : public RefCounted<CustomPropertyData> {
public:
static NonnullRefPtr<CustomPropertyData> create(
OrderedHashMap<FlyString, StyleProperty> own_values,
RefPtr<CustomPropertyData const> parent);
StyleProperty const* get(FlyString const& name) const;
OrderedHashMap<FlyString, StyleProperty> const& own_values() const { return m_own_values; }
void for_each_property(Function<void(FlyString const&, StyleProperty const&)> callback) const;
RefPtr<CustomPropertyData const> parent() const { return m_parent; }
bool is_empty() const;
private:
CustomPropertyData(OrderedHashMap<FlyString, StyleProperty> own_values, RefPtr<CustomPropertyData const> parent, u8 ancestor_count);
OrderedHashMap<FlyString, StyleProperty> m_own_values;
RefPtr<CustomPropertyData const> m_parent;
u8 m_ancestor_count { 0 };
};
}