aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/layout_2020/flow/float.rs95
1 files changed, 65 insertions, 30 deletions
diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs
index dce4350ce5c..382477860d9 100644
--- a/components/layout_2020/flow/float.rs
+++ b/components/layout_2020/flow/float.rs
@@ -82,6 +82,9 @@ pub(crate) struct PlacementAmongFloats<'a> {
next_band: FloatBand,
/// The size of the object to place.
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> {
@@ -100,35 +103,52 @@ impl<'a> PlacementAmongFloats<'a> {
current_bands,
next_band,
object_size,
+ ceiling,
}
}
- fn current_ceiling(&self) -> Length {
- self.current_bands.front().unwrap().top
+ /// The top of the bands under consideration. This is initially the ceiling provided
+ /// 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 {
- assert!(!self.current_bands.is_empty());
- self.next_band.top - self.current_ceiling()
+ if let Some(top) = self.top_of_bands() {
+ self.next_band.top - top
+ } else {
+ assert!(self.next_band.top.px().is_infinite());
+ self.next_band.top
+ }
+ }
+
+ /// Add a single band to the bands under consideration and calculate the new
+ /// [`PlacementAmongFloats::next_band`].
+ fn add_one_band(&mut self) {
+ assert!(!self.next_band.top.px().is_infinite());
+ self.current_bands.push_back(self.next_band);
+ self.next_band = self
+ .float_context
+ .bands
+ .find_next(self.next_band.top)
+ .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 {
- assert!(!self.next_band.top.px().is_infinite());
- self.current_bands.push_back(self.next_band);
- self.next_band = self
- .float_context
- .bands
- .find_next(self.next_band.top)
- .unwrap();
+ 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 min_inline_end = self.float_context.containing_block_info.inline_end;
- assert!(!self.current_bands.is_empty());
-
for band in self.current_bands.iter() {
if let Some(left) = band.left {
max_inline_start = max_inline_start.max(left);
@@ -140,22 +160,29 @@ impl<'a> PlacementAmongFloats<'a> {
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();
- let (inline_start, inline_end) = self.calculate_viable_inline_space();
- if self.object_size.inline > inline_end - inline_start {
+ let (inline_start, inline_end) = self.calculate_inline_start_and_end();
+ let available_inline_size = inline_end - inline_start;
+ if available_inline_size < self.object_size.inline {
return None;
}
- Some(Vec2 {
- inline: inline_start,
- block: self.current_ceiling(),
+ let top = self.top_of_bands().unwrap();
+ Some(Rect {
+ start_corner: Vec2 {
+ inline: inline_start,
+ block: top,
+ },
+ size: Vec2 {
+ inline: available_inline_size,
+ block: self.next_band.top - top,
+ },
})
}
/// Run the placement algorithm for this [PlacementAmongFloats].
- pub(crate) fn place(&mut self) -> Vec2<Length> {
- let ceiling = self.current_ceiling();
-
+ pub(crate) fn place(&mut self) -> Rect<Length> {
while !self.current_bands.is_empty() {
if let Some(result) = self.try_place_once() {
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
// cleared all floats.
- return Vec2 {
- inline: self.float_context.containing_block_info.inline_start,
- block: ceiling
- .max(self.float_context.clear_left_position)
- .max(self.float_context.clear_right_position),
- };
+ Rect {
+ start_corner: Vec2 {
+ inline: self.float_context.containing_block_info.inline_start,
+ block: self
+ .ceiling
+ .max(self.float_context.clear_left_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 =
clear_position.unwrap_or_else(|| self.position_without_clearance(&block_start_margin));
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 clearance = if has_clearance {
Some(position.block - self.position_with_zero_clearance(&block_start_margin))