layout: Ensure IFC for abspos with inline-level original display (#39041)

Absolutely positioned elements get blockified, but their static position
still depends on the original display. Therefore, if we encounter an
abspos with an inline-level original display, we will now ensure that
it's handled in an inline formatting context. This way its static
position will correctly take into account things like `text-align`.

Testing: Several WPT tests are now passing.
Fixes: #39017

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-09-02 05:43:55 +02:00 committed by GitHub
parent 665ee150a6
commit 9264ef1a95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 42 additions and 44 deletions

View file

@ -10,6 +10,7 @@ use style::properties::ComputedValues;
use style::properties::longhands::list_style_position::computed_value::T as ListStylePosition;
use style::selector_parser::PseudoElement;
use style::str::char_is_whitespace;
use style::values::specified::box_::DisplayOutside as StyloDisplayOutside;
use super::OutsideMarker;
use super::inline::construct::InlineFormattingContextBuilder;
@ -587,22 +588,34 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
contents: Contents,
box_slot: BoxSlot<'dom>,
) {
if let Some(builder) = self.inline_formatting_context_builder.as_mut() {
if !builder.is_empty {
let constructor = || {
ArcRefCell::new(AbsolutelyPositionedBox::construct(
self.context,
info,
display_inside,
contents,
))
};
let old_layout_box = box_slot.take_layout_box_if_undamaged(info.damage);
let inline_level_box =
builder.push_absolutely_positioned_box(constructor, old_layout_box);
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
return;
}
// If the original display was inline-level, then we need an inline formatting context
// in order to compute the static position correctly.
// If it was block-level, we don't want to break an existing inline formatting context,
// so push it there (`LineItemLayout::layout_absolute` can handle this well). But if
// there is no inline formatting context, then we can avoid creating one.
let needs_inline_builder =
info.style.get_box().original_display.outside() == StyloDisplayOutside::Inline;
if needs_inline_builder {
self.ensure_inline_formatting_context_builder();
}
let inline_builder = self
.inline_formatting_context_builder
.as_mut()
.filter(|builder| needs_inline_builder || !builder.is_empty);
if let Some(inline_builder) = inline_builder {
let constructor = || {
ArcRefCell::new(AbsolutelyPositionedBox::construct(
self.context,
info,
display_inside,
contents,
))
};
let old_layout_box = box_slot.take_layout_box_if_undamaged(info.damage);
let inline_level_box =
inline_builder.push_absolutely_positioned_box(constructor, old_layout_box);
box_slot.set(LayoutBox::InlineLevel(vec![inline_level_box]));
return;
}
let kind = BlockLevelCreator::OutOfFlowAbsolutelyPositionedBox {