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
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;
}
}