summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-07-06 14:56:10 +0200
committerAndreas Kling <kling@serenityos.org>2022-07-06 20:31:22 +0200
commit83a6be593c9dda39e02812ce91222dd5c0afa9fa (patch)
tree0e4f566bd956f22e47dd7f27b8e9781570f2d94d
parente7370443f2d40505086c1c9d5cd1e8c12a739b06 (diff)
downloadserenity-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.cpp50
-rw-r--r--Userland/Libraries/LibWeb/Layout/FormattingState.h7
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&);