Fix PlacementAmongFloats to avoid missing some bands (#30280)

PlacementAmongFloats would stop iterating when current_bands would be
empty, even if next_band wasn't at infinity.

Then the BFC root or replaced block was placed after all the floats,
even if it could fit next to some of them.

This patch moves the next_band into current_bands so that the loop
keeps considering bands.
This commit is contained in:
Oriol Brufau 2023-09-01 22:18:19 +02:00 committed by GitHub
parent efa8433548
commit a4fdbc30ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 4 deletions

View file

@ -200,14 +200,29 @@ impl<'a> PlacementAmongFloats<'a> {
})
}
/// Checks if we either have bands or we have gone past all of them.
/// This is an invariant that should hold, otherwise we are in a broken state.
fn has_bands_or_at_end(&self) -> bool {
!self.current_bands.is_empty() || self.next_band.top.px().is_infinite()
}
fn pop_front_band_ensuring_has_bands_or_at_end(&mut self) {
self.current_bands.pop_front();
if !self.has_bands_or_at_end() {
self.add_one_band();
}
}
/// Run the placement algorithm for this [PlacementAmongFloats].
pub(crate) fn place(&mut self) -> Rect<Length> {
debug_assert!(self.has_bands_or_at_end());
while !self.current_bands.is_empty() {
if let Some(result) = self.try_place_once() {
return result;
}
self.current_bands.pop_front();
self.pop_front_band_ensuring_has_bands_or_at_end();
}
debug_assert!(self.has_bands_or_at_end());
// We could not fit the object in among the floats, so we place it as if it
// cleared all floats.
@ -237,6 +252,7 @@ impl<'a> PlacementAmongFloats<'a> {
block_size_after_layout: Length,
size_from_placement: &Vec2<Length>,
) -> bool {
debug_assert!(self.has_bands_or_at_end());
debug_assert_eq!(size_from_placement.block, self.current_bands_height());
debug_assert_eq!(
size_from_placement.inline,
@ -268,7 +284,7 @@ impl<'a> PlacementAmongFloats<'a> {
if available_inline_size < self.object_size.inline {
self.next_band = self.current_bands[old_num_bands];
self.current_bands.truncate(old_num_bands);
self.current_bands.pop_front();
self.pop_front_band_ensuring_has_bands_or_at_end();
}
return false;
}

View file

@ -0,0 +1,2 @@
[floats-wrap-bfc-008.html]
expected: FAIL

View file

@ -61829,6 +61829,19 @@
{}
]
],
"floats-wrap-bfc-008.html": [
"5da80756d5f00f19afca1c05af462cac3af62a67",
[
null,
[
[
"/css/CSS2/reference/ref-filled-green-100px-square.xht",
"=="
]
],
{}
]
],
"floats-wrap-bfc-outside-001.xht": [
"5ba6a9750e7bafcb0a1fa1e5e420f337943a232a",
[

View file

@ -1,2 +0,0 @@
[c414-flt-fit-001.xht]
expected: FAIL

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<title>CSS Test: BFC root after 2 floats</title>
<link rel="author" title="Oriol Brufau" href="obrufau@igalia.com">
<link rel="help" href="https://drafts.csswg.org/css2/#floats">
<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
<meta name="assert" content="
The BFC root doesn't fit next to the 1st float, but fits next to the 2nd one,
so it should be placed next to the 2nd one.">
<style>
.wrapper {
width: 100px;
}
.float {
float: left;
height: 50px;
background: green;
}
.bfc {
overflow: hidden;
width: 50px;
height: 50px;
background: green;
}
</style>
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
<div class="wrapper">
<div class="float" style="width: 100px"></div>
<div class="float" style="width: 50px"></div>
<div class="bfc" style=""></div>
</div>