Revert "LibWeb: Cache intrinsic sizes across layout runs"

This reverts commit 12c6ac78e2.

Very large performance regression when viewing GitHub repository pages.
This commit is contained in:
Andreas Kling 2025-03-08 12:08:51 +01:00
commit 73a4b176cf
Notes: github-actions[bot] 2025-03-08 11:10:16 +00:00
13 changed files with 102 additions and 108 deletions

View file

@ -17,13 +17,6 @@ struct LineBoxFragmentCoordinate {
size_t fragment_index { 0 };
};
struct IntrinsicSizes {
Optional<CSSPixels> min_content_width;
Optional<CSSPixels> max_content_width;
HashMap<CSSPixels, Optional<CSSPixels>> min_content_height;
HashMap<CSSPixels, Optional<CSSPixels>> max_content_height;
};
class Box : public NodeWithStyleAndBoxModelMetrics {
GC_CELL(Box, NodeWithStyleAndBoxModelMetrics);
@ -60,14 +53,6 @@ public:
virtual void visit_edges(Cell::Visitor&) override;
IntrinsicSizes& cached_intrinsic_sizes() const
{
if (!m_cached_intrinsic_sizes)
m_cached_intrinsic_sizes = make<IntrinsicSizes>();
return *m_cached_intrinsic_sizes;
}
void reset_cached_intrinsic_sizes() const { m_cached_intrinsic_sizes.clear(); }
protected:
Box(DOM::Document&, DOM::Node*, GC::Ref<CSS::ComputedProperties>);
Box(DOM::Document&, DOM::Node*, NonnullOwnPtr<CSS::ComputedValues>);
@ -80,8 +65,6 @@ private:
Optional<CSSPixelFraction> m_natural_aspect_ratio;
Vector<GC::Ref<Node>> m_contained_abspos_children;
OwnPtr<IntrinsicSizes> mutable m_cached_intrinsic_sizes;
};
template<>

View file

@ -1442,9 +1442,11 @@ CSSPixels FormattingContext::calculate_min_content_width(Layout::Box const& box)
if (box.has_natural_width())
return *box.natural_width();
auto& cache = box.cached_intrinsic_sizes().min_content_width;
if (cache.has_value())
return cache.value();
auto& root_state = m_state.m_root;
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
if (cache.min_content_width.has_value())
return *cache.min_content_width;
LayoutState throwaway_state(&m_state);
@ -1464,9 +1466,8 @@ CSSPixels FormattingContext::calculate_min_content_width(Layout::Box const& box)
context->run(AvailableSpace(available_width, available_height));
auto min_content_width = clamp_to_max_dimension_value(context->automatic_content_width());
cache.emplace(min_content_width);
return min_content_width;
cache.min_content_width = clamp_to_max_dimension_value(context->automatic_content_width());
return *cache.min_content_width;
}
CSSPixels FormattingContext::calculate_max_content_width(Layout::Box const& box) const
@ -1474,9 +1475,11 @@ CSSPixels FormattingContext::calculate_max_content_width(Layout::Box const& box)
if (box.has_natural_width())
return *box.natural_width();
auto& cache = box.cached_intrinsic_sizes().max_content_width;
if (cache.has_value())
return cache.value();
auto& root_state = m_state.m_root;
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
if (cache.max_content_width.has_value())
return *cache.max_content_width;
LayoutState throwaway_state(&m_state);
@ -1496,9 +1499,8 @@ CSSPixels FormattingContext::calculate_max_content_width(Layout::Box const& box)
context->run(AvailableSpace(available_width, available_height));
auto max_content_width = clamp_to_max_dimension_value(context->automatic_content_width());
cache.emplace(max_content_width);
return max_content_width;
cache.max_content_width = clamp_to_max_dimension_value(context->automatic_content_width());
return *cache.max_content_width;
}
// https://www.w3.org/TR/css-sizing-3/#min-content-block-size
@ -1511,9 +1513,14 @@ CSSPixels FormattingContext::calculate_min_content_height(Layout::Box const& box
if (box.has_natural_height())
return *box.natural_height();
auto cache_slot = box.cached_intrinsic_sizes().min_content_height.ensure(width);
if (cache_slot.has_value())
return cache_slot.value();
auto get_cache_slot = [&]() -> Optional<CSSPixels>* {
auto& root_state = m_state.m_root;
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
return &cache.min_content_height.ensure(width);
};
if (auto* cache_slot = get_cache_slot(); cache_slot && cache_slot->has_value())
return cache_slot->value();
LayoutState throwaway_state(&m_state);
@ -1530,7 +1537,9 @@ CSSPixels FormattingContext::calculate_min_content_height(Layout::Box const& box
context->run(AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_min_content()));
auto min_content_height = clamp_to_max_dimension_value(context->automatic_content_height());
cache_slot.emplace(min_content_height);
if (auto* cache_slot = get_cache_slot()) {
*cache_slot = min_content_height;
}
return min_content_height;
}
@ -1542,9 +1551,14 @@ CSSPixels FormattingContext::calculate_max_content_height(Layout::Box const& box
if (box.has_natural_height())
return *box.natural_height();
auto& cache_slot = box.cached_intrinsic_sizes().max_content_height.ensure(width);
if (cache_slot.has_value())
return cache_slot.value();
auto get_cache_slot = [&]() -> Optional<CSSPixels>* {
auto& root_state = m_state.m_root;
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
return &cache.max_content_height.ensure(width);
};
if (auto* cache_slot = get_cache_slot(); cache_slot && cache_slot->has_value())
return cache_slot->value();
LayoutState throwaway_state(&m_state);
@ -1561,7 +1575,11 @@ CSSPixels FormattingContext::calculate_max_content_height(Layout::Box const& box
context->run(AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_max_content()));
auto max_content_height = clamp_to_max_dimension_value(context->automatic_content_height());
cache_slot.emplace(max_content_height);
if (auto* cache_slot = get_cache_slot()) {
*cache_slot = max_content_height;
}
return max_content_height;
}

View file

@ -221,6 +221,18 @@ struct LayoutState {
HashMap<GC::Ref<Layout::Node const>, NonnullOwnPtr<UsedValues>> used_values_per_layout_node;
// We cache intrinsic sizes once determined, as they will not change over the course of a full layout.
// This avoids computing them several times while performing flex layout.
struct IntrinsicSizes {
Optional<CSSPixels> min_content_width;
Optional<CSSPixels> max_content_width;
HashMap<CSSPixels, Optional<CSSPixels>> min_content_height;
HashMap<CSSPixels, Optional<CSSPixels>> max_content_height;
};
HashMap<GC::Ptr<NodeWithStyle const>, NonnullOwnPtr<IntrinsicSizes>> mutable intrinsic_sizes;
LayoutState const* m_parent { nullptr };
LayoutState const& m_root;