LibWeb: Improve painting of nested inline elements

PaintableWithLines created from inline nodes need to examine their
children to fully compute their size and offset as nested children
might have textnodes that are placed before their parent.

Fixes #1286
This commit is contained in:
Christoffer Sandberg 2024-11-22 10:54:00 +01:00 committed by Sam Atkins
parent e20a887a8d
commit 879af72850
Notes: github-actions[bot] 2024-12-04 11:24:53 +00:00
4 changed files with 80 additions and 14 deletions

View file

@ -312,8 +312,9 @@ void LayoutState::commit(Box& root)
auto* paintable = inline_node->first_paintable();
if (paintable)
continue;
paintable = inline_node->create_paintable_for_line_with_index(0);
inline_node->add_paintable(paintable);
auto line_paintable = inline_node->create_paintable_for_line_with_index(0);
inline_node->add_paintable(line_paintable);
inline_node_paintables.set(line_paintable.ptr());
}
// Resolve relative positions for regular boxes (not line box fragments):
@ -377,17 +378,42 @@ void LayoutState::commit(Box& root)
continue;
}
auto const& fragments = paintable_with_lines->fragments();
if (fragments.is_empty()) {
continue;
Optional<CSSPixelPoint> offset;
CSSPixelSize size;
auto line_index = paintable_with_lines->line_index();
paintable_with_lines->for_each_in_inclusive_subtree_of_type<Painting::PaintableWithLines>([&offset, &size, &line_index](auto& paintable) {
if (paintable.line_index() == line_index) {
auto const& fragments = paintable.fragments();
if (!fragments.is_empty()) {
if (!offset.has_value() || (fragments.first().offset().x() < offset.value().x())) {
offset = fragments.first().offset();
}
}
for (auto const& fragment : fragments) {
// FIXME: Padding and margin of nested inlines not included in fragment width
size.set_width(size.width() + fragment.width());
}
}
return TraversalDecision::Continue;
});
if (offset.has_value()) {
if (!paintable_with_lines->fragments().is_empty()) {
offset.value().set_y(paintable_with_lines->fragments().first().offset().y());
}
// FIXME: If this paintable does not have any fragment we do no know the y offset. It should be where text should
// start if there had been any for this node. Pick y offset of the leftmost fragment in the inclusive subtree in the meantime.
paintable_with_lines->set_offset(offset.value());
}
paintable_with_lines->set_offset(fragments.first().offset());
CSSPixelSize size;
for (auto const& fragment : fragments) {
size.set_width(size.width() + fragment.width());
size.set_height(max(size.height(), fragment.height()));
if (!paintable_with_lines->fragments().is_empty()) {
for (auto const& fragment : paintable_with_lines->fragments()) {
size.set_height(max(size.height(), fragment.height()));
}
} else {
size.set_height(paintable_with_lines->layout_node().computed_values().line_height());
}
paintable_with_lines->set_content_size(size.width(), size.height());
}
@ -686,5 +712,4 @@ void LayoutState::UsedValues::set_indefinite_content_height()
{
m_has_definite_height = false;
}
}

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<style>
.bluebg {
background-color: #0000FF7F;
}
</style>
<body>
<div>
<span class="bluebg">12</span>
</div>
<div>
<span class="bluebg">12</span>
</div>
<div>
<span class="bluebg">1234</span><span>consecutive inline item</span>
</div>
<div>
<span class="bluebg">24</span>
</div>
</body>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<link rel="match" href="../expected/inline-nested-node-ref.html">
<style>
.bluebg {
background-color: #0000FF7F;
}
</style>
<body>
<div>
<span class="bluebg">1<span>2</span></span>
</div>
<div>
<span class="bluebg"><span>1</span>2</span>
</div>
<div>
<span class="bluebg">1<span>2</span>3<span>4</span></span><span>consecutive inline item</span>
</div>
<div>
<span class="bluebg"><span>2</span><span>4</span></span>
</div>
</body>

View file

@ -52,9 +52,9 @@ Test embed.vspace = "120." maps to marginBottom: 120px
Test embed.width = "100" maps to width: 0px
Test embed.width = " 00110 " maps to width: 0px
Test embed.width = "120." maps to width: 0px
Test embed.height = "100" maps to height: 0px
Test embed.height = " 00110 " maps to height: 0px
Test embed.height = "120." maps to height: 0px
Test embed.height = "100" maps to height: 17px
Test embed.height = " 00110 " maps to height: 17px
Test embed.height = "120." maps to height: 17px
Test tr.height = "100" maps to height: 100px
Test tr.height = " 00110 " maps to height: 110px
Test tr.height = "120." maps to height: 120px