diff options
author | Andreas Kling <kling@serenityos.org> | 2022-07-06 14:56:10 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-07-06 20:31:22 +0200 |
commit | 83a6be593c9dda39e02812ce91222dd5c0afa9fa (patch) | |
tree | 0e4f566bd956f22e47dd7f27b8e9781570f2d94d | |
parent | e7370443f2d40505086c1c9d5cd1e8c12a739b06 (diff) | |
download | serenity-83a6be593c9dda39e02812ce91222dd5c0afa9fa.zip |
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.
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/FormattingState.cpp | 50 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/FormattingState.h | 7 |
2 files changed, 40 insertions, 17 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/FormattingState.cpp b/Userland/Libraries/LibWeb/Layout/FormattingState.cpp index 8b18f5f9fd..4e2339a65d 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; - - 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; + if (m_lookup_cache.box == &box && m_lookup_cache.is_mutable) + return *m_lookup_cache.state; + + 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<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() diff --git a/Userland/Libraries/LibWeb/Layout/FormattingState.h b/Userland/Libraries/LibWeb/Layout/FormattingState.h index 925b69aae2..50b08e6062 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&); |