mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 05:37:35 +00:00
LibWeb: Split intrinsic heights cache based on available width
Now that intrinsic heights (correctly) depend on the amount of available width, we can't just cache the first calculated min-content and max-content heights and reuse it without thinking. Instead, we have to cache three pairs: - min-content & max-content height with definite available width - min-content & max-content height with min-content available width - min-content & max-content height with max-content available width There might be some more elegant way of solving this, but basically this makes the cache work correctly when someone's containing block is being sized under a width constraint.
This commit is contained in:
parent
4b74f36cd0
commit
b945d164e2
2 changed files with 54 additions and 19 deletions
|
@ -1057,11 +1057,22 @@ float FormattingContext::calculate_min_content_height(Layout::Box const& box, Av
|
||||||
if (box.has_intrinsic_height())
|
if (box.has_intrinsic_height())
|
||||||
return *box.intrinsic_height();
|
return *box.intrinsic_height();
|
||||||
|
|
||||||
auto& root_state = m_state.m_root;
|
bool is_cacheable = available_width.is_definite() || available_width.is_intrinsic_sizing_constraint();
|
||||||
|
Optional<float>* cache_slot;
|
||||||
|
if (is_cacheable) {
|
||||||
|
auto& root_state = m_state.m_root;
|
||||||
|
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
|
||||||
|
if (available_width.is_definite()) {
|
||||||
|
cache_slot = &cache.min_content_height_with_definite_available_width;
|
||||||
|
} else if (available_width.is_min_content()) {
|
||||||
|
cache_slot = &cache.min_content_height_with_min_content_available_width;
|
||||||
|
} else if (available_width.is_max_content()) {
|
||||||
|
cache_slot = &cache.min_content_height_with_max_content_available_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
|
if (cache_slot && cache_slot->has_value())
|
||||||
if (cache.min_content_height.has_value())
|
return cache_slot->value();
|
||||||
return *cache.min_content_height;
|
|
||||||
|
|
||||||
LayoutState throwaway_state(&m_state);
|
LayoutState throwaway_state(&m_state);
|
||||||
|
|
||||||
|
@ -1073,15 +1084,17 @@ float FormattingContext::calculate_min_content_height(Layout::Box const& box, Av
|
||||||
|
|
||||||
context->run(box, LayoutMode::IntrinsicSizing, AvailableSpace(available_width, AvailableSize::make_min_content()));
|
context->run(box, LayoutMode::IntrinsicSizing, AvailableSpace(available_width, AvailableSize::make_min_content()));
|
||||||
|
|
||||||
cache.min_content_height = context->automatic_content_height();
|
auto min_content_height = context->automatic_content_height();
|
||||||
|
if (!isfinite(min_content_height)) {
|
||||||
if (!isfinite(*cache.min_content_height)) {
|
|
||||||
// HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine.
|
// HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine.
|
||||||
dbgln("FIXME: Calculated non-finite min-content height for {}", box.debug_description());
|
dbgln("FIXME: Calculated non-finite min-content height for {}", box.debug_description());
|
||||||
cache.min_content_height = 0;
|
min_content_height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *cache.min_content_height;
|
if (cache_slot) {
|
||||||
|
*cache_slot = min_content_height;
|
||||||
|
}
|
||||||
|
return min_content_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
float FormattingContext::calculate_max_content_height(Layout::Box const& box, AvailableSize const& available_width) const
|
float FormattingContext::calculate_max_content_height(Layout::Box const& box, AvailableSize const& available_width) const
|
||||||
|
@ -1089,11 +1102,22 @@ float FormattingContext::calculate_max_content_height(Layout::Box const& box, Av
|
||||||
if (box.has_intrinsic_height())
|
if (box.has_intrinsic_height())
|
||||||
return *box.intrinsic_height();
|
return *box.intrinsic_height();
|
||||||
|
|
||||||
auto& root_state = m_state.m_root;
|
bool is_cacheable = available_width.is_definite() || available_width.is_intrinsic_sizing_constraint();
|
||||||
|
Optional<float>* cache_slot;
|
||||||
|
if (is_cacheable) {
|
||||||
|
auto& root_state = m_state.m_root;
|
||||||
|
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
|
||||||
|
if (available_width.is_definite()) {
|
||||||
|
cache_slot = &cache.max_content_height_with_definite_available_width;
|
||||||
|
} else if (available_width.is_min_content()) {
|
||||||
|
cache_slot = &cache.max_content_height_with_min_content_available_width;
|
||||||
|
} else if (available_width.is_max_content()) {
|
||||||
|
cache_slot = &cache.max_content_height_with_max_content_available_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto& cache = *root_state.intrinsic_sizes.ensure(&box, [] { return adopt_own(*new LayoutState::IntrinsicSizes); });
|
if (cache_slot && cache_slot->has_value())
|
||||||
if (cache.max_content_height.has_value())
|
return cache_slot->value();
|
||||||
return *cache.max_content_height;
|
|
||||||
|
|
||||||
LayoutState throwaway_state(&m_state);
|
LayoutState throwaway_state(&m_state);
|
||||||
|
|
||||||
|
@ -1105,15 +1129,19 @@ float FormattingContext::calculate_max_content_height(Layout::Box const& box, Av
|
||||||
|
|
||||||
context->run(box, LayoutMode::IntrinsicSizing, AvailableSpace(available_width, AvailableSize::make_max_content()));
|
context->run(box, LayoutMode::IntrinsicSizing, AvailableSpace(available_width, AvailableSize::make_max_content()));
|
||||||
|
|
||||||
cache.max_content_height = context->automatic_content_height();
|
auto max_content_height = context->automatic_content_height();
|
||||||
|
|
||||||
if (!isfinite(*cache.max_content_height)) {
|
if (!isfinite(max_content_height)) {
|
||||||
// HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine.
|
// HACK: If layout calculates a non-finite result, something went wrong. Force it to zero and log a little whine.
|
||||||
dbgln("FIXME: Calculated non-finite max-content height for {}", box.debug_description());
|
dbgln("FIXME: Calculated non-finite max-content height for {}", box.debug_description());
|
||||||
cache.max_content_height = 0;
|
max_content_height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *cache.max_content_height;
|
if (cache_slot) {
|
||||||
|
*cache_slot = max_content_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_content_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
float FormattingContext::containing_block_width_for(Box const& box, LayoutState const& state)
|
float FormattingContext::containing_block_width_for(Box const& box, LayoutState const& state)
|
||||||
|
|
|
@ -155,8 +155,15 @@ struct LayoutState {
|
||||||
struct IntrinsicSizes {
|
struct IntrinsicSizes {
|
||||||
Optional<float> min_content_width;
|
Optional<float> min_content_width;
|
||||||
Optional<float> max_content_width;
|
Optional<float> max_content_width;
|
||||||
Optional<float> min_content_height;
|
|
||||||
Optional<float> max_content_height;
|
// NOTE: Since intrinsic heights depend on the amount of available width, we have to cache
|
||||||
|
// three separate results, depending on the available width at the time of calculation.
|
||||||
|
Optional<float> min_content_height_with_definite_available_width;
|
||||||
|
Optional<float> max_content_height_with_definite_available_width;
|
||||||
|
Optional<float> min_content_height_with_min_content_available_width;
|
||||||
|
Optional<float> max_content_height_with_min_content_available_width;
|
||||||
|
Optional<float> min_content_height_with_max_content_available_width;
|
||||||
|
Optional<float> max_content_height_with_max_content_available_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
HashMap<NodeWithStyleAndBoxModelMetrics const*, NonnullOwnPtr<IntrinsicSizes>> mutable intrinsic_sizes;
|
HashMap<NodeWithStyleAndBoxModelMetrics const*, NonnullOwnPtr<IntrinsicSizes>> mutable intrinsic_sizes;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue