From 0d4e4748c432e1ce1555e2f4ebb759c631038313 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Fri, 23 Feb 2024 18:55:18 +0100 Subject: [PATCH] layout: Place absolutes in IFCs at their hypothetical static position (#31418) Absolutes need to be placed at their hypothetical position as if the position value was static. This position differs based on the value they had before blockification. The code for placing absolutes was taking into account the original display for the inline value, but not for the block value. A static `display: block` box would placed at a new block position past the end of the linebox. --- components/layout_2020/dom_traversal.rs | 2 + components/layout_2020/flow/line.rs | 52 ++++++++++--------- components/layout_2020/style_ext.rs | 6 +-- .../abspos/between-float-and-text.html.ini | 2 - .../css/CSS2/positioning/abspos-007.xht.ini | 2 - .../abspos-block-level-001.html.ini | 2 - .../abspos-negative-margin-001.html.ini | 2 - ...te-dynamic-static-position-inline.html.ini | 2 - ...-scale-gradient-bg-obscure-red-bg.html.ini | 2 - 9 files changed, 32 insertions(+), 40 deletions(-) delete mode 100644 tests/wpt/meta/css/CSS2/abspos/between-float-and-text.html.ini delete mode 100644 tests/wpt/meta/css/CSS2/positioning/abspos-007.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/positioning/abspos-block-level-001.html.ini delete mode 100644 tests/wpt/meta/css/CSS2/positioning/abspos-negative-margin-001.html.ini delete mode 100644 tests/wpt/meta/css/css-position/position-absolute-dynamic-static-position-inline.html.ini delete mode 100644 tests/wpt/meta/css/css-transforms/fractional-scale-gradient-bg-obscure-red-bg.html.ini diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index f9b83a2b4cc..c4da1333a1c 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -89,6 +89,7 @@ where } } +#[derive(Debug)] pub(super) enum Contents { /// Refers to a DOM subtree, plus `::before` and `::after` pseudo-elements. OfElement, @@ -107,6 +108,7 @@ pub(super) enum NonReplacedContents { OfPseudoElement(Vec), } +#[derive(Debug)] pub(super) enum PseudoElementContentItem { Text(String), Replaced(ReplacedContent), diff --git a/components/layout_2020/flow/line.rs b/components/layout_2020/flow/line.rs index cf384422673..dce1d304fa9 100644 --- a/components/layout_2020/flow/line.rs +++ b/components/layout_2020/flow/line.rs @@ -13,6 +13,7 @@ use style::properties::ComputedValues; use style::values::computed::{Length, LengthPercentage}; use style::values::generics::box_::{GenericVerticalAlign, VerticalAlignKeyword}; use style::values::generics::text::LineHeight; +use style::values::specified::box_::DisplayOutside; use style::values::specified::text::TextDecorationLine; use style::Zero; use webrender_api::FontInstanceKey; @@ -27,9 +28,7 @@ use crate::geom::{LogicalRect, LogicalVec2}; use crate::positioned::{ relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, }; -use crate::style_ext::{ - ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside, PaddingBorderMargin, -}; +use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; use crate::ContainingBlock; pub(super) struct LineMetrics { @@ -523,31 +522,34 @@ impl AbsolutelyPositionedLineItem { fn layout(self, state: &mut LineItemLayoutState) -> ArcRefCell { let box_ = self.absolutely_positioned_box; let style = AtomicRef::map(box_.borrow(), |box_| box_.context.style()); - let initial_start_corner = match Display::from(style.get_box().original_display) { - Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { outside, inside: _ }) => { + + // From https://drafts.csswg.org/css2/#abs-non-replaced-width + // > The static-position containing block is the containing block of a + // > hypothetical box that would have been the first box of the element if its + // > specified position value had been static and its specified float had been + // > none. (Note that due to the rules in section 9.7 this hypothetical + // > calculation might require also assuming a different computed value for + // > display.) + // + // This box is different based on the original `display` value of the + // absolutely positioned element. If it's `inline` it would be placed inline + // at the top of the line, but if it's block it would be placed in a new + // block position after the linebox established by this line. + let initial_start_corner = + if style.get_box().original_display.outside() == DisplayOutside::Inline { + // Top of the line at the current inline position. LogicalVec2 { - inline: match outside { - DisplayOutside::Inline => { - state.inline_position - state.parent_offset.inline - }, - DisplayOutside::Block => Length::zero(), - }, - // The blocks start position of the absolute should be at the top of the line. + inline: state.inline_position - state.parent_offset.inline, block: -state.parent_offset.block, } - }, - Display::GeneratingBox(DisplayGeneratingBox::LayoutInternal(_)) => { - unreachable!( - "The result of blockification should never be a layout-internal value." - ); - }, - Display::Contents => { - panic!("display:contents does not generate an abspos box") - }, - Display::None => { - panic!("display:none does not generate an abspos box") - }, - }; + } else { + // After the bottom of the line at the start of the inline formatting context. + LogicalVec2 { + inline: Length::zero(), + block: state.line_metrics.block_size - state.parent_offset.block, + } + }; + let hoisted_box = AbsolutelyPositionedBox::to_hoisted( box_.clone(), initial_start_corner, diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index 1b0adc305ec..b4d0428a5a8 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -34,7 +34,7 @@ pub(crate) enum Display { GeneratingBox(DisplayGeneratingBox), } -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum DisplayGeneratingBox { OutsideInside { outside: DisplayOutside, @@ -72,13 +72,13 @@ impl DisplayGeneratingBox { } } -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum DisplayOutside { Block, Inline, } -#[derive(Clone, Copy, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum DisplayInside { // “list-items are limited to the Flow Layout display types” // diff --git a/tests/wpt/meta/css/CSS2/abspos/between-float-and-text.html.ini b/tests/wpt/meta/css/CSS2/abspos/between-float-and-text.html.ini deleted file mode 100644 index 07973158f98..00000000000 --- a/tests/wpt/meta/css/CSS2/abspos/between-float-and-text.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[between-float-and-text.html] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/positioning/abspos-007.xht.ini b/tests/wpt/meta/css/CSS2/positioning/abspos-007.xht.ini deleted file mode 100644 index b33a02aa958..00000000000 --- a/tests/wpt/meta/css/CSS2/positioning/abspos-007.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[abspos-007.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/positioning/abspos-block-level-001.html.ini b/tests/wpt/meta/css/CSS2/positioning/abspos-block-level-001.html.ini deleted file mode 100644 index 288e23b6065..00000000000 --- a/tests/wpt/meta/css/CSS2/positioning/abspos-block-level-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[abspos-block-level-001.html] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/positioning/abspos-negative-margin-001.html.ini b/tests/wpt/meta/css/CSS2/positioning/abspos-negative-margin-001.html.ini deleted file mode 100644 index 073aef19466..00000000000 --- a/tests/wpt/meta/css/CSS2/positioning/abspos-negative-margin-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[abspos-negative-margin-001.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-position/position-absolute-dynamic-static-position-inline.html.ini b/tests/wpt/meta/css/css-position/position-absolute-dynamic-static-position-inline.html.ini deleted file mode 100644 index 9af7d1ca213..00000000000 --- a/tests/wpt/meta/css/css-position/position-absolute-dynamic-static-position-inline.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[position-absolute-dynamic-static-position-inline.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-transforms/fractional-scale-gradient-bg-obscure-red-bg.html.ini b/tests/wpt/meta/css/css-transforms/fractional-scale-gradient-bg-obscure-red-bg.html.ini deleted file mode 100644 index c81e8f465a3..00000000000 --- a/tests/wpt/meta/css/css-transforms/fractional-scale-gradient-bg-obscure-red-bg.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[fractional-scale-gradient-bg-obscure-red-bg.html] - expected: FAIL