LibWeb: Stop treating intrinsic size keywords as auto in CSS heights

This commit introduces proper handling of three intrinsic size keywords
when used for CSS heights:

- min-content
- max-content
- fit-content

This necessitated a few plumbing changes, since we can't resolve these
values without having access to containing block widths.

This fixes some visual glitches on https://www.supabase.com/ as well
as a number of WPT tests. It also improves the appearance of dialogs.
This commit is contained in:
Andreas Kling
2024-11-21 17:32:02 +01:00
committed by Andreas Kling
parent f093a8af67
commit fbe9395928
10 changed files with 120 additions and 104 deletions

View File

@@ -624,7 +624,7 @@ CSSPixels FormattingContext::tentative_height_for_replaced_element(Box const& bo
return 150;
// FIXME: Handle cases when available_space is not definite.
return calculate_inner_height(box, available_space.height, computed_height);
return calculate_inner_height(box, available_space, computed_height);
}
CSSPixels FormattingContext::compute_height_for_replaced_element(Box const& box, AvailableSpace const& available_space) const
@@ -954,12 +954,12 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
auto const& computed_max_height = box.computed_values().max_height();
auto constrained_height = unconstrained_height;
if (!computed_max_height.is_none()) {
auto inner_max_height = calculate_inner_height(box, available_space.height, computed_max_height);
auto inner_max_height = calculate_inner_height(box, available_space, computed_max_height);
if (inner_max_height < constrained_height.to_px(box))
constrained_height = CSS::Length::make_px(inner_max_height);
}
if (!computed_min_height.is_auto()) {
auto inner_min_height = calculate_inner_height(box, available_space.height, computed_min_height);
auto inner_min_height = calculate_inner_height(box, available_space, computed_min_height);
if (inner_min_height > constrained_height.to_px(box))
constrained_height = CSS::Length::make_px(inner_min_height);
}
@@ -1148,7 +1148,7 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
return CSS::Length::make_px(compute_table_box_height_inside_table_wrapper(box, available_space));
if (should_treat_height_as_auto(box, available_space))
return CSS::Length::make_auto();
return CSS::Length::make_px(calculate_inner_height(box, available_space.height, box.computed_values().height()));
return CSS::Length::make_px(calculate_inner_height(box, available_space, box.computed_values().height()));
}());
used_height = apply_min_max_height_constraints(used_height);
@@ -1614,11 +1614,23 @@ CSSPixels FormattingContext::calculate_inner_width(Layout::Box const& box, Avail
return width.to_px(box, width_of_containing_block);
}
CSSPixels FormattingContext::calculate_inner_height(Layout::Box const& box, AvailableSize const& available_height, CSS::Size const& height) const
CSSPixels FormattingContext::calculate_inner_height(Layout::Box const& box, AvailableSpace const& available_space, CSS::Size const& height) const
{
VERIFY(!height.is_auto());
auto height_of_containing_block = available_height.to_px_or_zero();
if (height.is_fit_content()) {
return calculate_fit_content_height(box, available_space);
}
if (height.is_max_content()) {
return calculate_max_content_height(box, available_space.width.to_px_or_zero());
}
if (height.is_min_content()) {
return calculate_min_content_height(box, available_space.width.to_px_or_zero());
}
auto height_of_containing_block = available_space.height.to_px_or_zero();
auto& computed_values = box.computed_values();
if (computed_values.box_sizing() == CSS::BoxSizing::BorderBox) {
auto const& state = m_state.get(box);
auto inner_height = height.to_px(box, height_of_containing_block)
@@ -1682,7 +1694,7 @@ CSSPixels FormattingContext::calculate_stretch_fit_height(Box const& box, Availa
- box_state.border_bottom;
}
bool FormattingContext::should_treat_width_as_auto(Box const& box, AvailableSpace const& available_space)
bool FormattingContext::should_treat_width_as_auto(Box const& box, AvailableSpace const& available_space) const
{
auto const& computed_width = box.computed_values().width();
if (computed_width.is_auto())
@@ -1693,35 +1705,42 @@ bool FormattingContext::should_treat_width_as_auto(Box const& box, AvailableSpac
if (available_space.width.is_indefinite())
return true;
}
// AD-HOC: If the box has a preferred aspect ratio and no natural height,
// we treat the width as auto, since it can't be resolved through the ratio.
if (computed_width.is_min_content() || computed_width.is_max_content() || computed_width.is_fit_content()) {
if (box.has_preferred_aspect_ratio() && !box.has_natural_height())
// AD-HOC: If the box has a preferred aspect ratio and an intrinsic keyword for width...
if (box.has_preferred_aspect_ratio()
&& (computed_width.is_min_content() || computed_width.is_max_content() || computed_width.is_fit_content())) {
// If the box has no natural height to resolve the aspect ratio, we treat the width as auto.
if (!box.has_natural_height())
return true;
// If the box has definite height, we can resolve the width through the aspect ratio.
if (m_state.get(box).has_definite_height())
return true;
}
return false;
}
bool FormattingContext::should_treat_height_as_auto(Box const& box, AvailableSpace const& available_space)
bool FormattingContext::should_treat_height_as_auto(Box const& box, AvailableSpace const& available_space) const
{
auto computed_height = box.computed_values().height();
if (computed_height.is_auto())
return true;
// https://www.w3.org/TR/css-sizing-3/#valdef-width-min-content
// https://www.w3.org/TR/css-sizing-3/#valdef-width-max-content
// https://www.w3.org/TR/css-sizing-3/#valdef-width-fit-content
// For a boxs block size, unless otherwise specified, this is equivalent to its automatic size.
// FIXME: If height is not the block axis size, then we should be concerned with the width instead.
if (computed_height.is_min_content() || computed_height.is_max_content() || computed_height.is_fit_content())
return true;
if (box.computed_values().height().contains_percentage()) {
if (computed_height.contains_percentage()) {
if (available_space.height.is_max_content())
return true;
if (available_space.height.is_indefinite())
return true;
}
// AD-HOC: If the box has a preferred aspect ratio and an intrinsic keyword for height...
if (box.has_preferred_aspect_ratio()
&& (computed_height.is_min_content() || computed_height.is_max_content() || computed_height.is_fit_content())) {
// If the box has no natural width to resolve the aspect ratio, we treat the height as auto.
if (!box.has_natural_width())
return true;
// If the box has definite width, we can resolve the height through the aspect ratio.
if (m_state.get(box).has_definite_width())
return true;
}
return false;
}