mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Switch flex layout to app units (#32599)
This commit is contained in:
parent
42e090a1eb
commit
a972e5c200
3 changed files with 193 additions and 193 deletions
|
@ -14,9 +14,7 @@ use style::properties::longhands::flex_direction::computed_value::T as FlexDirec
|
||||||
use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap;
|
use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap;
|
||||||
use style::properties::longhands::justify_content::computed_value::T as JustifyContent;
|
use style::properties::longhands::justify_content::computed_value::T as JustifyContent;
|
||||||
use style::values::computed::length::Size;
|
use style::values::computed::length::Size;
|
||||||
use style::values::computed::Length;
|
|
||||||
use style::values::generics::flex::GenericFlexBasis as FlexBasis;
|
use style::values::generics::flex::GenericFlexBasis as FlexBasis;
|
||||||
use style::values::CSSFloat;
|
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
|
|
||||||
use super::geom::{
|
use super::geom::{
|
||||||
|
@ -45,13 +43,13 @@ struct FlexContext<'a> {
|
||||||
positioning_context: &'a mut PositioningContext,
|
positioning_context: &'a mut PositioningContext,
|
||||||
containing_block: &'a ContainingBlock<'a>, // For items
|
containing_block: &'a ContainingBlock<'a>, // For items
|
||||||
container_is_single_line: bool,
|
container_is_single_line: bool,
|
||||||
container_min_cross_size: Length,
|
container_min_cross_size: Au,
|
||||||
container_max_cross_size: Option<Length>,
|
container_max_cross_size: Option<Au>,
|
||||||
flex_axis: FlexAxis,
|
flex_axis: FlexAxis,
|
||||||
flex_direction_is_reversed: bool,
|
flex_direction_is_reversed: bool,
|
||||||
flex_wrap_reverse: bool,
|
flex_wrap_reverse: bool,
|
||||||
main_start_cross_start_sides_are: MainStartCrossStart,
|
main_start_cross_start_sides_are: MainStartCrossStart,
|
||||||
container_definite_inner_size: FlexRelativeVec2<Option<Length>>,
|
container_definite_inner_size: FlexRelativeVec2<Option<Au>>,
|
||||||
align_content: AlignContent,
|
align_content: AlignContent,
|
||||||
align_items: AlignItems,
|
align_items: AlignItems,
|
||||||
justify_content: JustifyContent,
|
justify_content: JustifyContent,
|
||||||
|
@ -60,9 +58,9 @@ struct FlexContext<'a> {
|
||||||
/// A flex item with some intermediate results
|
/// A flex item with some intermediate results
|
||||||
struct FlexItem<'a> {
|
struct FlexItem<'a> {
|
||||||
box_: &'a mut IndependentFormattingContext,
|
box_: &'a mut IndependentFormattingContext,
|
||||||
content_box_size: FlexRelativeVec2<LengthOrAuto>,
|
content_box_size: FlexRelativeVec2<AuOrAuto>,
|
||||||
content_min_size: FlexRelativeVec2<Length>,
|
content_min_size: FlexRelativeVec2<Au>,
|
||||||
content_max_size: FlexRelativeVec2<Option<Length>>,
|
content_max_size: FlexRelativeVec2<Option<Au>>,
|
||||||
padding: FlexRelativeSides<Au>,
|
padding: FlexRelativeSides<Au>,
|
||||||
border: FlexRelativeSides<Au>,
|
border: FlexRelativeSides<Au>,
|
||||||
margin: FlexRelativeSides<AuOrAuto>,
|
margin: FlexRelativeSides<AuOrAuto>,
|
||||||
|
@ -72,10 +70,10 @@ struct FlexItem<'a> {
|
||||||
pbm_auto_is_zero: FlexRelativeVec2<Au>,
|
pbm_auto_is_zero: FlexRelativeVec2<Au>,
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-flexbox/#algo-main-item>
|
/// <https://drafts.csswg.org/css-flexbox/#algo-main-item>
|
||||||
flex_base_size: Length,
|
flex_base_size: Au,
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-flexbox/#algo-main-item>
|
/// <https://drafts.csswg.org/css-flexbox/#algo-main-item>
|
||||||
hypothetical_main_size: Length,
|
hypothetical_main_size: Au,
|
||||||
/// This is `align-self`, defaulting to `align-items` if `auto`
|
/// This is `align-self`, defaulting to `align-items` if `auto`
|
||||||
align_self: AlignItems,
|
align_self: AlignItems,
|
||||||
}
|
}
|
||||||
|
@ -90,19 +88,19 @@ enum FlexContent {
|
||||||
/// A flex line with some intermediate results
|
/// A flex line with some intermediate results
|
||||||
struct FlexLine<'a> {
|
struct FlexLine<'a> {
|
||||||
items: &'a mut [FlexItem<'a>],
|
items: &'a mut [FlexItem<'a>],
|
||||||
outer_hypothetical_main_sizes_sum: Length,
|
outer_hypothetical_main_sizes_sum: Au,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return type of `FlexItem::layout`
|
/// Return type of `FlexItem::layout`
|
||||||
struct FlexItemLayoutResult {
|
struct FlexItemLayoutResult {
|
||||||
hypothetical_cross_size: Length,
|
hypothetical_cross_size: Au,
|
||||||
fragments: Vec<Fragment>,
|
fragments: Vec<Fragment>,
|
||||||
positioning_context: PositioningContext,
|
positioning_context: PositioningContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return type of `FlexLine::layout`
|
/// Return type of `FlexLine::layout`
|
||||||
struct FlexLineLayoutResult {
|
struct FlexLineLayoutResult {
|
||||||
cross_size: Length,
|
cross_size: Au,
|
||||||
item_fragments: Vec<(BoxFragment, PositioningContext)>, // One per flex item, in the given order
|
item_fragments: Vec<(BoxFragment, PositioningContext)>, // One per flex item, in the given order
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,9 +121,9 @@ impl FlexContext<'_> {
|
||||||
|
|
||||||
fn rect_to_flow_relative(
|
fn rect_to_flow_relative(
|
||||||
&self,
|
&self,
|
||||||
base_rect_size: FlexRelativeVec2<Length>,
|
base_rect_size: FlexRelativeVec2<Au>,
|
||||||
rect: FlexRelativeRect<Length>,
|
rect: FlexRelativeRect<Au>,
|
||||||
) -> LogicalRect<Length> {
|
) -> LogicalRect<Au> {
|
||||||
super::geom::rect_to_flow_relative(
|
super::geom::rect_to_flow_relative(
|
||||||
self.flex_axis,
|
self.flex_axis,
|
||||||
self.main_start_cross_start_sides_are,
|
self.main_start_cross_start_sides_are,
|
||||||
|
@ -200,7 +198,7 @@ impl FlexContainer {
|
||||||
// but resolving percentages there requires access
|
// but resolving percentages there requires access
|
||||||
// to the flex container’s own containing block which we don’t have.
|
// to the flex container’s own containing block which we don’t have.
|
||||||
// For now, use incorrect values instead of panicking:
|
// For now, use incorrect values instead of panicking:
|
||||||
let container_min_cross_size = Length::zero();
|
let container_min_cross_size = Au::zero();
|
||||||
let container_max_cross_size = None;
|
let container_max_cross_size = None;
|
||||||
|
|
||||||
let flex_container_position_style = containing_block.style.get_position();
|
let flex_container_position_style = containing_block.style.get_position();
|
||||||
|
@ -251,8 +249,8 @@ impl FlexContainer {
|
||||||
),
|
),
|
||||||
// https://drafts.csswg.org/css-flexbox/#definite-sizes
|
// https://drafts.csswg.org/css-flexbox/#definite-sizes
|
||||||
container_definite_inner_size: flex_axis.vec2_to_flex_relative(LogicalVec2 {
|
container_definite_inner_size: flex_axis.vec2_to_flex_relative(LogicalVec2 {
|
||||||
inline: Some(containing_block.inline_size.into()),
|
inline: Some(containing_block.inline_size),
|
||||||
block: containing_block.block_size.non_auto().map(|t| t.into()),
|
block: containing_block.block_size.non_auto(),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -281,15 +279,12 @@ impl FlexContainer {
|
||||||
// https://drafts.csswg.org/css-flexbox/#algo-flex
|
// https://drafts.csswg.org/css-flexbox/#algo-flex
|
||||||
let flex_lines = collect_flex_lines(
|
let flex_lines = collect_flex_lines(
|
||||||
&mut flex_context,
|
&mut flex_context,
|
||||||
container_main_size.into(),
|
container_main_size,
|
||||||
&mut flex_items,
|
&mut flex_items,
|
||||||
|flex_context, mut line| line.layout(flex_context, container_main_size.into()),
|
|flex_context, mut line| line.layout(flex_context, container_main_size),
|
||||||
);
|
);
|
||||||
|
|
||||||
let content_cross_size = flex_lines
|
let content_cross_size = flex_lines.iter().map(|line| line.cross_size).sum();
|
||||||
.iter()
|
|
||||||
.map(|line| line.cross_size)
|
|
||||||
.sum::<Length>();
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-flexbox/#algo-cross-container
|
// https://drafts.csswg.org/css-flexbox/#algo-cross-container
|
||||||
let container_cross_size = flex_context
|
let container_cross_size = flex_context
|
||||||
|
@ -304,8 +299,8 @@ impl FlexContainer {
|
||||||
// https://drafts.csswg.org/css-flexbox/#algo-line-align
|
// https://drafts.csswg.org/css-flexbox/#algo-line-align
|
||||||
// Align all flex lines per `align-content`.
|
// Align all flex lines per `align-content`.
|
||||||
let line_count = flex_lines.len();
|
let line_count = flex_lines.len();
|
||||||
let mut cross_start_position_cursor = Length::zero();
|
let mut cross_start_position_cursor = Au::zero();
|
||||||
let mut line_interval = Length::zero();
|
let mut line_interval = Au::zero();
|
||||||
|
|
||||||
if let Some(cross_size) = flex_context.container_definite_inner_size.cross {
|
if let Some(cross_size) = flex_context.container_definite_inner_size.cross {
|
||||||
let free_space = cross_size - content_cross_size;
|
let free_space = cross_size - content_cross_size;
|
||||||
|
@ -324,7 +319,7 @@ impl FlexContainer {
|
||||||
|
|
||||||
// 1. If there is only a single item being aligned and alignment is a distributed alignment keyword
|
// 1. If there is only a single item being aligned and alignment is a distributed alignment keyword
|
||||||
// https://www.w3.org/TR/css-align-3/#distribution-values
|
// https://www.w3.org/TR/css-align-3/#distribution-values
|
||||||
if line_count <= 1 || free_space <= Length::zero() {
|
if line_count <= 1 || free_space <= Au::zero() {
|
||||||
(resolved_align_content, is_safe) = match resolved_align_content {
|
(resolved_align_content, is_safe) = match resolved_align_content {
|
||||||
AlignContent::Stretch => (AlignContent::FlexStart, true),
|
AlignContent::Stretch => (AlignContent::FlexStart, true),
|
||||||
AlignContent::SpaceBetween => (AlignContent::FlexStart, true),
|
AlignContent::SpaceBetween => (AlignContent::FlexStart, true),
|
||||||
|
@ -335,7 +330,7 @@ impl FlexContainer {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
|
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
|
||||||
if free_space <= Length::zero() && is_safe {
|
if free_space <= Au::zero() && is_safe {
|
||||||
resolved_align_content = AlignContent::Start;
|
resolved_align_content = AlignContent::Start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,40 +339,40 @@ impl FlexContainer {
|
||||||
|
|
||||||
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
|
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
|
||||||
cross_start_position_cursor = match resolved_align_content {
|
cross_start_position_cursor = match resolved_align_content {
|
||||||
AlignContent::Start => Length::zero(),
|
AlignContent::Start => Au::zero(),
|
||||||
AlignContent::FlexStart => {
|
AlignContent::FlexStart => {
|
||||||
if layout_is_flex_reversed {
|
if layout_is_flex_reversed {
|
||||||
free_space
|
free_space
|
||||||
} else {
|
} else {
|
||||||
Length::zero()
|
Au::zero()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AlignContent::End => free_space,
|
AlignContent::End => free_space,
|
||||||
AlignContent::FlexEnd => {
|
AlignContent::FlexEnd => {
|
||||||
if layout_is_flex_reversed {
|
if layout_is_flex_reversed {
|
||||||
Length::zero()
|
Au::zero()
|
||||||
} else {
|
} else {
|
||||||
free_space
|
free_space
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AlignContent::Center => free_space / 2.0,
|
AlignContent::Center => free_space / 2,
|
||||||
AlignContent::Stretch => Length::zero(),
|
AlignContent::Stretch => Au::zero(),
|
||||||
AlignContent::SpaceBetween => Length::zero(),
|
AlignContent::SpaceBetween => Au::zero(),
|
||||||
AlignContent::SpaceAround => (free_space / line_count as CSSFloat) / 2.0,
|
AlignContent::SpaceAround => free_space / line_count as i32 / 2,
|
||||||
AlignContent::SpaceEvenly => free_space / (line_count + 1) as CSSFloat,
|
AlignContent::SpaceEvenly => free_space / (line_count + 1) as i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Implement gap property
|
// TODO: Implement gap property
|
||||||
line_interval = /*gap + */ match resolved_align_content {
|
line_interval = /*gap + */ match resolved_align_content {
|
||||||
AlignContent::Start => Length::zero(),
|
AlignContent::Start => Au::zero(),
|
||||||
AlignContent::FlexStart => Length::zero(),
|
AlignContent::FlexStart => Au::zero(),
|
||||||
AlignContent::End => Length::zero(),
|
AlignContent::End => Au::zero(),
|
||||||
AlignContent::FlexEnd => Length::zero(),
|
AlignContent::FlexEnd => Au::zero(),
|
||||||
AlignContent::Center => Length::zero(),
|
AlignContent::Center => Au::zero(),
|
||||||
AlignContent::Stretch => Length::zero(),
|
AlignContent::Stretch => Au::zero(),
|
||||||
AlignContent::SpaceBetween => free_space / (line_count - 1) as CSSFloat,
|
AlignContent::SpaceBetween => free_space / (line_count - 1) as i32,
|
||||||
AlignContent::SpaceAround => free_space / line_count as CSSFloat,
|
AlignContent::SpaceAround => free_space / line_count as i32,
|
||||||
AlignContent::SpaceEvenly => free_space / (line_count + 1) as CSSFloat,
|
AlignContent::SpaceEvenly => free_space / (line_count + 1) as i32,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -406,7 +401,7 @@ impl FlexContainer {
|
||||||
// And we’ll need to change the signature of `IndependentFormattingContext::layout`
|
// And we’ll need to change the signature of `IndependentFormattingContext::layout`
|
||||||
// to allow the inner formatting context to “negotiate” a used inline-size
|
// to allow the inner formatting context to “negotiate” a used inline-size
|
||||||
// with the outer one somehow.
|
// with the outer one somehow.
|
||||||
container_main_size.into()
|
container_main_size
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -417,23 +412,23 @@ impl FlexContainer {
|
||||||
let flow_relative_line_position = match (flex_axis, flex_wrap_reverse) {
|
let flow_relative_line_position = match (flex_axis, flex_wrap_reverse) {
|
||||||
(FlexAxis::Row, false) => LogicalVec2 {
|
(FlexAxis::Row, false) => LogicalVec2 {
|
||||||
block: line_cross_start_position,
|
block: line_cross_start_position,
|
||||||
inline: Length::zero(),
|
inline: Au::zero(),
|
||||||
},
|
},
|
||||||
(FlexAxis::Row, true) => LogicalVec2 {
|
(FlexAxis::Row, true) => LogicalVec2 {
|
||||||
block: container_cross_size - line_cross_start_position - line.cross_size,
|
block: container_cross_size - line_cross_start_position - line.cross_size,
|
||||||
inline: Length::zero(),
|
inline: Au::zero(),
|
||||||
},
|
},
|
||||||
(FlexAxis::Column, false) => LogicalVec2 {
|
(FlexAxis::Column, false) => LogicalVec2 {
|
||||||
block: Length::zero(),
|
block: Au::zero(),
|
||||||
inline: line_cross_start_position,
|
inline: line_cross_start_position,
|
||||||
},
|
},
|
||||||
(FlexAxis::Column, true) => LogicalVec2 {
|
(FlexAxis::Column, true) => LogicalVec2 {
|
||||||
block: Length::zero(),
|
block: Au::zero(),
|
||||||
inline: container_cross_size - line_cross_start_position - line.cross_size,
|
inline: container_cross_size - line_cross_start_position - line.cross_size,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
for (fragment, _) in &mut line.item_fragments {
|
for (fragment, _) in &mut line.item_fragments {
|
||||||
fragment.content_rect.start_corner += &flow_relative_line_position.into()
|
fragment.content_rect.start_corner += &flow_relative_line_position
|
||||||
}
|
}
|
||||||
line.item_fragments
|
line.item_fragments
|
||||||
});
|
});
|
||||||
|
@ -472,7 +467,7 @@ impl FlexContainer {
|
||||||
|
|
||||||
IndependentLayout {
|
IndependentLayout {
|
||||||
fragments,
|
fragments,
|
||||||
content_block_size: content_block_size.into(),
|
content_block_size,
|
||||||
content_inline_size_for_table: None,
|
content_inline_size_for_table: None,
|
||||||
baselines: Baselines::default(),
|
baselines: Baselines::default(),
|
||||||
}
|
}
|
||||||
|
@ -497,15 +492,24 @@ impl<'a> FlexItem<'a> {
|
||||||
let cross_axis_is_item_block_axis = container_is_row ^ item_is_orthogonal;
|
let cross_axis_is_item_block_axis = container_is_row ^ item_is_orthogonal;
|
||||||
|
|
||||||
let pbm = box_.style().padding_border_margin(containing_block);
|
let pbm = box_.style().padding_border_margin(containing_block);
|
||||||
let content_box_size = box_.style().content_box_size(containing_block, &pbm);
|
let content_box_size = box_
|
||||||
let max_size = box_.style().content_max_box_size(containing_block, &pbm);
|
.style()
|
||||||
let min_size = box_.style().content_min_box_size(containing_block, &pbm);
|
.content_box_size(containing_block, &pbm)
|
||||||
|
.map(|v| v.map(Au::from));
|
||||||
|
let max_size = box_
|
||||||
|
.style()
|
||||||
|
.content_max_box_size(containing_block, &pbm)
|
||||||
|
.map(|v| v.map(Au::from));
|
||||||
|
let min_size = box_
|
||||||
|
.style()
|
||||||
|
.content_min_box_size(containing_block, &pbm)
|
||||||
|
.map(|v| v.map(Au::from));
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-flexbox/#min-size-auto
|
// https://drafts.csswg.org/css-flexbox/#min-size-auto
|
||||||
let automatic_min_size = || {
|
let automatic_min_size = || {
|
||||||
// FIXME(stshine): Consider more situations when auto min size is not needed.
|
// FIXME(stshine): Consider more situations when auto min size is not needed.
|
||||||
if box_.style().get_box().overflow_x.is_scrollable() {
|
if box_.style().get_box().overflow_x.is_scrollable() {
|
||||||
return Length::zero();
|
return Au::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
if cross_axis_is_item_block_axis {
|
if cross_axis_is_item_block_axis {
|
||||||
|
@ -519,12 +523,12 @@ impl<'a> FlexItem<'a> {
|
||||||
.inline_size_over_block_size_intrinsic_ratio(box_.style()),
|
.inline_size_over_block_size_intrinsic_ratio(box_.style()),
|
||||||
content_box_size.block,
|
content_box_size.block,
|
||||||
) {
|
) {
|
||||||
(Some(ratio), LengthOrAuto::LengthPercentage(block_size)) => {
|
(Some(ratio), AuOrAuto::LengthPercentage(block_size)) => {
|
||||||
let block_size = block_size.clamp_between_extremums(
|
let block_size = block_size.clamp_between_extremums(
|
||||||
min_size.block.auto_is(Length::zero),
|
min_size.block.auto_is(Au::zero),
|
||||||
max_size.block,
|
max_size.block,
|
||||||
);
|
);
|
||||||
Some(block_size * ratio)
|
Some(block_size.scale_by(ratio))
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -542,8 +546,8 @@ impl<'a> FlexItem<'a> {
|
||||||
.inline_size_over_block_size_intrinsic_ratio(box_.style())
|
.inline_size_over_block_size_intrinsic_ratio(box_.style())
|
||||||
{
|
{
|
||||||
inline_content_size.clamp_between_extremums(
|
inline_content_size.clamp_between_extremums(
|
||||||
(min_size.block.auto_is(Length::zero) * ratio).into(),
|
min_size.block.auto_is(Au::zero).scale_by(ratio),
|
||||||
max_size.block.map(|l| (l * ratio).into()),
|
max_size.block.map(|l| l.scale_by(ratio)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
inline_content_size
|
inline_content_size
|
||||||
|
@ -552,25 +556,25 @@ impl<'a> FlexItem<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = match specified_size_suggestion {
|
let result = match specified_size_suggestion {
|
||||||
LengthOrAuto::LengthPercentage(l) => l.min(content_size_suggestion.into()),
|
AuOrAuto::LengthPercentage(l) => l.min(content_size_suggestion),
|
||||||
LengthOrAuto::Auto => {
|
AuOrAuto::Auto => {
|
||||||
if let Some(l) = transferred_size_suggestion {
|
if let Some(l) = transferred_size_suggestion {
|
||||||
l.min(content_size_suggestion.into())
|
l.min(content_size_suggestion)
|
||||||
} else {
|
} else {
|
||||||
content_size_suggestion.into()
|
content_size_suggestion
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
result.clamp_below_max(max_size.inline)
|
result.clamp_below_max(max_size.inline)
|
||||||
} else {
|
} else {
|
||||||
// FIXME(stshine): Implement this when main axis is item's block axis.
|
// FIXME(stshine): Implement this when main axis is item's block axis.
|
||||||
Length::zero()
|
Au::zero()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let min_size = LogicalVec2 {
|
let min_size = LogicalVec2 {
|
||||||
inline: min_size.inline.auto_is(automatic_min_size),
|
inline: min_size.inline.auto_is(automatic_min_size),
|
||||||
block: min_size.block.auto_is(Length::zero),
|
block: min_size.block.auto_is(Au::zero),
|
||||||
};
|
};
|
||||||
let margin_auto_is_zero = pbm.margin.auto_is(Au::zero);
|
let margin_auto_is_zero = pbm.margin.auto_is(Au::zero);
|
||||||
|
|
||||||
|
@ -621,19 +625,19 @@ fn flex_base_size(
|
||||||
flex_context: &FlexContext,
|
flex_context: &FlexContext,
|
||||||
flex_item: &mut IndependentFormattingContext,
|
flex_item: &mut IndependentFormattingContext,
|
||||||
cross_axis_is_item_block_axis: bool,
|
cross_axis_is_item_block_axis: bool,
|
||||||
content_box_size: FlexRelativeVec2<LengthOrAuto>,
|
content_box_size: FlexRelativeVec2<AuOrAuto>,
|
||||||
padding_border_sums: FlexRelativeVec2<Au>,
|
padding_border_sums: FlexRelativeVec2<Au>,
|
||||||
) -> Length {
|
) -> Au {
|
||||||
let used_flex_basis = match &flex_item.style().get_position().flex_basis {
|
let used_flex_basis = match &flex_item.style().get_position().flex_basis {
|
||||||
FlexBasis::Content => FlexBasis::Content,
|
FlexBasis::Content => FlexBasis::Content,
|
||||||
FlexBasis::Size(Size::LengthPercentage(length_percentage)) => {
|
FlexBasis::Size(Size::LengthPercentage(length_percentage)) => {
|
||||||
let apply_box_sizing = |length: Length| {
|
let apply_box_sizing = |length: Au| {
|
||||||
match flex_item.style().get_position().box_sizing {
|
match flex_item.style().get_position().box_sizing {
|
||||||
BoxSizing::ContentBox => length,
|
BoxSizing::ContentBox => length,
|
||||||
BoxSizing::BorderBox => {
|
BoxSizing::BorderBox => {
|
||||||
// This may make `length` negative,
|
// This may make `length` negative,
|
||||||
// but it will be clamped in the hypothetical main size
|
// but it will be clamped in the hypothetical main size
|
||||||
length - padding_border_sums.main.into()
|
length - padding_border_sums.main
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -643,12 +647,12 @@ fn flex_base_size(
|
||||||
Some(container_definite_main_size) => {
|
Some(container_definite_main_size) => {
|
||||||
let length = length_percentage
|
let length = length_percentage
|
||||||
.0
|
.0
|
||||||
.percentage_relative_to(container_definite_main_size);
|
.percentage_relative_to(container_definite_main_size.into());
|
||||||
FlexBasis::Size(apply_box_sizing(length))
|
FlexBasis::Size(apply_box_sizing(length.into()))
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
if let Some(length) = length_percentage.0.to_length() {
|
if let Some(length) = length_percentage.0.to_length() {
|
||||||
FlexBasis::Size(apply_box_sizing(length))
|
FlexBasis::Size(apply_box_sizing(length.into()))
|
||||||
} else {
|
} else {
|
||||||
// “and if that containing block’s size is indefinite,
|
// “and if that containing block’s size is indefinite,
|
||||||
// the used value for `flex-basis` is `content`.”
|
// the used value for `flex-basis` is `content`.”
|
||||||
|
@ -662,9 +666,9 @@ fn flex_base_size(
|
||||||
// “When specified on a flex item, the `auto` keyword retrieves
|
// “When specified on a flex item, the `auto` keyword retrieves
|
||||||
// the value of the main size property as the used `flex-basis`.”
|
// the value of the main size property as the used `flex-basis`.”
|
||||||
match content_box_size.main {
|
match content_box_size.main {
|
||||||
LengthOrAuto::LengthPercentage(length) => FlexBasis::Size(length),
|
AuOrAuto::LengthPercentage(length) => FlexBasis::Size(length),
|
||||||
// “If that value is itself `auto`, then the used value is `content`.”
|
// “If that value is itself `auto`, then the used value is `content`.”
|
||||||
LengthOrAuto::Auto => FlexBasis::Content,
|
AuOrAuto::Auto => FlexBasis::Content,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -689,7 +693,6 @@ fn flex_base_size(
|
||||||
flex_item
|
flex_item
|
||||||
.inline_content_sizes(flex_context.layout_context)
|
.inline_content_sizes(flex_context.layout_context)
|
||||||
.max_content
|
.max_content
|
||||||
.into()
|
|
||||||
} else {
|
} else {
|
||||||
// FIXME: block-axis content sizing requires another pass
|
// FIXME: block-axis content sizing requires another pass
|
||||||
// of "full" layout
|
// of "full" layout
|
||||||
|
@ -705,7 +708,7 @@ fn flex_base_size(
|
||||||
// https://drafts.csswg.org/css-flexbox/#algo-line-break
|
// https://drafts.csswg.org/css-flexbox/#algo-line-break
|
||||||
fn collect_flex_lines<'items, LineResult>(
|
fn collect_flex_lines<'items, LineResult>(
|
||||||
flex_context: &mut FlexContext,
|
flex_context: &mut FlexContext,
|
||||||
container_main_size: Length,
|
container_main_size: Au,
|
||||||
mut items: &'items mut [FlexItem<'items>],
|
mut items: &'items mut [FlexItem<'items>],
|
||||||
mut each: impl FnMut(&mut FlexContext, FlexLine<'items>) -> LineResult,
|
mut each: impl FnMut(&mut FlexContext, FlexLine<'items>) -> LineResult,
|
||||||
) -> Vec<LineResult> {
|
) -> Vec<LineResult> {
|
||||||
|
@ -713,18 +716,18 @@ fn collect_flex_lines<'items, LineResult>(
|
||||||
let line = FlexLine {
|
let line = FlexLine {
|
||||||
outer_hypothetical_main_sizes_sum: items
|
outer_hypothetical_main_sizes_sum: items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|item| item.hypothetical_main_size + item.pbm_auto_is_zero.main.into())
|
.map(|item| item.hypothetical_main_size + item.pbm_auto_is_zero.main)
|
||||||
.sum(),
|
.sum(),
|
||||||
items,
|
items,
|
||||||
};
|
};
|
||||||
vec![each(flex_context, line)]
|
vec![each(flex_context, line)]
|
||||||
} else {
|
} else {
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
let mut line_size_so_far = Length::zero();
|
let mut line_size_so_far = Au::zero();
|
||||||
let mut line_so_far_is_empty = true;
|
let mut line_so_far_is_empty = true;
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
while let Some(item) = items.get(index) {
|
while let Some(item) = items.get(index) {
|
||||||
let item_size = item.hypothetical_main_size + item.pbm_auto_is_zero.main.into();
|
let item_size = item.hypothetical_main_size + item.pbm_auto_is_zero.main;
|
||||||
let line_size_would_be = line_size_so_far + item_size;
|
let line_size_would_be = line_size_so_far + item_size;
|
||||||
let item_fits = line_size_would_be <= container_main_size;
|
let item_fits = line_size_would_be <= container_main_size;
|
||||||
if item_fits || line_so_far_is_empty {
|
if item_fits || line_so_far_is_empty {
|
||||||
|
@ -759,7 +762,7 @@ impl FlexLine<'_> {
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
flex_context: &mut FlexContext,
|
flex_context: &mut FlexContext,
|
||||||
container_main_size: Length,
|
container_main_size: Au,
|
||||||
) -> FlexLineLayoutResult {
|
) -> FlexLineLayoutResult {
|
||||||
let (item_used_main_sizes, mut free_space) =
|
let (item_used_main_sizes, mut free_space) =
|
||||||
self.resolve_flexible_lengths(container_main_size);
|
self.resolve_flexible_lengths(container_main_size);
|
||||||
|
@ -800,7 +803,7 @@ impl FlexLine<'_> {
|
||||||
item.content_box_size.cross.is_auto() &&
|
item.content_box_size.cross.is_auto() &&
|
||||||
!(item.margin.cross_start.is_auto() || item.margin.cross_end.is_auto())
|
!(item.margin.cross_start.is_auto() || item.margin.cross_end.is_auto())
|
||||||
{
|
{
|
||||||
(line_cross_size - item.pbm_auto_is_zero.cross.into()).clamp_between_extremums(
|
(line_cross_size - item.pbm_auto_is_zero.cross).clamp_between_extremums(
|
||||||
item.content_min_size.cross,
|
item.content_min_size.cross,
|
||||||
item.content_max_size.cross,
|
item.content_max_size.cross,
|
||||||
)
|
)
|
||||||
|
@ -822,7 +825,7 @@ impl FlexLine<'_> {
|
||||||
let (item_main_margins, free_space_distributed) =
|
let (item_main_margins, free_space_distributed) =
|
||||||
self.resolve_auto_main_margins(free_space);
|
self.resolve_auto_main_margins(free_space);
|
||||||
if free_space_distributed {
|
if free_space_distributed {
|
||||||
free_space = Length::zero();
|
free_space = Au::zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Align the items along the main-axis per justify-content.
|
// Align the items along the main-axis per justify-content.
|
||||||
|
@ -842,7 +845,7 @@ impl FlexLine<'_> {
|
||||||
|
|
||||||
// 1. If there is only a single item being aligned and alignment is a distributed alignment keyword
|
// 1. If there is only a single item being aligned and alignment is a distributed alignment keyword
|
||||||
// https://www.w3.org/TR/css-align-3/#distribution-values
|
// https://www.w3.org/TR/css-align-3/#distribution-values
|
||||||
if item_count <= 1 || free_space <= Length::zero() {
|
if item_count <= 1 || free_space <= Au::zero() {
|
||||||
(resolved_justify_content, is_safe) = match resolved_justify_content {
|
(resolved_justify_content, is_safe) = match resolved_justify_content {
|
||||||
JustifyContent::Stretch => (JustifyContent::FlexStart, true),
|
JustifyContent::Stretch => (JustifyContent::FlexStart, true),
|
||||||
JustifyContent::SpaceBetween => (JustifyContent::FlexStart, true),
|
JustifyContent::SpaceBetween => (JustifyContent::FlexStart, true),
|
||||||
|
@ -853,7 +856,7 @@ impl FlexLine<'_> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
|
// 2. If free space is negative the "safe" alignment variants all fallback to Start alignment
|
||||||
if free_space <= Length::zero() && is_safe {
|
if free_space <= Au::zero() && is_safe {
|
||||||
resolved_justify_content = JustifyContent::Start;
|
resolved_justify_content = JustifyContent::Start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -862,40 +865,40 @@ impl FlexLine<'_> {
|
||||||
|
|
||||||
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
|
// Implement "unsafe" alignment. "safe" alignment is handled by the fallback process above.
|
||||||
let main_start_position = match resolved_justify_content {
|
let main_start_position = match resolved_justify_content {
|
||||||
JustifyContent::Start => Length::zero(),
|
JustifyContent::Start => Au::zero(),
|
||||||
JustifyContent::FlexStart => {
|
JustifyContent::FlexStart => {
|
||||||
if layout_is_flex_reversed {
|
if layout_is_flex_reversed {
|
||||||
free_space
|
free_space
|
||||||
} else {
|
} else {
|
||||||
Length::zero()
|
Au::zero()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
JustifyContent::End => free_space,
|
JustifyContent::End => free_space,
|
||||||
JustifyContent::FlexEnd => {
|
JustifyContent::FlexEnd => {
|
||||||
if layout_is_flex_reversed {
|
if layout_is_flex_reversed {
|
||||||
Length::zero()
|
Au::zero()
|
||||||
} else {
|
} else {
|
||||||
free_space
|
free_space
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
JustifyContent::Center => free_space / 2.0,
|
JustifyContent::Center => free_space / 2,
|
||||||
JustifyContent::Stretch => Length::zero(),
|
JustifyContent::Stretch => Au::zero(),
|
||||||
JustifyContent::SpaceBetween => Length::zero(),
|
JustifyContent::SpaceBetween => Au::zero(),
|
||||||
JustifyContent::SpaceAround => (free_space / item_count as CSSFloat) / 2.0,
|
JustifyContent::SpaceAround => (free_space / item_count as i32) / 2,
|
||||||
JustifyContent::SpaceEvenly => free_space / (item_count + 1) as CSSFloat,
|
JustifyContent::SpaceEvenly => free_space / (item_count + 1) as i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Implement gap property
|
// TODO: Implement gap property
|
||||||
let item_main_interval = /*gap + */ match resolved_justify_content {
|
let item_main_interval = /*gap + */ match resolved_justify_content {
|
||||||
JustifyContent::Start => Length::zero(),
|
JustifyContent::Start => Au::zero(),
|
||||||
JustifyContent::FlexStart => Length::zero(),
|
JustifyContent::FlexStart => Au::zero(),
|
||||||
JustifyContent::End => Length::zero(),
|
JustifyContent::End => Au::zero(),
|
||||||
JustifyContent::FlexEnd => Length::zero(),
|
JustifyContent::FlexEnd => Au::zero(),
|
||||||
JustifyContent::Center => Length::zero(),
|
JustifyContent::Center => Au::zero(),
|
||||||
JustifyContent::Stretch => Length::zero(),
|
JustifyContent::Stretch => Au::zero(),
|
||||||
JustifyContent::SpaceBetween => free_space / (item_count - 1) as CSSFloat,
|
JustifyContent::SpaceBetween => free_space / (item_count - 1) as i32,
|
||||||
JustifyContent::SpaceAround => free_space / item_count as CSSFloat,
|
JustifyContent::SpaceAround => free_space / item_count as i32,
|
||||||
JustifyContent::SpaceEvenly => free_space / (item_count + 1) as CSSFloat,
|
JustifyContent::SpaceEvenly => free_space / (item_count + 1) as i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-flexbox/#algo-cross-margins
|
// https://drafts.csswg.org/css-flexbox/#algo-cross-margins
|
||||||
|
@ -957,7 +960,7 @@ impl FlexLine<'_> {
|
||||||
.zip(&item_margins)
|
.zip(&item_margins)
|
||||||
.map(|(((item, item_result), content_rect), margin)| {
|
.map(|(((item, item_result), content_rect), margin)| {
|
||||||
let content_rect = flex_context.rect_to_flow_relative(line_size, content_rect);
|
let content_rect = flex_context.rect_to_flow_relative(line_size, content_rect);
|
||||||
let margin = flex_context.sides_to_flow_relative(*margin).into();
|
let margin = flex_context.sides_to_flow_relative(*margin);
|
||||||
let collapsed_margin = CollapsedBlockMargins::from_margin(&margin);
|
let collapsed_margin = CollapsedBlockMargins::from_margin(&margin);
|
||||||
(
|
(
|
||||||
// TODO: We should likely propagate baselines from `display: flex`.
|
// TODO: We should likely propagate baselines from `display: flex`.
|
||||||
|
@ -965,7 +968,7 @@ impl FlexLine<'_> {
|
||||||
item.box_.base_fragment_info(),
|
item.box_.base_fragment_info(),
|
||||||
item.box_.style().clone(),
|
item.box_.style().clone(),
|
||||||
item_result.fragments,
|
item_result.fragments,
|
||||||
content_rect.into(),
|
content_rect,
|
||||||
flex_context.sides_to_flow_relative(item.padding),
|
flex_context.sides_to_flow_relative(item.padding),
|
||||||
flex_context.sides_to_flow_relative(item.border),
|
flex_context.sides_to_flow_relative(item.border),
|
||||||
margin,
|
margin,
|
||||||
|
@ -984,7 +987,7 @@ impl FlexLine<'_> {
|
||||||
|
|
||||||
/// Return the *main size* of each item, and the line’s remainaing free space
|
/// Return the *main size* of each item, and the line’s remainaing free space
|
||||||
/// <https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths>
|
/// <https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths>
|
||||||
fn resolve_flexible_lengths(&self, container_main_size: Length) -> (Vec<Length>, Length) {
|
fn resolve_flexible_lengths(&self, container_main_size: Au) -> (Vec<Au>, Au) {
|
||||||
let mut frozen = vec![false; self.items.len()];
|
let mut frozen = vec![false; self.items.len()];
|
||||||
let mut target_main_sizes_vec = self
|
let mut target_main_sizes_vec = self
|
||||||
.items
|
.items
|
||||||
|
@ -1030,12 +1033,11 @@ impl FlexLine<'_> {
|
||||||
.map(|((item, target_main_size), frozen)| {
|
.map(|((item, target_main_size), frozen)| {
|
||||||
item.pbm_auto_is_zero.main +
|
item.pbm_auto_is_zero.main +
|
||||||
if frozen.get() {
|
if frozen.get() {
|
||||||
target_main_size.get().into()
|
target_main_size.get()
|
||||||
} else {
|
} else {
|
||||||
item.flex_base_size.into()
|
item.flex_base_size
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|t| t.into())
|
|
||||||
.sum()
|
.sum()
|
||||||
};
|
};
|
||||||
// https://drafts.csswg.org/css-flexbox/#initial-free-space
|
// https://drafts.csswg.org/css-flexbox/#initial-free-space
|
||||||
|
@ -1059,7 +1061,7 @@ impl FlexLine<'_> {
|
||||||
unfrozen_items().map(|(item, _)| flex_factor(item)).sum();
|
unfrozen_items().map(|(item, _)| flex_factor(item)).sum();
|
||||||
// FIXME: I (Simon) transcribed the spec but I don’t yet understand why this algorithm
|
// FIXME: I (Simon) transcribed the spec but I don’t yet understand why this algorithm
|
||||||
if unfrozen_items_flex_factor_sum < 1. {
|
if unfrozen_items_flex_factor_sum < 1. {
|
||||||
let multiplied = initial_free_space * unfrozen_items_flex_factor_sum;
|
let multiplied = initial_free_space.scale_by(unfrozen_items_flex_factor_sum);
|
||||||
if multiplied.abs() < remaining_free_space.abs() {
|
if multiplied.abs() < remaining_free_space.abs() {
|
||||||
remaining_free_space = multiplied
|
remaining_free_space = multiplied
|
||||||
}
|
}
|
||||||
|
@ -1068,34 +1070,37 @@ impl FlexLine<'_> {
|
||||||
// “Distribute free space proportional to the flex factors.”
|
// “Distribute free space proportional to the flex factors.”
|
||||||
// FIXME: is it a problem if floating point precision errors accumulate
|
// FIXME: is it a problem if floating point precision errors accumulate
|
||||||
// and we get not-quite-zero remaining free space when we should get zero here?
|
// and we get not-quite-zero remaining free space when we should get zero here?
|
||||||
if remaining_free_space != Length::zero() {
|
if remaining_free_space != Au::zero() {
|
||||||
if grow {
|
if grow {
|
||||||
for (item, target_main_size) in unfrozen_items() {
|
for (item, target_main_size) in unfrozen_items() {
|
||||||
let grow_factor = item.box_.style().get_position().flex_grow.0;
|
let grow_factor = item.box_.style().get_position().flex_grow.0;
|
||||||
let ratio = grow_factor / unfrozen_items_flex_factor_sum;
|
let ratio = grow_factor / unfrozen_items_flex_factor_sum;
|
||||||
target_main_size.set(item.flex_base_size + remaining_free_space * ratio);
|
target_main_size
|
||||||
|
.set(item.flex_base_size + remaining_free_space.scale_by(ratio));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// https://drafts.csswg.org/css-flexbox/#scaled-flex-shrink-factor
|
// https://drafts.csswg.org/css-flexbox/#scaled-flex-shrink-factor
|
||||||
let scaled_shrink_factor = |item: &FlexItem| {
|
let scaled_shrink_factor = |item: &FlexItem| {
|
||||||
let shrink_factor = item.box_.style().get_position().flex_shrink.0;
|
let shrink_factor = item.box_.style().get_position().flex_shrink.0;
|
||||||
item.flex_base_size * shrink_factor
|
item.flex_base_size.scale_by(shrink_factor)
|
||||||
};
|
};
|
||||||
let scaled_shrink_factors_sum: Length = unfrozen_items()
|
let scaled_shrink_factors_sum: Au = unfrozen_items()
|
||||||
.map(|(item, _)| scaled_shrink_factor(item))
|
.map(|(item, _)| scaled_shrink_factor(item))
|
||||||
.sum();
|
.sum();
|
||||||
if scaled_shrink_factors_sum > Length::zero() {
|
if scaled_shrink_factors_sum > Au::zero() {
|
||||||
for (item, target_main_size) in unfrozen_items() {
|
for (item, target_main_size) in unfrozen_items() {
|
||||||
let ratio = scaled_shrink_factor(item) / scaled_shrink_factors_sum;
|
let ratio = scaled_shrink_factor(item).0 as f32 /
|
||||||
target_main_size
|
scaled_shrink_factors_sum.0 as f32;
|
||||||
.set(item.flex_base_size - remaining_free_space.abs() * ratio);
|
target_main_size.set(
|
||||||
|
item.flex_base_size - remaining_free_space.abs().scale_by(ratio),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// “Fix min/max violations.”
|
// “Fix min/max violations.”
|
||||||
let violation = |(item, target_main_size): (&FlexItem, &Cell<Length>)| {
|
let violation = |(item, target_main_size): (&FlexItem, &Cell<Au>)| {
|
||||||
let size = target_main_size.get();
|
let size = target_main_size.get();
|
||||||
let clamped = size.clamp_between_extremums(
|
let clamped = size.clamp_between_extremums(
|
||||||
item.content_min_size.main,
|
item.content_min_size.main,
|
||||||
|
@ -1105,19 +1110,19 @@ impl FlexLine<'_> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// “Freeze over-flexed items.”
|
// “Freeze over-flexed items.”
|
||||||
let total_violation: Length = unfrozen_items().map(violation).sum();
|
let total_violation: Au = unfrozen_items().map(violation).sum();
|
||||||
if total_violation == Length::zero() {
|
if total_violation == Au::zero() {
|
||||||
// “Freeze all items.”
|
// “Freeze all items.”
|
||||||
// Return instead, as that’s what the next loop iteration would do.
|
// Return instead, as that’s what the next loop iteration would do.
|
||||||
let remaining_free_space =
|
let remaining_free_space =
|
||||||
container_main_size - target_main_sizes_vec.iter().cloned().sum();
|
container_main_size - target_main_sizes_vec.iter().cloned().sum();
|
||||||
return (target_main_sizes_vec, remaining_free_space);
|
return (target_main_sizes_vec, remaining_free_space);
|
||||||
} else if total_violation > Length::zero() {
|
} else if total_violation > Au::zero() {
|
||||||
// “Freeze all the items with min violations.”
|
// “Freeze all the items with min violations.”
|
||||||
// “If the item’s target main size was made larger by [clamping],
|
// “If the item’s target main size was made larger by [clamping],
|
||||||
// it’s a min violation.”
|
// it’s a min violation.”
|
||||||
for (item_and_target_main_size, frozen) in items() {
|
for (item_and_target_main_size, frozen) in items() {
|
||||||
if violation(item_and_target_main_size) > Length::zero() {
|
if violation(item_and_target_main_size) > Au::zero() {
|
||||||
let (item, target_main_size) = item_and_target_main_size;
|
let (item, target_main_size) = item_and_target_main_size;
|
||||||
target_main_size.set(item.content_min_size.main);
|
target_main_size.set(item.content_min_size.main);
|
||||||
frozen_count.set(frozen_count.get() + 1);
|
frozen_count.set(frozen_count.get() + 1);
|
||||||
|
@ -1130,7 +1135,7 @@ impl FlexLine<'_> {
|
||||||
// “If the item’s target main size was made smaller by [clamping],
|
// “If the item’s target main size was made smaller by [clamping],
|
||||||
// it’s a max violation.”
|
// it’s a max violation.”
|
||||||
for (item_and_target_main_size, frozen) in items() {
|
for (item_and_target_main_size, frozen) in items() {
|
||||||
if violation(item_and_target_main_size) < Length::zero() {
|
if violation(item_and_target_main_size) < Au::zero() {
|
||||||
let (item, target_main_size) = item_and_target_main_size;
|
let (item, target_main_size) = item_and_target_main_size;
|
||||||
let Some(max_size) = item.content_max_size.main else {
|
let Some(max_size) = item.content_max_size.main else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -1152,9 +1157,9 @@ impl<'a> FlexItem<'a> {
|
||||||
// with the used main size and the given available space, treating `auto` as `fit-content`.”
|
// with the used main size and the given available space, treating `auto` as `fit-content`.”
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
used_main_size: Length,
|
used_main_size: Au,
|
||||||
flex_context: &mut FlexContext,
|
flex_context: &mut FlexContext,
|
||||||
used_cross_size_override: Option<Length>,
|
used_cross_size_override: Option<Au>,
|
||||||
) -> FlexItemLayoutResult {
|
) -> FlexItemLayoutResult {
|
||||||
let mut positioning_context = PositioningContext::new_for_subtree(
|
let mut positioning_context = PositioningContext::new_for_subtree(
|
||||||
flex_context
|
flex_context
|
||||||
|
@ -1183,7 +1188,7 @@ impl<'a> FlexItem<'a> {
|
||||||
.style
|
.style
|
||||||
.content_box_size(flex_context.containing_block, &pbm)
|
.content_box_size(flex_context.containing_block, &pbm)
|
||||||
.inline,
|
.inline,
|
||||||
block: LengthOrAuto::LengthPercentage(size),
|
block: LengthOrAuto::LengthPercentage(size.into()),
|
||||||
});
|
});
|
||||||
let size = replaced.contents.used_size_as_if_inline_element(
|
let size = replaced.contents.used_size_as_if_inline_element(
|
||||||
flex_context.containing_block,
|
flex_context.containing_block,
|
||||||
|
@ -1194,19 +1199,19 @@ impl<'a> FlexItem<'a> {
|
||||||
let cross_size = flex_context.vec2_to_flex_relative(size).cross;
|
let cross_size = flex_context.vec2_to_flex_relative(size).cross;
|
||||||
let fragments = replaced.contents.make_fragments(&replaced.style, size);
|
let fragments = replaced.contents.make_fragments(&replaced.style, size);
|
||||||
FlexItemLayoutResult {
|
FlexItemLayoutResult {
|
||||||
hypothetical_cross_size: cross_size.into(),
|
hypothetical_cross_size: cross_size,
|
||||||
fragments,
|
fragments,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||||
let block_size = match used_cross_size_override {
|
let block_size = match used_cross_size_override {
|
||||||
Some(s) => AuOrAuto::LengthPercentage(s.into()),
|
Some(s) => AuOrAuto::LengthPercentage(s),
|
||||||
None => self.content_box_size.cross.map(|t| t.into()),
|
None => self.content_box_size.cross.map(|t| t),
|
||||||
};
|
};
|
||||||
|
|
||||||
let item_as_containing_block = ContainingBlock {
|
let item_as_containing_block = ContainingBlock {
|
||||||
inline_size: used_main_size.into(),
|
inline_size: used_main_size,
|
||||||
block_size,
|
block_size,
|
||||||
style: &non_replaced.style,
|
style: &non_replaced.style,
|
||||||
};
|
};
|
||||||
|
@ -1224,7 +1229,7 @@ impl<'a> FlexItem<'a> {
|
||||||
let hypothetical_cross_size = self
|
let hypothetical_cross_size = self
|
||||||
.content_box_size
|
.content_box_size
|
||||||
.cross
|
.cross
|
||||||
.auto_is(|| content_block_size.into())
|
.auto_is(|| content_block_size)
|
||||||
.clamp_between_extremums(
|
.clamp_between_extremums(
|
||||||
self.content_min_size.cross,
|
self.content_min_size.cross,
|
||||||
self.content_max_size.cross,
|
self.content_max_size.cross,
|
||||||
|
@ -1253,7 +1258,7 @@ impl<'items> FlexLine<'items> {
|
||||||
&self,
|
&self,
|
||||||
item_layout_results: &[FlexItemLayoutResult],
|
item_layout_results: &[FlexItemLayoutResult],
|
||||||
flex_context: &FlexContext,
|
flex_context: &FlexContext,
|
||||||
) -> Length {
|
) -> Au {
|
||||||
if flex_context.container_is_single_line {
|
if flex_context.container_is_single_line {
|
||||||
if let Some(size) = flex_context.container_definite_inner_size.cross {
|
if let Some(size) = flex_context.container_definite_inner_size.cross {
|
||||||
return size;
|
return size;
|
||||||
|
@ -1264,12 +1269,12 @@ impl<'items> FlexLine<'items> {
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&*self.items)
|
.zip(&*self.items)
|
||||||
.map(|(item_result, item)| {
|
.map(|(item_result, item)| {
|
||||||
item_result.hypothetical_cross_size + item.pbm_auto_is_zero.cross.into()
|
item_result.hypothetical_cross_size + item.pbm_auto_is_zero.cross
|
||||||
});
|
});
|
||||||
// FIXME: add support for `align-self: baseline`
|
// FIXME: add support for `align-self: baseline`
|
||||||
// and computing the baseline of flex items.
|
// and computing the baseline of flex items.
|
||||||
// https://drafts.csswg.org/css-flexbox/#baseline-participation
|
// https://drafts.csswg.org/css-flexbox/#baseline-participation
|
||||||
let largest = outer_hypothetical_cross_sizes.fold(Length::zero(), Length::max);
|
let largest = outer_hypothetical_cross_sizes.fold(Au::zero(), Au::max);
|
||||||
if flex_context.container_is_single_line {
|
if flex_context.container_is_single_line {
|
||||||
largest.clamp_between_extremums(
|
largest.clamp_between_extremums(
|
||||||
flex_context.container_min_cross_size,
|
flex_context.container_min_cross_size,
|
||||||
|
@ -1285,9 +1290,9 @@ impl<'items> FlexLine<'items> {
|
||||||
// and return whether free space has been distributed.
|
// and return whether free space has been distributed.
|
||||||
fn resolve_auto_main_margins(
|
fn resolve_auto_main_margins(
|
||||||
&self,
|
&self,
|
||||||
remaining_free_space: Length,
|
remaining_free_space: Au,
|
||||||
) -> (impl Iterator<Item = (Length, Length)> + '_, bool) {
|
) -> (impl Iterator<Item = (Au, Au)> + '_, bool) {
|
||||||
let each_auto_margin = if remaining_free_space > Length::zero() {
|
let each_auto_margin = if remaining_free_space > Au::zero() {
|
||||||
let auto_margins_count = self
|
let auto_margins_count = self
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1296,38 +1301,32 @@ impl<'items> FlexLine<'items> {
|
||||||
})
|
})
|
||||||
.sum::<u32>();
|
.sum::<u32>();
|
||||||
if auto_margins_count > 0 {
|
if auto_margins_count > 0 {
|
||||||
remaining_free_space / auto_margins_count as f32
|
remaining_free_space / auto_margins_count as i32
|
||||||
} else {
|
} else {
|
||||||
Length::zero()
|
Au::zero()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Length::zero()
|
Au::zero()
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
self.items.iter().map(move |item| {
|
self.items.iter().map(move |item| {
|
||||||
(
|
(
|
||||||
item.margin
|
item.margin.main_start.auto_is(|| each_auto_margin),
|
||||||
.main_start
|
item.margin.main_end.auto_is(|| each_auto_margin),
|
||||||
.auto_is(|| each_auto_margin.into())
|
|
||||||
.into(),
|
|
||||||
item.margin
|
|
||||||
.main_end
|
|
||||||
.auto_is(|| each_auto_margin.into())
|
|
||||||
.into(),
|
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
each_auto_margin > Length::zero(),
|
each_auto_margin > Au::zero(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the coordinate of the main-start side of the content area of each item
|
/// Return the coordinate of the main-start side of the content area of each item
|
||||||
fn align_along_main_axis<'a>(
|
fn align_along_main_axis<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
item_used_main_sizes: &'a [Length],
|
item_used_main_sizes: &'a [Au],
|
||||||
item_margins: &'a [FlexRelativeSides<Length>],
|
item_margins: &'a [FlexRelativeSides<Au>],
|
||||||
main_start_position: Length,
|
main_start_position: Au,
|
||||||
item_main_interval: Length,
|
item_main_interval: Au,
|
||||||
) -> impl Iterator<Item = Length> + 'a {
|
) -> impl Iterator<Item = Au> + 'a {
|
||||||
// “Align the items along the main-axis”
|
// “Align the items along the main-axis”
|
||||||
let mut main_position_cursor = main_start_position;
|
let mut main_position_cursor = main_start_position;
|
||||||
self.items
|
self.items
|
||||||
|
@ -1335,13 +1334,12 @@ impl<'items> FlexLine<'items> {
|
||||||
.zip(item_used_main_sizes)
|
.zip(item_used_main_sizes)
|
||||||
.zip(item_margins)
|
.zip(item_margins)
|
||||||
.map(move |((item, &main_content_size), margin)| {
|
.map(move |((item, &main_content_size), margin)| {
|
||||||
main_position_cursor += margin.main_start +
|
main_position_cursor +=
|
||||||
item.border.main_start.into() +
|
margin.main_start + item.border.main_start + item.padding.main_start;
|
||||||
item.padding.main_start.into();
|
|
||||||
let content_main_start_position = main_position_cursor;
|
let content_main_start_position = main_position_cursor;
|
||||||
main_position_cursor += main_content_size +
|
main_position_cursor += main_content_size +
|
||||||
item.padding.main_end.into() +
|
item.padding.main_end +
|
||||||
item.border.main_end.into() +
|
item.border.main_end +
|
||||||
margin.main_end +
|
margin.main_end +
|
||||||
item_main_interval;
|
item_main_interval;
|
||||||
content_main_start_position
|
content_main_start_position
|
||||||
|
@ -1355,24 +1353,24 @@ impl FlexItem<'_> {
|
||||||
fn resolve_auto_cross_margins(
|
fn resolve_auto_cross_margins(
|
||||||
&self,
|
&self,
|
||||||
flex_context: &FlexContext,
|
flex_context: &FlexContext,
|
||||||
line_cross_size: Length,
|
line_cross_size: Au,
|
||||||
item_cross_content_size: Length,
|
item_cross_content_size: Au,
|
||||||
) -> (Length, Length) {
|
) -> (Au, Au) {
|
||||||
let auto_count = match (self.margin.cross_start, self.margin.cross_end) {
|
let auto_count = match (self.margin.cross_start, self.margin.cross_end) {
|
||||||
(AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
|
(AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
|
||||||
return (start.into(), end.into());
|
return (start, end);
|
||||||
},
|
},
|
||||||
(AuOrAuto::Auto, AuOrAuto::Auto) => 2.,
|
(AuOrAuto::Auto, AuOrAuto::Auto) => 2,
|
||||||
_ => 1.,
|
_ => 1,
|
||||||
};
|
};
|
||||||
let outer_size = self.pbm_auto_is_zero.cross + item_cross_content_size.into();
|
let outer_size = self.pbm_auto_is_zero.cross + item_cross_content_size;
|
||||||
let available = line_cross_size - outer_size.into();
|
let available = line_cross_size - outer_size;
|
||||||
let start;
|
let start;
|
||||||
let end;
|
let end;
|
||||||
if available > Length::zero() {
|
if available > Au::zero() {
|
||||||
let each_auto_margin = available / auto_count;
|
let each_auto_margin = available / auto_count;
|
||||||
start = self.margin.cross_start.auto_is(|| each_auto_margin.into());
|
start = self.margin.cross_start.auto_is(|| each_auto_margin);
|
||||||
end = self.margin.cross_end.auto_is(|| each_auto_margin.into());
|
end = self.margin.cross_end.auto_is(|| each_auto_margin);
|
||||||
} else {
|
} else {
|
||||||
// “the block-start or inline-start margin (whichever is in the cross axis)”
|
// “the block-start or inline-start margin (whichever is in the cross axis)”
|
||||||
// This margin is the cross-end on iff `flex-wrap` is `wrap-reverse`,
|
// This margin is the cross-end on iff `flex-wrap` is `wrap-reverse`,
|
||||||
|
@ -1395,44 +1393,41 @@ impl FlexItem<'_> {
|
||||||
// set it to zero. Set the opposite margin so that the outer cross size of the item
|
// set it to zero. Set the opposite margin so that the outer cross size of the item
|
||||||
// equals the cross size of its flex line.”
|
// equals the cross size of its flex line.”
|
||||||
if flex_wrap_reverse {
|
if flex_wrap_reverse {
|
||||||
start = self.margin.cross_start.auto_is(|| available.into());
|
start = self.margin.cross_start.auto_is(|| available);
|
||||||
end = self.margin.cross_end.auto_is(Au::zero);
|
end = self.margin.cross_end.auto_is(Au::zero);
|
||||||
} else {
|
} else {
|
||||||
start = self.margin.cross_start.auto_is(Au::zero);
|
start = self.margin.cross_start.auto_is(Au::zero);
|
||||||
end = self.margin.cross_end.auto_is(|| available.into());
|
end = self.margin.cross_end.auto_is(|| available);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(start.into(), end.into())
|
(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the coordinate of the cross-start side of the content area
|
/// Return the coordinate of the cross-start side of the content area
|
||||||
fn align_along_cross_axis(
|
fn align_along_cross_axis(
|
||||||
&self,
|
&self,
|
||||||
margin: &FlexRelativeSides<Length>,
|
margin: &FlexRelativeSides<Au>,
|
||||||
content_size: &Length,
|
content_size: &Au,
|
||||||
line_cross_size: Length,
|
line_cross_size: Au,
|
||||||
) -> Length {
|
) -> Au {
|
||||||
let outer_cross_start =
|
let outer_cross_start =
|
||||||
if self.margin.cross_start.is_auto() || self.margin.cross_end.is_auto() {
|
if self.margin.cross_start.is_auto() || self.margin.cross_end.is_auto() {
|
||||||
Length::zero()
|
Au::zero()
|
||||||
} else {
|
} else {
|
||||||
match self.align_self {
|
match self.align_self {
|
||||||
AlignItems::Stretch | AlignItems::FlexStart => Length::zero(),
|
AlignItems::Stretch | AlignItems::FlexStart => Au::zero(),
|
||||||
AlignItems::FlexEnd => {
|
AlignItems::FlexEnd => {
|
||||||
let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross.into();
|
let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross;
|
||||||
line_cross_size - margin_box_cross
|
line_cross_size - margin_box_cross
|
||||||
},
|
},
|
||||||
AlignItems::Center => {
|
AlignItems::Center => {
|
||||||
let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross.into();
|
let margin_box_cross = *content_size + self.pbm_auto_is_zero.cross;
|
||||||
(line_cross_size - margin_box_cross) / 2.
|
(line_cross_size - margin_box_cross) / 2
|
||||||
},
|
},
|
||||||
// FIXME: handle baseline alignment
|
// FIXME: handle baseline alignment
|
||||||
AlignItems::Baseline => Length::zero(),
|
AlignItems::Baseline => Au::zero(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
outer_cross_start +
|
outer_cross_start + margin.cross_start + self.border.cross_start + self.padding.cross_start
|
||||||
margin.cross_start +
|
|
||||||
self.border.cross_start.into() +
|
|
||||||
self.padding.cross_start.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ pub type PhysicalPoint<U> = euclid::Point2D<U, CSSPixel>;
|
||||||
pub type PhysicalSize<U> = euclid::Size2D<U, CSSPixel>;
|
pub type PhysicalSize<U> = euclid::Size2D<U, CSSPixel>;
|
||||||
pub type PhysicalRect<U> = euclid::Rect<U, CSSPixel>;
|
pub type PhysicalRect<U> = euclid::Rect<U, CSSPixel>;
|
||||||
pub type PhysicalSides<U> = euclid::SideOffsets2D<U, CSSPixel>;
|
pub type PhysicalSides<U> = euclid::SideOffsets2D<U, CSSPixel>;
|
||||||
pub type LengthOrAuto = AutoOr<Length>;
|
|
||||||
pub type AuOrAuto = AutoOr<Au>;
|
pub type AuOrAuto = AutoOr<Au>;
|
||||||
|
pub type LengthOrAuto = AutoOr<Length>;
|
||||||
pub type LengthPercentageOrAuto<'a> = AutoOr<&'a LengthPercentage>;
|
pub type LengthPercentageOrAuto<'a> = AutoOr<&'a LengthPercentage>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Serialize)]
|
#[derive(Clone, Copy, Serialize)]
|
||||||
|
|
|
@ -624,14 +624,19 @@ fn size_to_length(size: &Size) -> LengthPercentageOrAuto {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait Clamp: Sized {
|
pub(crate) trait Clamp: Sized {
|
||||||
|
fn clamp_below_max(self, max: Option<Self>) -> Self;
|
||||||
fn clamp_between_extremums(self, min: Self, max: Option<Self>) -> Self;
|
fn clamp_between_extremums(self, min: Self, max: Option<Self>) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clamp for Au {
|
impl Clamp for Au {
|
||||||
fn clamp_between_extremums(self, min: Self, max: Option<Self>) -> Self {
|
fn clamp_below_max(self, max: Option<Self>) -> Self {
|
||||||
match max {
|
match max {
|
||||||
Some(max_value) => self.min(max_value).max(min),
|
None => self,
|
||||||
None => self.max(min),
|
Some(max) => self.min(max),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clamp_between_extremums(self, min: Self, max: Option<Self>) -> Self {
|
||||||
|
self.clamp_below_max(max).max(min)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue