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; + 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 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&);