1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 16:17:45 +00:00

LibWeb: Add a 1-entry lookup cache to FormattingState

This makes repeated lookups of the state for the same box much faster
by bypassing the HashMap.
This commit is contained in:
Andreas Kling 2022-07-06 14:56:10 +02:00
parent e7370443f2
commit 83a6be593c
2 changed files with 39 additions and 16 deletions

View file

@ -12,32 +12,48 @@ namespace Web::Layout {
FormattingState::NodeState& FormattingState::get_mutable(NodeWithStyleAndBoxModelMetrics const& box) FormattingState::NodeState& FormattingState::get_mutable(NodeWithStyleAndBoxModelMetrics const& box)
{ {
if (auto it = nodes.find(&box); it != nodes.end()) if (m_lookup_cache.box == &box && m_lookup_cache.is_mutable)
return *it->value; return *m_lookup_cache.state;
for (auto* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) { auto& node_state = [&]() -> NodeState& {
if (auto it = ancestor->nodes.find(&box); it != ancestor->nodes.end()) { if (auto it = nodes.find(&box); it != nodes.end())
auto cow_node_state = adopt_own(*new NodeState(*it->value)); return *it->value;
auto* cow_node_state_ptr = cow_node_state.ptr();
nodes.set(&box, move(cow_node_state)); for (auto const* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) {
return *cow_node_state_ptr; if (auto it = ancestor->nodes.find(&box); it != ancestor->nodes.end()) {
auto cow_node_state = adopt_own(*new NodeState(*it->value));
auto* cow_node_state_ptr = cow_node_state.ptr();
nodes.set(&box, move(cow_node_state));
return *cow_node_state_ptr;
}
} }
}
return *nodes.ensure(&box, [] { return adopt_own(*new NodeState); }); return *nodes.ensure(&box, [] { return adopt_own(*new NodeState); });
}();
m_lookup_cache = LookupCache { .box = &box, .state = &node_state, .is_mutable = true };
return node_state;
} }
FormattingState::NodeState const& FormattingState::get(NodeWithStyleAndBoxModelMetrics const& box) const FormattingState::NodeState const& FormattingState::get(NodeWithStyleAndBoxModelMetrics const& box) const
{ {
if (auto it = nodes.find(&box); it != nodes.end()) if (m_lookup_cache.box == &box)
return *it->value; return *m_lookup_cache.state;
for (auto* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) { auto& node_state = [&]() -> NodeState const& {
if (auto it = ancestor->nodes.find(&box); it != ancestor->nodes.end()) if (auto it = nodes.find(&box); it != nodes.end())
return *it->value; return *it->value;
}
return *const_cast<FormattingState&>(*this).nodes.ensure(&box, [] { return adopt_own(*new NodeState); }); for (auto* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) {
if (auto it = ancestor->nodes.find(&box); it != ancestor->nodes.end())
return *it->value;
}
return *const_cast<FormattingState&>(*this).nodes.ensure(&box, [] { return adopt_own(*new NodeState); });
}();
const_cast<FormattingState*>(this)->m_lookup_cache = LookupCache { .box = &box, .state = const_cast<NodeState*>(&node_state), .is_mutable = false };
return node_state;
} }
void FormattingState::commit() void FormattingState::commit()

View file

@ -111,6 +111,13 @@ struct FormattingState {
FormattingState const* m_parent { nullptr }; FormattingState const* m_parent { nullptr };
FormattingState const& m_root; FormattingState const& m_root;
struct LookupCache {
NodeWithStyleAndBoxModelMetrics const* box { nullptr };
NodeState* state { nullptr };
bool is_mutable { false };
};
LookupCache m_lookup_cache;
}; };
Gfx::FloatRect absolute_content_rect(Box const&, FormattingState const&); Gfx::FloatRect absolute_content_rect(Box const&, FormattingState const&);