1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 05:17:35 +00:00

LibWeb: Compute content width before static position for abspos elements

In some scenarios, correctly computing the static position may depend on
the content width having been calculated beforehand.
This commit is contained in:
implicitfield 2024-03-02 21:53:25 +04:00 committed by Andreas Kling
parent 18fe86adc3
commit e3b1d4a141
3 changed files with 72 additions and 4 deletions

View file

@ -0,0 +1,34 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x116 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x100 children: not-inline
BlockContainer <div#containing-block> at (8,8) content-size 200x100 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 200x0 children: inline
TextNode <#text>
Box <div#inner-flex> at (8,8) content-size 200x0 flex-container(row) [FFC] children: not-inline
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
BlockContainer <div> at (83,8) content-size 50x100 positioned [BFC] children: not-inline
BlockContainer <(anonymous)> at (83,8) content-size 50x0 children: inline
TextNode <#text>
BlockContainer <span> at (83,8) content-size 50x0 children: not-inline
BlockContainer <(anonymous)> at (83,8) content-size 50x0 children: inline
TextNode <#text>
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 200x0 children: inline
TextNode <#text>
BlockContainer <(anonymous)> at (8,108) content-size 784x0 children: inline
TextNode <#text>
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x116]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x100]
PaintableWithLines (BlockContainer<DIV>#containing-block) [8,8 200x100]
PaintableWithLines (BlockContainer(anonymous)) [8,8 200x0]
PaintableBox (Box<DIV>#inner-flex) [8,8 200x0] overflow: [83,8 50x100]
PaintableWithLines (BlockContainer<DIV>) [83,8 50x100]
PaintableWithLines (BlockContainer(anonymous)) [83,8 50x0]
PaintableWithLines (BlockContainer<SPAN>) [83,8 50x0]
PaintableWithLines (BlockContainer(anonymous)) [83,8 50x0]
PaintableWithLines (BlockContainer(anonymous)) [8,8 200x0]
PaintableWithLines (BlockContainer(anonymous)) [8,108 784x0]

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<style>
#containing-block {
width: 200px;
height: 100px;
background: red;
}
#inner-flex {
display: flex;
justify-content: center;
}
span {
display: block;
width: 50px;
}
</style>
<div id="containing-block">
<div id="inner-flex">
<div style="position: absolute; height: 100px; background: green;">
<span></span>
</div>
</div>
</div>

View file

@ -656,7 +656,7 @@ CSSPixels FormattingContext::compute_height_for_replaced_element(Box const& box,
void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_element(Box const& box, AvailableSpace const& available_space) void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_element(Box const& box, AvailableSpace const& available_space)
{ {
auto width_of_containing_block = available_space.width.to_px_or_zero(); auto width_of_containing_block = available_space.width.to_px_or_zero();
auto& computed_values = box.computed_values(); auto const& computed_values = box.computed_values();
auto zero_value = CSS::Length::make_px(0); auto zero_value = CSS::Length::make_px(0);
auto margin_left = CSS::Length::make_auto(); auto margin_left = CSS::Length::make_auto();
@ -699,10 +699,20 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
// Then, if the 'direction' property of the element establishing the static-position containing block // Then, if the 'direction' property of the element establishing the static-position containing block
// is 'ltr' set 'left' to the static position and apply rule number three below; // is 'ltr' set 'left' to the static position and apply rule number three below;
// otherwise, set 'right' to the static position and apply rule number one below. // otherwise, set 'right' to the static position and apply rule number one below.
// FIXME: This is very hackish.
// NOTE: As with compute_height_for_absolutely_positioned_non_replaced_element, we actually apply these
// steps in the opposite order since the static position may depend on the width of the box.
auto result = calculate_shrink_to_fit_widths(box);
auto available_width = solve_for_width();
CSSPixels content_width = min(max(result.preferred_minimum_width, available_width.to_px(box)), result.preferred_width);
width = CSS::Length::make_px(content_width);
m_state.get_mutable(box).set_content_width(content_width);
auto static_position = calculate_static_position(box); auto static_position = calculate_static_position(box);
left = static_position.x(); left = static_position.x();
goto Rule3; right = solve_for_right();
} }
// If none of the three is auto: // If none of the three is auto:
@ -765,7 +775,6 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
// 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto',
// then the width is shrink-to-fit. Then solve for 'right' // then the width is shrink-to-fit. Then solve for 'right'
else if (width.is_auto() && computed_right.is_auto() && !computed_left.is_auto()) { else if (width.is_auto() && computed_right.is_auto() && !computed_left.is_auto()) {
Rule3:
auto result = calculate_shrink_to_fit_widths(box); auto result = calculate_shrink_to_fit_widths(box);
auto available_width = solve_for_width(); auto available_width = solve_for_width();
width = CSS::Length::make_px(min(max(result.preferred_minimum_width, available_width.to_px(box)), result.preferred_width)); width = CSS::Length::make_px(min(max(result.preferred_minimum_width, available_width.to_px(box)), result.preferred_width));