aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <infra@servo.org>2023-06-19 16:56:16 +0200
committerGitHub <noreply@github.com>2023-06-19 16:56:16 +0200
commit836ae5fa48b7cb60dd801e6cd20becc1d839e8f5 (patch)
treeaff1c4c315820eff7d29f5900623cc67173d4503
parentffccc5c88b8d47efc777b0bc9d2620bed4bc84d7 (diff)
parent4ec6dd17836493aa479ea6ff887cd628bd1711e3 (diff)
downloadservo-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.rs7
-rw-r--r--components/layout_2020/flow/mod.rs115
-rw-r--r--components/layout_2020/sizing.rs9
-rw-r--r--tests/wpt/metadata-layout-2020/css/css-flexbox/flex-basis-intrinsics-001.html.ini9
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