From 0d2800e4117f21bd33a636834d1f0e36e17f48cf Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 24 Aug 2025 17:34:46 +0200 Subject: [PATCH] LibWeb: Don't relocate fragments across atomic inline boundary All fragments inside an atomic inline box should stay within that box, otherwise we'll screw up the paint order and paint them behind things that they're supposed to be on top of. This fixes an issue with inline-block content not appearing on sites like Google Docs and Reddit, among others. --- Libraries/LibWeb/Layout/LayoutState.cpp | 2 ++ Libraries/LibWeb/Layout/LineBoxFragment.cpp | 2 +- Libraries/LibWeb/Layout/Node.cpp | 8 ++++++++ Libraries/LibWeb/Layout/Node.h | 2 ++ ...sition-containing-block-inline-situation.txt | 6 +++--- ...no-relocation-of-atomic-inline-fragments.txt | 17 +++++++++++++++++ .../inline-fragment-ordering-flakiness.txt | 6 +++--- ...o-relocation-of-atomic-inline-fragments.html | 11 +++++++++++ 8 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/block-and-inline/no-relocation-of-atomic-inline-fragments.txt create mode 100644 Tests/LibWeb/Layout/input/block-and-inline/no-relocation-of-atomic-inline-fragments.html diff --git a/Libraries/LibWeb/Layout/LayoutState.cpp b/Libraries/LibWeb/Layout/LayoutState.cpp index b412e44ce55..0c2b574837d 100644 --- a/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Libraries/LibWeb/Layout/LayoutState.cpp @@ -258,6 +258,8 @@ void LayoutState::commit(Box& root) auto try_to_relocate_fragment_in_inline_node = [&](auto& fragment, size_t line_index) -> bool { for (auto const* parent = fragment.layout_node().parent(); parent; parent = parent->parent()) { + if (parent->is_atomic_inline()) + break; if (is(*parent)) { auto& inline_node = const_cast(static_cast(*parent)); auto line_paintable = inline_node.create_paintable_for_line_with_index(line_index); diff --git a/Libraries/LibWeb/Layout/LineBoxFragment.cpp b/Libraries/LibWeb/Layout/LineBoxFragment.cpp index 1f433cdf986..eab199ec8e8 100644 --- a/Libraries/LibWeb/Layout/LineBoxFragment.cpp +++ b/Libraries/LibWeb/Layout/LineBoxFragment.cpp @@ -68,7 +68,7 @@ Utf16View LineBoxFragment::text() const bool LineBoxFragment::is_atomic_inline() const { - return layout_node().is_replaced_box() || (layout_node().display().is_inline_outside() && !layout_node().display().is_flow_inside()); + return layout_node().is_atomic_inline(); } CSS::Direction LineBoxFragment::resolve_glyph_run_direction(Gfx::GlyphRun::TextType text_type) const diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index 3eaec5dd827..95633072828 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -1125,6 +1125,14 @@ bool Node::is_inline_table() const return display.is_inline_outside() && display.is_table_inside(); } +bool Node::is_atomic_inline() const +{ + if (is_replaced_box()) + return true; + auto display = this->display(); + return display.is_inline_outside() && !display.is_flow_inside(); +} + GC::Ref NodeWithStyle::create_anonymous_wrapper() const { auto wrapper = heap().allocate(const_cast(document()), nullptr, computed_values().clone_inherited_values()); diff --git a/Libraries/LibWeb/Layout/Node.h b/Libraries/LibWeb/Layout/Node.h index 70b38754098..6fd5fc9f12c 100644 --- a/Libraries/LibWeb/Layout/Node.h +++ b/Libraries/LibWeb/Layout/Node.h @@ -95,6 +95,8 @@ public: bool is_inline_block() const; bool is_inline_table() const; + bool is_atomic_inline() const; + bool is_out_of_flow(FormattingContext const&) const; // These are used to optimize hot is variants for some classes where dynamic_cast is too slow. diff --git a/Tests/LibWeb/Layout/expected/abspos-static-position-containing-block-inline-situation.txt b/Tests/LibWeb/Layout/expected/abspos-static-position-containing-block-inline-situation.txt index ef01b5186a5..0afb9834c77 100644 --- a/Tests/LibWeb/Layout/expected/abspos-static-position-containing-block-inline-situation.txt +++ b/Tests/LibWeb/Layout/expected/abspos-static-position-containing-block-inline-situation.txt @@ -2,15 +2,15 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer at (0,0) content-size 800x18 [BFC] children: inline InlineNode frag 0 from BlockContainer start: 0, length: 0, rect: [8,13 0x0] baseline: 0 - frag 1 from TextNode start: 0, length: 5, rect: [8,0 36.84375x18] baseline: 13.796875 - "hello" BlockContainer
at (8,13) content-size 0x0 inline-block [BFC] children: not-inline BlockContainer
at (8,0) content-size 36.84375x18 positioned [BFC] children: inline + frag 0 from TextNode start: 0, length: 5, rect: [8,0 36.84375x18] baseline: 13.796875 + "hello" TextNode <#text> ViewportPaintable (Viewport<#document>) [0,0 800x600] PaintableWithLines (BlockContainer) [0,0 800x18] - PaintableWithLines (InlineNode) [8,13 36.84375x18] + PaintableWithLines (InlineNode) [0,13 36.84375x0] PaintableWithLines (BlockContainer
) [8,13 0x0] PaintableWithLines (BlockContainer
) [8,0 36.84375x18] TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/no-relocation-of-atomic-inline-fragments.txt b/Tests/LibWeb/Layout/expected/block-and-inline/no-relocation-of-atomic-inline-fragments.txt new file mode 100644 index 00000000000..05483ad2ec0 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/no-relocation-of-atomic-inline-fragments.txt @@ -0,0 +1,17 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x18 [BFC] children: inline + InlineNode + frag 0 from BlockContainer start: 0, length: 0, rect: [8,0 11.796875x18] baseline: 13.796875 + BlockContainer
at (8,0) content-size 11.796875x18 positioned inline-block [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [8,0 11.796875x18] baseline: 13.796875 + "$" + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x18] + PaintableWithLines (InlineNode) [0,0 23.59375x18] + PaintableWithLines (BlockContainer
) [8,0 11.796875x18] + TextPaintable (TextNode<#text>) + +SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto) + SC for BlockContainer [0,0 800x18] [children: 0] (z-index: auto) diff --git a/Tests/LibWeb/Layout/expected/inline-fragment-ordering-flakiness.txt b/Tests/LibWeb/Layout/expected/inline-fragment-ordering-flakiness.txt index 03b43f4802b..35126f5e22c 100644 --- a/Tests/LibWeb/Layout/expected/inline-fragment-ordering-flakiness.txt +++ b/Tests/LibWeb/Layout/expected/inline-fragment-ordering-flakiness.txt @@ -2,16 +2,16 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer at (0,0) content-size 800x18 [BFC] children: inline InlineNode frag 0 from BlockContainer start: 0, length: 0, rect: [8,0 36.84375x18] baseline: 13.796875 - frag 1 from TextNode start: 0, length: 5, rect: [8,0 36.84375x18] baseline: 13.796875 - "hello" BlockContainer
at (8,0) content-size 36.84375x18 inline-block [BFC] children: not-inline BlockContainer
at (8,0) content-size 36.84375x18 children: inline + frag 0 from TextNode start: 0, length: 5, rect: [8,0 36.84375x18] baseline: 13.796875 + "hello" TextNode <#text> TextNode <#text> ViewportPaintable (Viewport<#document>) [0,0 800x600] PaintableWithLines (BlockContainer) [0,0 800x18] - PaintableWithLines (InlineNode) [8,0 73.6875x18] + PaintableWithLines (InlineNode) [0,0 73.6875x18] PaintableWithLines (BlockContainer
) [8,0 36.84375x18] PaintableWithLines (BlockContainer
) [8,0 36.84375x18] TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/input/block-and-inline/no-relocation-of-atomic-inline-fragments.html b/Tests/LibWeb/Layout/input/block-and-inline/no-relocation-of-atomic-inline-fragments.html new file mode 100644 index 00000000000..568edb5e700 --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/no-relocation-of-atomic-inline-fragments.html @@ -0,0 +1,11 @@ +
$