mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
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. -->
This commit is contained in:
commit
836ae5fa48
4 changed files with 112 additions and 28 deletions
|
@ -690,12 +690,7 @@ impl FloatBox {
|
||||||
.floats
|
.floats
|
||||||
.lower_ceiling(sequential_layout_state.current_block_position_including_margins());
|
.lower_ceiling(sequential_layout_state.current_block_position_including_margins());
|
||||||
|
|
||||||
let style = match self.contents {
|
let style = self.contents.style().clone();
|
||||||
IndependentFormattingContext::Replaced(ref replaced) => replaced.style.clone(),
|
|
||||||
IndependentFormattingContext::NonReplaced(ref non_replaced) => {
|
|
||||||
non_replaced.style.clone()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let float_context = &mut sequential_layout_state.floats;
|
let float_context = &mut sequential_layout_state.floats;
|
||||||
let box_fragment = positioning_context.layout_maybe_position_relative_fragment(
|
let box_fragment = positioning_context.layout_maybe_position_relative_fragment(
|
||||||
layout_context,
|
layout_context,
|
||||||
|
|
|
@ -25,6 +25,8 @@ use crate::ContainingBlock;
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||||
use rayon_croissant::ParallelIteratorExt;
|
use rayon_croissant::ParallelIteratorExt;
|
||||||
use servo_arc::Arc;
|
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::logical_geometry::WritingMode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::{Length, LengthOrAuto};
|
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 {
|
impl BlockContainer {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
|
@ -143,21 +238,11 @@ impl BlockContainer {
|
||||||
writing_mode: WritingMode,
|
writing_mode: WritingMode,
|
||||||
) -> ContentSizes {
|
) -> ContentSizes {
|
||||||
match &self {
|
match &self {
|
||||||
Self::BlockLevelBoxes(boxes) if layout_context.use_rayon => boxes
|
Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes(
|
||||||
.par_iter()
|
boxes,
|
||||||
.map(|box_| {
|
layout_context,
|
||||||
box_.borrow_mut()
|
writing_mode,
|
||||||
.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::InlineFormattingContext(context) => {
|
Self::InlineFormattingContext(context) => {
|
||||||
context.inline_content_sizes(layout_context, writing_mode)
|
context.inline_content_sizes(layout_context, writing_mode)
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,13 +33,20 @@ impl ContentSizes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max(self, other: Self) -> Self {
|
pub fn max(&self, other: Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
min_content: self.min_content.max(other.min_content),
|
min_content: self.min_content.max(other.min_content),
|
||||||
max_content: self.max_content.max(other.max_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.
|
/// Relevant to outer intrinsic inline sizes, for percentages from padding and margin.
|
||||||
pub fn adjust_for_pbm_percentages(&mut self, percentages: Percentage) {
|
pub fn adjust_for_pbm_percentages(&mut self, percentages: Percentage) {
|
||||||
// " Note that this may yield an infinite result, but undefined results
|
// " Note that this may yield an infinite result, but undefined results
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
[flex-basis-intrinsics-001.html]
|
[flex-basis-intrinsics-001.html]
|
||||||
|
[.flex-item 1]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
[.flex-item 2]
|
[.flex-item 2]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -20,11 +23,5 @@
|
||||||
[.flex-item 6]
|
[.flex-item 6]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[.flex-item 7]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[.flex-item 9]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[.flex-item 11]
|
[.flex-item 11]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue