From 83a6be593c9dda39e02812ce91222dd5c0afa9fa Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 6 Jul 2022 14:56:10 +0200 Subject: [PATCH] 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. --- .../LibWeb/Layout/FormattingState.cpp | 48 ++++++++++++------- .../Libraries/LibWeb/Layout/FormattingState.h | 7 +++ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Userland/Libraries/LibWeb/Layout/FormattingState.cpp b/Userland/Libraries/LibWeb/Layout/FormattingState.cpp index 8b18f5f9fd7..4e2339a65dd 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingState.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingState.cpp @@ -12,32 +12,48 @@ namespace Web::Layout { FormattingState::NodeState& FormattingState::get_mutable(NodeWithStyleAndBoxModelMetrics const& box) { - if (auto it = nodes.find(&box); it != nodes.end()) - return *it->value; + if (m_lookup_cache.box == &box && m_lookup_cache.is_mutable) + return *m_lookup_cache.state; - for (auto* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) { - 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; + auto& node_state = [&]() -> NodeState& { + if (auto it = nodes.find(&box); it != nodes.end()) + return *it->value; + + for (auto const* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) { + 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 { - if (auto it = nodes.find(&box); it != nodes.end()) - return *it->value; + if (m_lookup_cache.box == &box) + return *m_lookup_cache.state; - for (auto* ancestor = m_parent; ancestor; ancestor = ancestor->m_parent) { - if (auto it = ancestor->nodes.find(&box); it != ancestor->nodes.end()) + auto& node_state = [&]() -> NodeState const& { + if (auto it = nodes.find(&box); it != nodes.end()) return *it->value; - } - return *const_cast(*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(*this).nodes.ensure(&box, [] { return adopt_own(*new NodeState); }); + }(); + + const_cast(this)->m_lookup_cache = LookupCache { .box = &box, .state = const_cast(&node_state), .is_mutable = false }; + return node_state; } void FormattingState::commit() diff --git a/Userland/Libraries/LibWeb/Layout/FormattingState.h b/Userland/Libraries/LibWeb/Layout/FormattingState.h index 925b69aae2c..50b08e60626 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingState.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingState.h @@ -111,6 +111,13 @@ struct FormattingState { FormattingState const* m_parent { nullptr }; 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&);