From 2c341d9e69f75919d9ddb252ccffe9e6ca381e8a Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Tue, 17 Oct 2023 09:53:57 +0200 Subject: [PATCH] Allow raising FloatContext ceiling after processing box with overflow (#30539) When a box has overflow, any floats placed in that box will lower the float ceiling into the overflow. If no float is placed in the box though, the ceiling should be the block position where the overflow starts. We already know where this is, because we might be passing a negative value for the new block position after processing a box (content_size - actual_size would be negative). This negative value never raises the ceiling though since a maximum is used. In the case that there is overflow, this change allows raising the ceiling, but never passed the lowest float. This necessitates keeping two values for the ceiling: one for floats and one for non-floats. Fixes #30304. --- components/layout_2020/flow/float.rs | 39 +++++++++++++------ components/layout_2020/flow/mod.rs | 6 +++ components/layout_2020/tests/floats.rs | 2 +- .../margin-collapse-104.xht.ini | 2 - .../meta/css/CSS2/zorder/z-index-020.xht.ini | 2 - .../elementsFromPoint-simple.html.ini | 9 ----- 6 files changed, 35 insertions(+), 25 deletions(-) delete mode 100644 tests/wpt/meta/css/CSS2/margin-padding-clear/margin-collapse-104.xht.ini delete mode 100644 tests/wpt/meta/css/CSS2/zorder/z-index-020.xht.ini diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 218833f4634..9253e856ce6 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -307,9 +307,13 @@ pub struct FloatContext { /// This tree is immutable; modification operations return the new tree, which may share nodes /// with previous versions of the tree. pub bands: FloatBandTree, - /// The current (logically) vertical position. No new floats may be placed (logically) above - /// this line. - pub ceiling: Length, + /// The block-direction "ceiling" defined by the placement of other floated content of + /// this FloatContext. No new floats can be placed at a lower block start than this value. + pub ceiling_from_floats: Length, + /// The block-direction "ceiling" defined by the placement of non-floated content that + /// precedes floated content in the document. Note that this may actually decrease as + /// content is laid out in the case that content overflows its container. + pub ceiling_from_non_floats: Length, /// Details about the position of the containing block relative to the /// independent block formatting context that contains all of the floats /// this `FloatContext` positions. @@ -337,7 +341,8 @@ impl FloatContext { }); FloatContext { bands, - ceiling: Length::zero(), + ceiling_from_floats: Length::zero(), + ceiling_from_non_floats: Length::zero(), containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets( Length::zero(), max_inline_size, @@ -350,8 +355,14 @@ impl FloatContext { /// (Logically) lowers the ceiling to at least `new_ceiling` units. /// /// If the ceiling is already logically lower (i.e. larger) than this, does nothing. - pub fn lower_ceiling(&mut self, new_ceiling: Length) { - self.ceiling = self.ceiling.max(new_ceiling); + pub fn set_ceiling_from_non_floats(&mut self, new_ceiling: Length) { + self.ceiling_from_non_floats = new_ceiling; + } + + /// The "ceiling" used for float placement. This is the minimum block position value + /// that should be used for placing any new float. + fn ceiling(&mut self) -> Length { + self.ceiling_from_floats.max(self.ceiling_from_non_floats) } /// Determines where a float with the given placement would go, but leaves the float context @@ -411,7 +422,8 @@ impl FloatContext { /// Places a new float and adds it to the list. Returns the start corner of its margin box. pub fn add_float(&mut self, new_float: &PlacementInfo) -> LogicalVec2 { // Place the float. - let new_float_origin = self.place_object(&new_float, self.ceiling); + let ceiling = self.ceiling(); + let new_float_origin = self.place_object(&new_float, ceiling); let new_float_extent = match new_float.side { FloatSide::Left => new_float_origin.inline + new_float.size.inline, FloatSide::Right => new_float_origin.inline, @@ -464,7 +476,8 @@ impl FloatContext { // CSS 2.1 ยง 9.5.1 rule 6: The outer top of a floating box may not be higher than the outer // top of any block or floated box generated by an element earlier in the source document. - self.ceiling = self.ceiling.max(new_float_rect.start_corner.block); + self.ceiling_from_floats + .max_assign(new_float_rect.start_corner.block); new_float_rect.start_corner } } @@ -994,12 +1007,16 @@ impl SequentialLayoutState { } } - /// Moves the current block position (logically) down by `block_distance`. + /// Moves the current block position (logically) down by `block_distance`. This may be + /// a negative advancement in the case that that block content overflows its + /// container, when the container is adjusting the block position of the + /// [`SequentialLayoutState`] after processing its overflowing content. /// /// Floats may not be placed higher than the current block position. pub(crate) fn advance_block_position(&mut self, block_distance: Length) { self.bfc_relative_block_position += block_distance; - self.floats.lower_ceiling(self.bfc_relative_block_position); + self.floats + .set_ceiling_from_non_floats(self.bfc_relative_block_position); } /// Replace the entire [ContainingBlockPositionInfo] data structure stored @@ -1161,7 +1178,7 @@ impl SequentialLayoutState { .adjoin(&margins_collapsing_with_parent_containing_block) .solve(); - self.floats.lower_ceiling( + self.floats.set_ceiling_from_non_floats( block_start_of_containing_block_in_bfc + block_offset_from_containing_block_top, ); diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 85db59478f1..8b18bc5cdbd 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -761,6 +761,12 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context( // Account for padding and border. We also might have to readjust the // `bfc_relative_block_position` if it was different from the content size (i.e. was // non-`auto` and/or was affected by min/max block size). + // + // If this adjustment is positive, that means that a block size was specified, but + // the content inside had a smaller block size. If this adjustment is negative, a + // block size was specified, but the content inside overflowed this container in + // the block direction. In that case, the ceiling for floats is effectively raised + // as long as no floats in the overflowing content lowered it. sequential_layout_state.advance_block_position( (block_size - content_block_size) + pbm.padding.block_end + pbm.border.block_end, ); diff --git a/components/layout_2020/tests/floats.rs b/components/layout_2020/tests/floats.rs index 6226c774b44..b5187e7c4ef 100644 --- a/components/layout_2020/tests/floats.rs +++ b/components/layout_2020/tests/floats.rs @@ -467,7 +467,7 @@ impl FloatPlacement { let mut placed_floats = vec![]; for float in floats { let ceiling = Length::new(float.ceiling as f32); - float_context.lower_ceiling(ceiling); + float_context.set_ceiling_from_non_floats(ceiling); float_context.containing_block_info = float.containing_block_info; placed_floats.push(PlacedFloat { origin: float_context.add_float(&float.info), diff --git a/tests/wpt/meta/css/CSS2/margin-padding-clear/margin-collapse-104.xht.ini b/tests/wpt/meta/css/CSS2/margin-padding-clear/margin-collapse-104.xht.ini deleted file mode 100644 index 05240ac99c1..00000000000 --- a/tests/wpt/meta/css/CSS2/margin-padding-clear/margin-collapse-104.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[margin-collapse-104.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/CSS2/zorder/z-index-020.xht.ini b/tests/wpt/meta/css/CSS2/zorder/z-index-020.xht.ini deleted file mode 100644 index e896f829816..00000000000 --- a/tests/wpt/meta/css/CSS2/zorder/z-index-020.xht.ini +++ /dev/null @@ -1,2 +0,0 @@ -[z-index-020.xht] - expected: FAIL diff --git a/tests/wpt/meta/css/cssom-view/elementsFromPoint-simple.html.ini b/tests/wpt/meta/css/cssom-view/elementsFromPoint-simple.html.ini index a4b894bcee4..5334b943293 100644 --- a/tests/wpt/meta/css/cssom-view/elementsFromPoint-simple.html.ini +++ b/tests/wpt/meta/css/cssom-view/elementsFromPoint-simple.html.ini @@ -1,12 +1,3 @@ [elementsFromPoint-simple.html] - [elementsFromPoint for each corner of a simple div] - expected: FAIL - - [elementsFromPoint for each corner of a div that is between another div and its pseudo-element] - expected: FAIL - - [elementsFromPoint for each corner of a div that has a margin] - expected: FAIL - [elementsFromPoint for each corner of a div with a 3d transform] expected: FAIL