LibWeb: Derive box baseline from last child *with line boxes*

Before this change, we always derived a box's baseline from its last
child, even if the last child didn't have any line boxes inside.

This caused baselines to slip further down vertically than expected.

There are more baseline alignment issues to fix, but this one was
responsible for a fair chunk of trouble. :^)
This commit is contained in:
Andreas Kling 2023-07-25 10:58:11 +02:00
parent 7b3902e3d5
commit ccf35a973f
Notes: sideshowbarker 2024-07-17 08:27:05 +09:00
7 changed files with 107 additions and 8 deletions

View file

@ -0,0 +1,22 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (1,1) content-size 798x600 [BFC] children: not-inline
BlockContainer <body> at (10,10) content-size 780x92.9375 children: inline
line 0 width: 307.140625, height: 92.9375, bottom: 92.9375, baseline: 35
frag 0 from TextNode start: 0, length: 13, rect: [10,31.46875 103.140625x17.46875]
"Hello friends"
frag 1 from BlockContainer start: 0, length: 0, rect: [114.140625,11 202x90.9375]
TextNode <#text>
BlockContainer <div.ib> at (114.140625,11) content-size 202x90.9375 inline-block [BFC] children: not-inline
BlockContainer <div> at (115.140625,12) content-size 200x17.46875 children: inline
line 0 width: 22.546875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 3, rect: [115.140625,12 22.546875x17.46875]
"1st"
TextNode <#text>
BlockContainer <div> at (115.140625,31.46875) content-size 200x17.46875 children: inline
line 0 width: 26.28125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 3, rect: [115.140625,31.46875 26.28125x17.46875]
"2nd"
TextNode <#text>
BlockContainer <div.whee> at (115.140625,50.9375) content-size 200x50 children: not-inline
BlockContainer <(anonymous)> at (114.140625,101.9375) content-size 202x0 children: inline
TextNode <#text>

View file

@ -0,0 +1,26 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (1,1) content-size 798x600 [BFC] children: not-inline
BlockContainer <body> at (10,10) content-size 780x60.40625 children: inline
line 0 width: 144.375, height: 60.40625, bottom: 60.40625, baseline: 35
frag 0 from TextNode start: 0, length: 13, rect: [10,31.46875 103.140625x17.46875]
"Hello friends"
frag 1 from BlockContainer start: 0, length: 0, rect: [114.140625,11 39.234375x58.40625]
TextNode <#text>
BlockContainer <div.ib> at (114.140625,11) content-size 39.234375x58.40625 inline-block [BFC] children: not-inline
BlockContainer <div> at (115.140625,12) content-size 37.234375x17.46875 children: inline
line 0 width: 22.546875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 3, rect: [115.140625,12 22.546875x17.46875]
"1st"
TextNode <#text>
BlockContainer <div> at (115.140625,31.46875) content-size 37.234375x17.46875 children: inline
line 0 width: 26.28125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 3, rect: [115.140625,31.46875 26.28125x17.46875]
"2nd"
TextNode <#text>
BlockContainer <div.float> at (115.140625,50.9375) content-size 37.234375x17.46875 floating [BFC] children: inline
line 0 width: 37.234375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 5, rect: [115.140625,50.9375 37.234375x17.46875]
"float"
TextNode <#text>
BlockContainer <(anonymous)> at (114.140625,49.9375) content-size 39.234375x0 children: inline
TextNode <#text>

View file

@ -1,12 +1,12 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (1,1) content-size 798x135 [BFC] children: inline
line 0 width: 170.96875, height: 135, bottom: 135, baseline: 13.53125
frag 0 from BlockContainer start: 0, length: 0, rect: [2,15.53125 168.96875x119.46875]
BlockContainer <body> at (2,15.53125) content-size 168.96875x119.46875 inline-block [BFC] children: not-inline
BlockContainer <div.hmm> at (3,16.53125) content-size 166.96875x17.46875 children: inline
BlockContainer <html> at (1,1) content-size 798x121.46875 [BFC] children: inline
line 0 width: 170.96875, height: 121.46875, bottom: 121.46875, baseline: 15.53125
frag 0 from BlockContainer start: 0, length: 0, rect: [2,2 168.96875x119.46875]
BlockContainer <body> at (2,2) content-size 168.96875x119.46875 inline-block [BFC] children: not-inline
BlockContainer <div.hmm> at (3,3) content-size 166.96875x17.46875 children: inline
line 0 width: 166.96875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 21, rect: [3,16.53125 166.96875x17.46875]
frag 0 from TextNode start: 0, length: 21, rect: [3,3 166.96875x17.46875]
"suspiciously tall box"
TextNode <#text>
BlockContainer <(anonymous)> at (2,135) content-size 168.96875x0 children: inline
BlockContainer <(anonymous)> at (2,121.46875) content-size 168.96875x0 children: inline
TextNode <#text>

View file

@ -0,0 +1,16 @@
<style>
* {
border: 1px solid black;
}
.ib {
display: inline-block;
}
.ib div {
background: pink;
}
.ib div.whee {
width: 200px;
height: 50px;
background: orange;
}
</style><body>Hello friends<div class=ib><div>1st</div><div>2nd</div><div class="whee"></div>

View file

@ -0,0 +1,15 @@
<style>
* {
border: 1px solid black;
}
.ib {
display: inline-block;
}
.ib div {
background: pink;
}
.ib div.float {
background: orange;
float: left;
}
</style><body>Hello friends<div class=ib><div>1st</div><div>2nd</div><div class="float">float</div>

View file

@ -1686,6 +1686,24 @@ CSSPixelRect FormattingContext::absolute_content_rect(Box const& box) const
return rect;
}
Box const* FormattingContext::box_child_to_derive_baseline_from(Box const& box) const
{
// To find the baseline of a box, we first look for the last in-flow child with at least one line box.
auto const* last_box_child = box.last_child_of_type<Box>();
for (Node const* child = last_box_child; child; child = child->previous_sibling()) {
if (!child->is_box())
continue;
auto& child_box = static_cast<Box const&>(*child);
if (child_box.is_out_of_flow(*this))
continue;
if (m_state.get(child_box).line_boxes.is_empty())
continue;
return &child_box;
}
// If none of the children has a line box, the baseline is formed by the last in-flow child.
return last_box_child;
}
CSSPixels FormattingContext::box_baseline(Box const& box) const
{
auto const& box_state = m_state.get(box);
@ -1714,7 +1732,7 @@ CSSPixels FormattingContext::box_baseline(Box const& box) const
if (!box_state.line_boxes.is_empty())
return box_state.margin_box_top() + box_state.offset.y() + box_state.line_boxes.last().baseline();
if (box.has_children() && !box.children_are_inline()) {
auto const* child_box = box.last_child_of_type<Box>();
auto const* child_box = box_child_to_derive_baseline_from(box);
VERIFY(child_box);
return box_baseline(*child_box);
}

View file

@ -151,6 +151,8 @@ protected:
[[nodiscard]] Optional<CSSPixels> compute_auto_height_for_absolutely_positioned_element(Box const&, AvailableSpace const&, BeforeOrAfterInsideLayout) const;
[[nodiscard]] Box const* box_child_to_derive_baseline_from(Box const&) const;
Type m_type {};
FormattingContext* m_parent { nullptr };