LibWeb: Implement vertical-align: middle correctly for atomic inlines

This makes inline icons pop into the right place on https://ahrefs.com/
This commit is contained in:
Andreas Kling 2024-08-26 10:28:26 +02:00 committed by Andreas Kling
parent c42679597a
commit c22acc2551
Notes: github-actions[bot] 2024-08-26 13:50:02 +00:00
3 changed files with 38 additions and 6 deletions

View file

@ -0,0 +1,16 @@
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: inline
InlineNode <span>
frag 0 from TextNode start: 0, length: 4, rect: [8,49 35.15625x17] baseline: 13.296875
"foo "
frag 1 from BlockContainer start: 0, length: 0, rect: [43,8 100x100] baseline: 54.296875
TextNode <#text>
BlockContainer <span.thing> at (43,8) content-size 100x100 inline-block [BFC] children: not-inline
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x116]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x100]
InlinePaintable (InlineNode<SPAN>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<SPAN>.thing) [43,8 100x100]

View file

@ -0,0 +1,9 @@
<!doctype html><style>
* { outline: 1px solid black; }
.thing {
display: inline-block;
vertical-align: middle;
width: 100px;
height: 100px;
}
</style><body><span>foo <span class="thing"></span>

View file

@ -261,25 +261,32 @@ void LineBuilder::update_last_line()
CSSPixels new_fragment_y = 0;
auto y_value_for_alignment = [&](CSS::VerticalAlign vertical_align) {
CSSPixels effective_box_top = fragment.border_box_top();
CSSPixels effective_box_top_offset = fragment.border_box_top();
CSSPixels effective_box_bottom_offset = fragment.border_box_top();
if (fragment.is_atomic_inline()) {
auto const& fragment_box_state = m_layout_state.get(static_cast<Box const&>(fragment.layout_node()));
effective_box_top = fragment_box_state.margin_box_top();
effective_box_top_offset = fragment_box_state.margin_box_top();
effective_box_bottom_offset = fragment_box_state.margin_box_bottom();
}
switch (vertical_align) {
case CSS::VerticalAlign::Baseline:
return m_current_y + line_box_baseline - fragment.baseline() + effective_box_top;
return m_current_y + line_box_baseline - fragment.baseline() + effective_box_top_offset;
case CSS::VerticalAlign::Top:
return m_current_y + effective_box_top;
case CSS::VerticalAlign::Middle:
return m_current_y + effective_box_top_offset;
case CSS::VerticalAlign::Middle: {
// Align the vertical midpoint of the box with the baseline of the parent box
// plus half the x-height of the parent.
auto const x_height = CSSPixels::nearest_value_for(m_context.containing_block().first_available_font().pixel_metrics().x_height);
return m_current_y + line_box_baseline + ((effective_box_top_offset - effective_box_bottom_offset - x_height - fragment.height()) / 2);
}
case CSS::VerticalAlign::Bottom:
case CSS::VerticalAlign::Sub:
case CSS::VerticalAlign::Super:
case CSS::VerticalAlign::TextBottom:
case CSS::VerticalAlign::TextTop:
// FIXME: These are all 'baseline'
return m_current_y + line_box_baseline - fragment.baseline() + effective_box_top;
return m_current_y + line_box_baseline - fragment.baseline() + effective_box_top_offset;
}
VERIFY_NOT_REACHED();
};