diff options
Diffstat (limited to 'components/layout_2020/flow/float.rs')
-rw-r--r-- | components/layout_2020/flow/float.rs | 68 |
1 files changed, 65 insertions, 3 deletions
diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 382477860d9..45493ebd8f4 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -160,6 +160,12 @@ impl<'a> PlacementAmongFloats<'a> { return (max_inline_start, min_inline_end); } + /// Find the total inline size provided by the current set of bands under consideration. + fn calculate_viable_inline_size(&self) -> Length { + let (inline_start, inline_end) = self.calculate_inline_start_and_end(); + inline_end - inline_start + } + fn try_place_once(&mut self) -> Option<Rect<Length>> { assert!(!self.current_bands.is_empty()); self.accumulate_enough_bands_for_block_size(); @@ -207,6 +213,56 @@ impl<'a> PlacementAmongFloats<'a> { }, } } + + /// After placing an object with `height: auto` (and using the minimum inline and + /// block size as the object size) and then laying it out, try to fit the object into + /// the current set of bands, given block size after layout and the available inline + /// space from the original placement. This will return true if the object fits at the + /// original placement location or false if the placement and layout must be run again + /// (with this [PlacementAmongFloats]). + pub(crate) fn try_to_expand_for_auto_block_size( + &mut self, + block_size_after_layout: Length, + size_from_placement: &Vec2<Length>, + ) -> bool { + debug_assert_eq!(size_from_placement.block, self.current_bands_height()); + debug_assert_eq!( + size_from_placement.inline, + self.calculate_viable_inline_size() + ); + + // If the object after layout fits into the originally calculated placement, then + // it fits without any more work. + if block_size_after_layout <= size_from_placement.block { + return true; + } + + // Keep searching until we have found an area with enough height + // to contain the block after layout. + let old_num_bands = self.current_bands.len(); + assert!(old_num_bands > 0); + while self.current_bands_height() < block_size_after_layout { + self.add_one_band(); + + // If the new inline size is narrower, we must stop and run layout again. + // Normally, a narrower block size means a bigger height, but in some + // circumstances, such as when aspect ratio is used a narrower inline size + // can counter-interuitively lead to a smaller block size after layout! + let available_inline_size = self.calculate_viable_inline_size(); + if available_inline_size < size_from_placement.inline { + // If the inline size becomes smaller than the minimum inline size, then + // the current set of bands will never work and we must try removing the + // first and searching starting from the second. + 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(); + } + return false; + } + } + true + } } /// Data kept during layout about the floats in a given block formatting context. @@ -939,14 +995,20 @@ impl SequentialLayoutState { /// Computes the position of the block-start border edge of an element /// with the provided `block_start_margin`, assuming no clearance. - fn position_without_clearance(&self, block_start_margin: &CollapsedMargin) -> Length { + pub(crate) fn position_without_clearance( + &self, + block_start_margin: &CollapsedMargin, + ) -> Length { // Adjoin `current_margin` and `block_start_margin` since there is no clearance. self.bfc_relative_block_position + self.current_margin.adjoin(&block_start_margin).solve() } /// Computes the position of the block-start border edge of an element /// with the provided `block_start_margin`, assuming a clearance of 0px. - fn position_with_zero_clearance(&self, block_start_margin: &CollapsedMargin) -> Length { + pub(crate) fn position_with_zero_clearance( + &self, + block_start_margin: &CollapsedMargin, + ) -> Length { // Clearance prevents `current_margin` and `block_start_margin` from being // adjoining, so we need to solve them separately and then sum. self.bfc_relative_block_position + self.current_margin.solve() + block_start_margin.solve() @@ -954,7 +1016,7 @@ impl SequentialLayoutState { /// Returns the block-end outer edge of the lowest float that is to be cleared (if any) /// by an element with the provided `clear` and `block_start_margin`. - fn calculate_clear_position( + pub(crate) fn calculate_clear_position( &self, clear: Clear, block_start_margin: &CollapsedMargin, |