diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/inline-block-vertical-align-middle.txt b/Tests/LibWeb/Layout/expected/block-and-inline/inline-block-vertical-align-middle.txt
new file mode 100644
index 00000000000..7b39efb7f13
--- /dev/null
+++ b/Tests/LibWeb/Layout/expected/block-and-inline/inline-block-vertical-align-middle.txt
@@ -0,0 +1,16 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+ BlockContainer at (0,0) content-size 800x116 [BFC] children: not-inline
+ BlockContainer
at (8,8) content-size 784x100 children: inline
+ InlineNode
+ 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 at (43,8) content-size 100x100 inline-block [BFC] children: not-inline
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [0,0 800x116]
+ PaintableWithLines (BlockContainer) [8,8 784x100]
+ InlinePaintable (InlineNode)
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer.thing) [43,8 100x100]
diff --git a/Tests/LibWeb/Layout/input/block-and-inline/inline-block-vertical-align-middle.html b/Tests/LibWeb/Layout/input/block-and-inline/inline-block-vertical-align-middle.html
new file mode 100644
index 00000000000..bf666dd2ee4
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/block-and-inline/inline-block-vertical-align-middle.html
@@ -0,0 +1,9 @@
+foo
\ No newline at end of file
diff --git a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp
index 7e3207db69e..35bfc39f30f 100644
--- a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp
+++ b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp
@@ -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(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();
};