diff options
author | bors-servo <infra@servo.org> | 2023-06-19 16:56:16 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-19 16:56:16 +0200 |
commit | 836ae5fa48b7cb60dd801e6cd20becc1d839e8f5 (patch) | |
tree | aff1c4c315820eff7d29f5900623cc67173d4503 | |
parent | ffccc5c88b8d47efc777b0bc9d2620bed4bc84d7 (diff) | |
parent | 4ec6dd17836493aa479ea6ff887cd628bd1711e3 (diff) | |
download | servo-836ae5fa48b7cb60dd801e6cd20becc1d839e8f5.tar.gz servo-836ae5fa48b7cb60dd801e6cd20becc1d839e8f5.zip |
Auto merge of #29887 - Loirooriol:float-inline-size-complete, r=mrobinson
Handle floats in BlockContainer::inline_content_sizes
Typically, block-level contents are stacked vertically, so this was just taking the maximum size among all contents. However, floats can be stacked horizontally, so we need to sum their sizes.
<!-- Please describe your changes on the following line: -->
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #29874
<!-- Either: -->
- [X] There are tests for these changes OR
- [ ] These changes do not require tests because ___
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
-rw-r--r-- | components/layout_2020/flow/float.rs | 7 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 115 | ||||
-rw-r--r-- | components/layout_2020/sizing.rs | 9 | ||||
-rw-r--r-- | tests/wpt/metadata-layout-2020/css/css-flexbox/flex-basis-intrinsics-001.html.ini | 9 |
4 files changed, 112 insertions, 28 deletions
diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 9a52b50853d..5750ed6039d 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -690,12 +690,7 @@ impl FloatBox { .floats .lower_ceiling(sequential_layout_state.current_block_position_including_margins()); - let style = match self.contents { - IndependentFormattingContext::Replaced(ref replaced) => replaced.style.clone(), - IndependentFormattingContext::NonReplaced(ref non_replaced) => { - non_replaced.style.clone() - }, - }; + let style = self.contents.style().clone(); let float_context = &mut sequential_layout_state.floats; let box_fragment = positioning_context.layout_maybe_position_relative_fragment( layout_context, diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 5837e836d88..94b1727b15a 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -25,6 +25,8 @@ use crate::ContainingBlock; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; +use style::computed_values::clear::T as Clear; +use style::computed_values::float::T as Float; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; use style::values::computed::{Length, LengthOrAuto}; @@ -107,6 +109,99 @@ impl BlockFormattingContext { } } +/// Finds the min/max-content inline size of the block-level children of a block container. +/// The in-flow boxes will stack vertically, so we only need to consider the maximum size. +/// But floats can flow horizontally depending on 'clear', so we may need to sum their sizes. +/// CSS 2 does not define the exact algorithm, this logic is based on the behavior observed +/// on Gecko and Blink. +fn calculate_inline_content_size_for_block_level_boxes( + boxes: &[ArcRefCell<BlockLevelBox>], + layout_context: &LayoutContext, + writing_mode: WritingMode, +) -> ContentSizes { + let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| { + let size = box_ + .borrow_mut() + .inline_content_sizes(layout_context, writing_mode); + if let BlockLevelBox::OutOfFlowFloatBox(ref float_box) = *box_.borrow_mut() { + let style_box = &float_box.contents.style().get_box(); + (size, style_box.float, style_box.clear) + } else { + // The element may in fact have clearance, but the logic below ignores it, + // so don't bother retrieving it from the style. + (size, Float::None, Clear::None) + } + }; + + /// When iterating the block-level boxes to compute the inline content sizes, + /// this struct contains the data accumulated up to the current box. + struct AccumulatedData { + /// The maximum size seen so far, not including trailing uncleared floats. + max_size: ContentSizes, + /// The size of the trailing uncleared floats with 'float: left'. + left_floats: ContentSizes, + /// The size of the trailing uncleared floats with 'float: right'. + right_floats: ContentSizes, + } + + impl AccumulatedData { + fn max_size_including_uncleared_floats(&self) -> ContentSizes { + self.max_size.max(self.left_floats.add(&self.right_floats)) + } + fn clear_floats(&mut self, clear: Clear) { + match clear { + Clear::Left => { + self.max_size = self.max_size_including_uncleared_floats(); + self.left_floats = ContentSizes::zero(); + }, + Clear::Right => { + self.max_size = self.max_size_including_uncleared_floats(); + self.right_floats = ContentSizes::zero(); + }, + Clear::Both => { + self.max_size = self.max_size_including_uncleared_floats(); + self.left_floats = ContentSizes::zero(); + self.right_floats = ContentSizes::zero(); + }, + Clear::None => {}, + }; + } + } + + let accumulate = |mut data: AccumulatedData, (size, float, clear)| { + if float == Float::None { + // TODO: The first BFC root after a sequence of floats should appear next to them + // (if it doesn't have clearance). + data.clear_floats(Clear::Both); + data.max_size = data.max_size.max(size); + } else { + data.clear_floats(clear); + match float { + Float::Left => data.left_floats = data.left_floats.add(&size), + Float::Right => data.right_floats = data.right_floats.add(&size), + Float::None => unreachable!(), + } + } + data + }; + let zero = AccumulatedData { + max_size: ContentSizes::zero(), + left_floats: ContentSizes::zero(), + right_floats: ContentSizes::zero(), + }; + let data = if layout_context.use_rayon { + boxes + .par_iter() + .map(get_box_info) + .collect::<Vec<_>>() + .into_iter() + .fold(zero, accumulate) + } else { + boxes.iter().map(get_box_info).fold(zero, accumulate) + }; + data.max_size_including_uncleared_floats() +} + impl BlockContainer { fn layout( &self, @@ -143,21 +238,11 @@ impl BlockContainer { writing_mode: WritingMode, ) -> ContentSizes { match &self { - Self::BlockLevelBoxes(boxes) if layout_context.use_rayon => boxes - .par_iter() - .map(|box_| { - box_.borrow_mut() - .inline_content_sizes(layout_context, writing_mode) - }) - .reduce(ContentSizes::zero, ContentSizes::max), - Self::BlockLevelBoxes(boxes) => boxes - .iter() - .map(|box_| { - box_.borrow_mut() - .inline_content_sizes(layout_context, writing_mode) - }) - .reduce(ContentSizes::max) - .unwrap_or_else(ContentSizes::zero), + Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes( + boxes, + layout_context, + writing_mode, + ), Self::InlineFormattingContext(context) => { context.inline_content_sizes(layout_context, writing_mode) }, diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index ccf60ceb933..31e96341132 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -33,13 +33,20 @@ impl ContentSizes { } } - pub fn max(self, other: Self) -> Self { + pub fn max(&self, other: Self) -> Self { Self { min_content: self.min_content.max(other.min_content), max_content: self.max_content.max(other.max_content), } } + pub fn add(&self, other: &Self) -> Self { + Self { + min_content: self.min_content.max(other.min_content), + max_content: self.max_content + other.max_content, + } + } + /// Relevant to outer intrinsic inline sizes, for percentages from padding and margin. pub fn adjust_for_pbm_percentages(&mut self, percentages: Percentage) { // " Note that this may yield an infinite result, but undefined results diff --git a/tests/wpt/metadata-layout-2020/css/css-flexbox/flex-basis-intrinsics-001.html.ini b/tests/wpt/metadata-layout-2020/css/css-flexbox/flex-basis-intrinsics-001.html.ini index c35db30bab8..c7592731081 100644 --- a/tests/wpt/metadata-layout-2020/css/css-flexbox/flex-basis-intrinsics-001.html.ini +++ b/tests/wpt/metadata-layout-2020/css/css-flexbox/flex-basis-intrinsics-001.html.ini @@ -1,4 +1,7 @@ [flex-basis-intrinsics-001.html] + [.flex-item 1] + expected: FAIL + [.flex-item 2] expected: FAIL @@ -20,11 +23,5 @@ [.flex-item 6] expected: FAIL - [.flex-item 7] - expected: FAIL - - [.flex-item 9] - expected: FAIL - [.flex-item 11] expected: FAIL |