LibWeb: Mark height as definite before doing inner layout of abspos

...boxes with non-auto height.

We know for sure that by the time we layout abspos boxes, their
containing block has definite height, so it's possible to resolve
non-auto heights and mark it as definite before doing inner layout.

Big step towards having reasonable performance on
https://demo.immich.app/photos because now we avoid a bunch of work
initiated by mistakenly invoked intersection observer callbacks.

Co-Authored-By: Andreas Kling <andreas@ladybird.org>
This commit is contained in:
Aliaksandr Kalenik 2025-03-21 20:08:47 +01:00
parent 9ec986753a
commit a055c9f9f1
3 changed files with 38 additions and 4 deletions

View file

@ -1170,9 +1170,9 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el
box_state.set_content_height(used_height.to_px(box));
// do not set calculated insets or margins on the first pass, there will be a second pass
if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
if (box.computed_values().height().is_auto() && before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
return;
box_state.set_has_definite_height(true);
box_state.inset_top = top.to_px(box, height_of_containing_block);
box_state.inset_bottom = bottom.to_px(box, height_of_containing_block);
box_state.margin_top = margin_top.to_px(box, width_of_containing_block);
@ -1255,7 +1255,9 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava
auto independent_formatting_context = layout_inside(box, LayoutMode::Normal, box_state.available_inner_space_or_constraints_from(available_space));
compute_height_for_absolutely_positioned_element(box, available_space, BeforeOrAfterInsideLayout::After);
if (box.computed_values().height().is_auto()) {
compute_height_for_absolutely_positioned_element(box, available_space, BeforeOrAfterInsideLayout::After);
}
CSSPixelPoint used_offset;
@ -1350,8 +1352,9 @@ void FormattingContext::compute_height_for_absolutely_positioned_replaced_elemen
box_state.set_content_height(height);
// do not set calculated insets or margins on the first pass, there will be a second pass
if (before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
if (box.computed_values().height().is_auto() && before_or_after_inside_layout == BeforeOrAfterInsideLayout::Before)
return;
box_state.set_has_definite_height(true);
box_state.inset_top = to_px(top);
box_state.inset_bottom = to_px(bottom);
box_state.margin_top = to_px(margin_top);

View file

@ -0,0 +1,13 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x16 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x0 positioned children: not-inline
BlockContainer <main> at (8,8) content-size 120x0 positioned [BFC] children: not-inline
BlockContainer <div#asset-grid> at (18,18) content-size 100x0 children: not-inline
BlockContainer <div#virtual-timeline> at (18,18) content-size 100x30 children: not-inline
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x16]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x0]
PaintableWithLines (BlockContainer<MAIN>) [8,8 120x0] overflow: [8,8 120x40]
PaintableWithLines (BlockContainer<DIV>#asset-grid) [8,8 120x20] overflow: [18,18 100x30]
PaintableWithLines (BlockContainer<DIV>#virtual-timeline) [18,18 100x30]

View file

@ -0,0 +1,18 @@
<!doctype html><style>
* { outline: 1px solid black; }
body { position: relative; }
main {
position: absolute;
height: 100%;
}
#asset-grid {
background: pink;
height: 100%;
width: 100px;
border: 10px solid red;
}
#virtual-timeline {
background: orange;
height: 30px;
}
</style><body><main><div id="asset-grid"><div id="virtual-timeline">