mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
Refactor PlacementAmongFloats (#30068)
- Add explanatory comments. - Rename some methods. - Store the ceiling instead of relying on the first band, this allows calling place() when current_bands is empty. - Make current_bands_height() work when current_bands is empty. - Add add_one_band() helper method. - Make place() return a Rect. Follow-up patches will need to know the size of the area shrunk by floats. This will be useful for #30057 and #30050. Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
51fa6c7e18
commit
66e0d543cf
1 changed files with 65 additions and 30 deletions
|
@ -82,6 +82,9 @@ pub(crate) struct PlacementAmongFloats<'a> {
|
||||||
next_band: FloatBand,
|
next_band: FloatBand,
|
||||||
/// The size of the object to place.
|
/// The size of the object to place.
|
||||||
object_size: Vec2<Length>,
|
object_size: Vec2<Length>,
|
||||||
|
/// The minimum position in the block direction for the placement. Objects should not
|
||||||
|
/// be placed before this point.
|
||||||
|
ceiling: Length,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PlacementAmongFloats<'a> {
|
impl<'a> PlacementAmongFloats<'a> {
|
||||||
|
@ -100,20 +103,30 @@ impl<'a> PlacementAmongFloats<'a> {
|
||||||
current_bands,
|
current_bands,
|
||||||
next_band,
|
next_band,
|
||||||
object_size,
|
object_size,
|
||||||
|
ceiling,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_ceiling(&self) -> Length {
|
/// The top of the bands under consideration. This is initially the ceiling provided
|
||||||
self.current_bands.front().unwrap().top
|
/// during creation of this [`PlacementAmongFloats`], but may be larger if the top
|
||||||
|
/// band is discarded.
|
||||||
|
fn top_of_bands(&self) -> Option<Length> {
|
||||||
|
self.current_bands.front().map(|band| band.top)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The height of the bands under consideration.
|
||||||
fn current_bands_height(&self) -> Length {
|
fn current_bands_height(&self) -> Length {
|
||||||
assert!(!self.current_bands.is_empty());
|
if let Some(top) = self.top_of_bands() {
|
||||||
self.next_band.top - self.current_ceiling()
|
self.next_band.top - top
|
||||||
|
} else {
|
||||||
|
assert!(self.next_band.top.px().is_infinite());
|
||||||
|
self.next_band.top
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accumulate_enough_bands_for_block_size(&mut self) {
|
/// Add a single band to the bands under consideration and calculate the new
|
||||||
while self.current_bands_height() < self.object_size.block {
|
/// [`PlacementAmongFloats::next_band`].
|
||||||
|
fn add_one_band(&mut self) {
|
||||||
assert!(!self.next_band.top.px().is_infinite());
|
assert!(!self.next_band.top.px().is_infinite());
|
||||||
self.current_bands.push_back(self.next_band);
|
self.current_bands.push_back(self.next_band);
|
||||||
self.next_band = self
|
self.next_band = self
|
||||||
|
@ -122,13 +135,20 @@ impl<'a> PlacementAmongFloats<'a> {
|
||||||
.find_next(self.next_band.top)
|
.find_next(self.next_band.top)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds bands to the set of bands under consideration until their block size is at
|
||||||
|
/// least large enough to contain the block size of the object being placed.
|
||||||
|
fn accumulate_enough_bands_for_block_size(&mut self) {
|
||||||
|
while self.current_bands_height() < self.object_size.block {
|
||||||
|
self.add_one_band();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_viable_inline_space(&self) -> (Length, Length) {
|
/// Find the start and end of the inline space provided by the current set of bands
|
||||||
|
/// under consideration.
|
||||||
|
fn calculate_inline_start_and_end(&self) -> (Length, Length) {
|
||||||
let mut max_inline_start = self.float_context.containing_block_info.inline_start;
|
let mut max_inline_start = self.float_context.containing_block_info.inline_start;
|
||||||
let mut min_inline_end = self.float_context.containing_block_info.inline_end;
|
let mut min_inline_end = self.float_context.containing_block_info.inline_end;
|
||||||
assert!(!self.current_bands.is_empty());
|
|
||||||
|
|
||||||
for band in self.current_bands.iter() {
|
for band in self.current_bands.iter() {
|
||||||
if let Some(left) = band.left {
|
if let Some(left) = band.left {
|
||||||
max_inline_start = max_inline_start.max(left);
|
max_inline_start = max_inline_start.max(left);
|
||||||
|
@ -140,22 +160,29 @@ impl<'a> PlacementAmongFloats<'a> {
|
||||||
return (max_inline_start, min_inline_end);
|
return (max_inline_start, min_inline_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn try_place_once(&mut self) -> Option<Vec2<Length>> {
|
fn try_place_once(&mut self) -> Option<Rect<Length>> {
|
||||||
|
assert!(!self.current_bands.is_empty());
|
||||||
self.accumulate_enough_bands_for_block_size();
|
self.accumulate_enough_bands_for_block_size();
|
||||||
let (inline_start, inline_end) = self.calculate_viable_inline_space();
|
let (inline_start, inline_end) = self.calculate_inline_start_and_end();
|
||||||
if self.object_size.inline > inline_end - inline_start {
|
let available_inline_size = inline_end - inline_start;
|
||||||
|
if available_inline_size < self.object_size.inline {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(Vec2 {
|
let top = self.top_of_bands().unwrap();
|
||||||
|
Some(Rect {
|
||||||
|
start_corner: Vec2 {
|
||||||
inline: inline_start,
|
inline: inline_start,
|
||||||
block: self.current_ceiling(),
|
block: top,
|
||||||
|
},
|
||||||
|
size: Vec2 {
|
||||||
|
inline: available_inline_size,
|
||||||
|
block: self.next_band.top - top,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the placement algorithm for this [PlacementAmongFloats].
|
/// Run the placement algorithm for this [PlacementAmongFloats].
|
||||||
pub(crate) fn place(&mut self) -> Vec2<Length> {
|
pub(crate) fn place(&mut self) -> Rect<Length> {
|
||||||
let ceiling = self.current_ceiling();
|
|
||||||
|
|
||||||
while !self.current_bands.is_empty() {
|
while !self.current_bands.is_empty() {
|
||||||
if let Some(result) = self.try_place_once() {
|
if let Some(result) = self.try_place_once() {
|
||||||
return result;
|
return result;
|
||||||
|
@ -165,12 +192,20 @@ impl<'a> PlacementAmongFloats<'a> {
|
||||||
|
|
||||||
// We could not fit the object in among the floats, so we place it as if it
|
// We could not fit the object in among the floats, so we place it as if it
|
||||||
// cleared all floats.
|
// cleared all floats.
|
||||||
return Vec2 {
|
Rect {
|
||||||
|
start_corner: Vec2 {
|
||||||
inline: self.float_context.containing_block_info.inline_start,
|
inline: self.float_context.containing_block_info.inline_start,
|
||||||
block: ceiling
|
block: self
|
||||||
|
.ceiling
|
||||||
.max(self.float_context.clear_left_position)
|
.max(self.float_context.clear_left_position)
|
||||||
.max(self.float_context.clear_right_position),
|
.max(self.float_context.clear_right_position),
|
||||||
};
|
},
|
||||||
|
size: Vec2 {
|
||||||
|
inline: self.float_context.containing_block_info.inline_end -
|
||||||
|
self.float_context.containing_block_info.inline_start,
|
||||||
|
block: Length::new(f32::INFINITY),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -989,7 +1024,7 @@ impl SequentialLayoutState {
|
||||||
let ceiling =
|
let ceiling =
|
||||||
clear_position.unwrap_or_else(|| self.position_without_clearance(&block_start_margin));
|
clear_position.unwrap_or_else(|| self.position_without_clearance(&block_start_margin));
|
||||||
let mut placement = PlacementAmongFloats::new(&self.floats, ceiling, object_size);
|
let mut placement = PlacementAmongFloats::new(&self.floats, ceiling, object_size);
|
||||||
let position = placement.place();
|
let position = placement.place().start_corner;
|
||||||
let has_clearance = clear_position.is_some() || position.block > ceiling;
|
let has_clearance = clear_position.is_some() || position.block > ceiling;
|
||||||
let clearance = if has_clearance {
|
let clearance = if has_clearance {
|
||||||
Some(position.block - self.position_with_zero_clearance(&block_start_margin))
|
Some(position.block - self.position_with_zero_clearance(&block_start_margin))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue