mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:37:35 +00:00
LibWeb: Make LayoutState use HashMap instead of potentially huge Vector
Before this change, LayoutState essentially had a Vector<UsedValues*> resized to the exact number of layout nodes in the current document. When a nested layout is performed (to calculate the intrinsic size of something), we make a new LayoutState with its own Vector. If an entry is missing in a nested LayoutState, we check the parent chain all the way up to the root. Because each nested LayoutState had to allocate a new Vector with space for all layout nodes, this could get really nasty on very large pages (such as the ECMA262 specification). This patch replaces the Vector with a HashMap. There's now a small cost to lookups, but what we get in return is the ability to handle huge layout trees without spending eternity in page faults.
This commit is contained in:
parent
e83681ee34
commit
e2c72922f6
6 changed files with 35 additions and 42 deletions
|
@ -11,44 +11,56 @@
|
|||
|
||||
namespace Web::Layout {
|
||||
|
||||
LayoutState::LayoutState(LayoutState const* parent)
|
||||
: m_parent(parent)
|
||||
, m_root(find_root())
|
||||
{
|
||||
}
|
||||
|
||||
LayoutState::~LayoutState()
|
||||
{
|
||||
}
|
||||
|
||||
LayoutState::UsedValues& LayoutState::get_mutable(NodeWithStyleAndBoxModelMetrics const& box)
|
||||
{
|
||||
auto serial_id = box.serial_id();
|
||||
if (used_values_per_layout_node[serial_id])
|
||||
return *used_values_per_layout_node[serial_id];
|
||||
if (auto* used_values = used_values_per_layout_node.get(&box).value_or(nullptr))
|
||||
return *used_values;
|
||||
|
||||
for (auto const* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) {
|
||||
if (ancestor->used_values_per_layout_node[serial_id]) {
|
||||
auto cow_used_values = adopt_own(*new UsedValues(*ancestor->used_values_per_layout_node[serial_id]));
|
||||
if (auto* ancestor_used_values = ancestor->used_values_per_layout_node.get(&box).value_or(nullptr)) {
|
||||
auto cow_used_values = adopt_own(*new UsedValues(*ancestor_used_values));
|
||||
auto* cow_used_values_ptr = cow_used_values.ptr();
|
||||
used_values_per_layout_node[serial_id] = move(cow_used_values);
|
||||
used_values_per_layout_node.set(&box, move(cow_used_values));
|
||||
return *cow_used_values_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto const* containing_block_used_values = box.is_viewport() ? nullptr : &get(*box.containing_block());
|
||||
|
||||
used_values_per_layout_node[serial_id] = adopt_own(*new UsedValues);
|
||||
used_values_per_layout_node[serial_id]->set_node(const_cast<NodeWithStyleAndBoxModelMetrics&>(box), containing_block_used_values);
|
||||
return *used_values_per_layout_node[serial_id];
|
||||
auto new_used_values = adopt_own(*new UsedValues);
|
||||
auto* new_used_values_ptr = new_used_values.ptr();
|
||||
new_used_values->set_node(const_cast<NodeWithStyleAndBoxModelMetrics&>(box), containing_block_used_values);
|
||||
used_values_per_layout_node.set(&box, move(new_used_values));
|
||||
return *new_used_values_ptr;
|
||||
}
|
||||
|
||||
LayoutState::UsedValues const& LayoutState::get(NodeWithStyleAndBoxModelMetrics const& box) const
|
||||
{
|
||||
auto serial_id = box.serial_id();
|
||||
if (used_values_per_layout_node[serial_id])
|
||||
return *used_values_per_layout_node[serial_id];
|
||||
if (auto const* used_values = used_values_per_layout_node.get(&box).value_or(nullptr))
|
||||
return *used_values;
|
||||
|
||||
for (auto* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) {
|
||||
if (ancestor->used_values_per_layout_node[serial_id])
|
||||
return *ancestor->used_values_per_layout_node[serial_id];
|
||||
for (auto const* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) {
|
||||
if (auto const* ancestor_used_values = ancestor->used_values_per_layout_node.get(&box).value_or(nullptr))
|
||||
return *ancestor_used_values;
|
||||
}
|
||||
|
||||
auto const* containing_block_used_values = box.is_viewport() ? nullptr : &get(*box.containing_block());
|
||||
|
||||
const_cast<LayoutState*>(this)->used_values_per_layout_node[serial_id] = adopt_own(*new UsedValues);
|
||||
const_cast<LayoutState*>(this)->used_values_per_layout_node[serial_id]->set_node(const_cast<NodeWithStyleAndBoxModelMetrics&>(box), containing_block_used_values);
|
||||
return *used_values_per_layout_node[serial_id];
|
||||
auto new_used_values = adopt_own(*new UsedValues);
|
||||
auto* new_used_values_ptr = new_used_values.ptr();
|
||||
new_used_values->set_node(const_cast<NodeWithStyleAndBoxModelMetrics&>(box), containing_block_used_values);
|
||||
const_cast<LayoutState*>(this)->used_values_per_layout_node.set(&box, move(new_used_values));
|
||||
return *new_used_values_ptr;
|
||||
}
|
||||
|
||||
void LayoutState::commit()
|
||||
|
@ -58,10 +70,8 @@ void LayoutState::commit()
|
|||
|
||||
HashTable<Layout::TextNode*> text_nodes;
|
||||
|
||||
for (auto& used_values_ptr : used_values_per_layout_node) {
|
||||
if (!used_values_ptr)
|
||||
continue;
|
||||
auto& used_values = *used_values_ptr;
|
||||
for (auto& it : used_values_per_layout_node) {
|
||||
auto& used_values = *it.value;
|
||||
auto& node = const_cast<NodeWithStyleAndBoxModelMetrics&>(used_values.node());
|
||||
|
||||
// Transfer box model metrics.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue