mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
layout: Implement the fit-content()
sizing function (#36056)
Spec: https://drafts.csswg.org/css-sizing-3/#funcdef-width-fit-content It's similar to the `fit-content` keyword but, instead of clamping the stretch size between `min-content` and `max-content`, it clamps the provided argument. So now that we support `fit-content`, it's quite straightforward to add. It's just not completely clear what should happen when the argument has a cyclic percentage, so this may need some further adjustments depending on the outcome of https://github.com/w3c/csswg-drafts/issues/11805 Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
3a356ffb74
commit
8c2ac88ad0
33 changed files with 100 additions and 192 deletions
|
@ -2599,11 +2599,8 @@ impl FlexItemBox {
|
|||
BoxSizing::BorderBox => length - main_padding_border_sum,
|
||||
}
|
||||
};
|
||||
size.maybe_map(|v| {
|
||||
v.maybe_to_used_value(container_definite_main_size)
|
||||
.map(apply_box_sizing)
|
||||
})
|
||||
.unwrap_or_default()
|
||||
size.resolve_percentages_for_preferred(container_definite_main_size)
|
||||
.map(apply_box_sizing)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -2144,9 +2144,11 @@ impl<'container> PlacementState<'container> {
|
|||
|
||||
fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &ContainingBlock) -> bool {
|
||||
match size {
|
||||
StyleSize::Auto | StyleSize::MinContent | StyleSize::MaxContent | StyleSize::FitContent => {
|
||||
true
|
||||
},
|
||||
StyleSize::Auto |
|
||||
StyleSize::MinContent |
|
||||
StyleSize::MaxContent |
|
||||
StyleSize::FitContent |
|
||||
StyleSize::FitContentFunction(_) => true,
|
||||
StyleSize::Stretch => {
|
||||
// TODO: Should this return true when the containing block has a definite size of 0px?
|
||||
!containing_block.size.block.is_definite()
|
||||
|
|
|
@ -133,6 +133,17 @@ impl<T: Clone> LogicalVec2<T> {
|
|||
block: f(&self.block),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn map_with<U, V>(
|
||||
&self,
|
||||
other: &LogicalVec2<U>,
|
||||
f: impl Fn(&T, &U) -> V,
|
||||
) -> LogicalVec2<V> {
|
||||
LogicalVec2 {
|
||||
inline: f(&self.inline, &other.inline),
|
||||
block: f(&self.block, &other.block),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Add<Output = T> + Copy> Add<LogicalVec2<T>> for LogicalVec2<T> {
|
||||
|
@ -697,6 +708,8 @@ pub(crate) enum Size<T> {
|
|||
MaxContent,
|
||||
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-fit-content>
|
||||
FitContent,
|
||||
/// <https://drafts.csswg.org/css-sizing-3/#funcdef-width-fit-content>
|
||||
FitContentFunction(T),
|
||||
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-stretch>
|
||||
Stretch,
|
||||
/// Represents a numeric `<length-percentage>`, but resolved as a `T`.
|
||||
|
@ -730,34 +743,28 @@ impl<T: Clone> Size<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn map<U>(&self, f: impl FnOnce(T) -> U) -> Size<U> {
|
||||
pub(crate) fn map<U>(&self, f: impl FnOnce(T) -> U) -> Size<U> {
|
||||
match self {
|
||||
Size::Initial => Size::Initial,
|
||||
Size::MinContent => Size::MinContent,
|
||||
Size::MaxContent => Size::MaxContent,
|
||||
Size::FitContent => Size::FitContent,
|
||||
Size::FitContentFunction(size) => Size::FitContentFunction(f(size.clone())),
|
||||
Size::Stretch => Size::Stretch,
|
||||
Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn maybe_map<U>(&self, f: impl FnOnce(T) -> Option<U>) -> Option<Size<U>> {
|
||||
Some(match self {
|
||||
Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())?),
|
||||
_ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StyleSize> for Size<LengthPercentage> {
|
||||
fn from(size: StyleSize) -> Self {
|
||||
match size {
|
||||
StyleSize::LengthPercentage(length) => Size::Numeric(length.0),
|
||||
StyleSize::LengthPercentage(lp) => Size::Numeric(lp.0),
|
||||
StyleSize::Auto => Size::Initial,
|
||||
StyleSize::MinContent => Size::MinContent,
|
||||
StyleSize::MaxContent => Size::MaxContent,
|
||||
StyleSize::FitContent => Size::FitContent,
|
||||
StyleSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0),
|
||||
StyleSize::Stretch => Size::Stretch,
|
||||
StyleSize::AnchorSizeFunction(_) => unreachable!("anchor-size() should be disabled"),
|
||||
}
|
||||
|
@ -767,11 +774,12 @@ impl From<StyleSize> for Size<LengthPercentage> {
|
|||
impl From<StyleMaxSize> for Size<LengthPercentage> {
|
||||
fn from(max_size: StyleMaxSize) -> Self {
|
||||
match max_size {
|
||||
StyleMaxSize::LengthPercentage(length) => Size::Numeric(length.0),
|
||||
StyleMaxSize::LengthPercentage(lp) => Size::Numeric(lp.0),
|
||||
StyleMaxSize::None => Size::Initial,
|
||||
StyleMaxSize::MinContent => Size::MinContent,
|
||||
StyleMaxSize::MaxContent => Size::MaxContent,
|
||||
StyleMaxSize::FitContent => Size::FitContent,
|
||||
StyleMaxSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0),
|
||||
StyleMaxSize::Stretch => Size::Stretch,
|
||||
StyleMaxSize::AnchorSizeFunction(_) => unreachable!("anchor-size() should be disabled"),
|
||||
}
|
||||
|
@ -784,25 +792,49 @@ impl Size<LengthPercentage> {
|
|||
self.to_numeric()
|
||||
.and_then(|length_percentage| length_percentage.to_percentage())
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<Size<LengthPercentage>> {
|
||||
pub(crate) fn maybe_percentages_relative_to_basis(
|
||||
&self,
|
||||
basis: &LogicalVec2<Option<Au>>,
|
||||
) -> LogicalVec2<Size<Au>> {
|
||||
LogicalVec2 {
|
||||
inline: self
|
||||
.inline
|
||||
.maybe_map(|v| v.maybe_to_used_value(basis.inline))
|
||||
.unwrap_or_default(),
|
||||
block: self
|
||||
.block
|
||||
.maybe_map(|v| v.maybe_to_used_value(basis.block))
|
||||
.unwrap_or_default(),
|
||||
/// Resolves percentages in a preferred size, against the provided basis.
|
||||
/// If the basis is missing, percentages are considered cyclic.
|
||||
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
||||
/// <https://www.w3.org/TR/css-sizing-3/#cyclic-percentage-size>
|
||||
#[inline]
|
||||
pub(crate) fn resolve_percentages_for_preferred(&self, basis: Option<Au>) -> Size<Au> {
|
||||
match self {
|
||||
Size::Numeric(numeric) => numeric
|
||||
.maybe_to_used_value(basis)
|
||||
.map_or(Size::Initial, Size::Numeric),
|
||||
Size::FitContentFunction(numeric) => {
|
||||
// Under discussion in https://github.com/w3c/csswg-drafts/issues/11805
|
||||
numeric
|
||||
.maybe_to_used_value(basis)
|
||||
.map_or(Size::FitContent, Size::FitContentFunction)
|
||||
},
|
||||
_ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves percentages in a maximum size, against the provided basis.
|
||||
/// If the basis is missing, percentages are considered cyclic.
|
||||
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
||||
/// <https://www.w3.org/TR/css-sizing-3/#cyclic-percentage-size>
|
||||
#[inline]
|
||||
pub(crate) fn resolve_percentages_for_max(&self, basis: Option<Au>) -> Size<Au> {
|
||||
match self {
|
||||
Size::Numeric(numeric) => numeric
|
||||
.maybe_to_used_value(basis)
|
||||
.map_or(Size::Initial, Size::Numeric),
|
||||
Size::FitContentFunction(numeric) => {
|
||||
// Under discussion in https://github.com/w3c/csswg-drafts/issues/11805
|
||||
numeric
|
||||
.maybe_to_used_value(basis)
|
||||
.map_or(Size::MaxContent, Size::FitContentFunction)
|
||||
},
|
||||
_ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicalVec2<Size<LengthPercentage>> {
|
||||
pub(crate) fn percentages_relative_to_basis(
|
||||
&self,
|
||||
basis: &LogicalVec2<Au>,
|
||||
|
@ -831,6 +863,7 @@ impl Size<Au> {
|
|||
},
|
||||
Self::MinContent => content_size.min_content,
|
||||
Self::MaxContent => content_size.max_content,
|
||||
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
||||
Self::FitContent => {
|
||||
content_size.shrink_to_fit(stretch_size.unwrap_or_else(|| content_size.max_content))
|
||||
},
|
||||
|
@ -852,6 +885,7 @@ impl Size<Au> {
|
|||
Self::Initial => get_automatic_minimum_size(),
|
||||
Self::MinContent => content_size.min_content,
|
||||
Self::MaxContent => content_size.max_content,
|
||||
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
||||
Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or_default()),
|
||||
Self::Stretch => stretch_size.unwrap_or_default(),
|
||||
Self::Numeric(numeric) => *numeric,
|
||||
|
@ -870,6 +904,7 @@ impl Size<Au> {
|
|||
Self::Initial => return None,
|
||||
Self::MinContent => content_size.min_content,
|
||||
Self::MaxContent => content_size.max_content,
|
||||
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
||||
Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or(MAX_AU)),
|
||||
Self::Stretch => return stretch_size,
|
||||
Self::Numeric(numeric) => *numeric,
|
||||
|
@ -888,7 +923,11 @@ impl Size<Au> {
|
|||
#[inline]
|
||||
pub(crate) fn maybe_resolve_extrinsic(&self, stretch_size: Option<Au>) -> Option<Au> {
|
||||
match self {
|
||||
Self::Initial | Self::MinContent | Self::MaxContent | Self::FitContent => None,
|
||||
Self::Initial |
|
||||
Self::MinContent |
|
||||
Self::MaxContent |
|
||||
Self::FitContent |
|
||||
Self::FitContentFunction(_) => None,
|
||||
Self::Stretch => stretch_size,
|
||||
Self::Numeric(numeric) => Some(*numeric),
|
||||
}
|
||||
|
|
|
@ -191,6 +191,10 @@ pub(crate) fn outer_inline(
|
|||
content_size.sizes.max_content,
|
||||
content_size.depends_on_block_constraints,
|
||||
),
|
||||
Size::FitContentFunction(size) => {
|
||||
let size = content_size.sizes.shrink_to_fit(size);
|
||||
(size, size, content_size.depends_on_block_constraints)
|
||||
},
|
||||
Size::Stretch => return stretch_values,
|
||||
})
|
||||
};
|
||||
|
|
|
@ -1014,18 +1014,16 @@ impl LayoutStyle<'_> {
|
|||
depends_on_block_constraints(&max_size.block) ||
|
||||
style.depends_on_block_constraints_due_to_relative_positioning(writing_mode);
|
||||
|
||||
let box_size = box_size.maybe_percentages_relative_to_basis(&containing_block.size);
|
||||
let content_box_size = style
|
||||
.content_box_size_for_box_size(box_size, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let box_size = box_size.map_with(&containing_block.size, |size, basis| {
|
||||
size.resolve_percentages_for_preferred(*basis)
|
||||
});
|
||||
let content_box_size = style.content_box_size_for_box_size(box_size, &pbm);
|
||||
let min_size = min_size.percentages_relative_to_basis(&containing_block_size_or_zero);
|
||||
let content_min_box_size = style
|
||||
.content_min_box_size_for_min_size(min_size, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let max_size = max_size.maybe_percentages_relative_to_basis(&containing_block.size);
|
||||
let content_max_box_size = style
|
||||
.content_max_box_size_for_max_size(max_size, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let content_min_box_size = style.content_min_box_size_for_min_size(min_size, &pbm);
|
||||
let max_size = max_size.map_with(&containing_block.size, |size, basis| {
|
||||
size.resolve_percentages_for_max(*basis)
|
||||
});
|
||||
let content_max_box_size = style.content_max_box_size_for_max_size(max_size, &pbm);
|
||||
ContentBoxSizesAndPBM {
|
||||
content_box_sizes: LogicalVec2 {
|
||||
block: Sizes::new(
|
||||
|
|
|
@ -54,6 +54,7 @@ pub fn dimension(val: &stylo::Size) -> taffy::Dimension {
|
|||
stylo::Size::MaxContent => taffy::Dimension::Auto,
|
||||
stylo::Size::MinContent => taffy::Dimension::Auto,
|
||||
stylo::Size::FitContent => taffy::Dimension::Auto,
|
||||
stylo::Size::FitContentFunction(_) => taffy::Dimension::Auto,
|
||||
stylo::Size::Stretch => taffy::Dimension::Auto,
|
||||
|
||||
// Anchor positioning will be flagged off for time being
|
||||
|
@ -71,6 +72,7 @@ pub fn max_size_dimension(val: &stylo::MaxSize) -> taffy::Dimension {
|
|||
stylo::MaxSize::MaxContent => taffy::Dimension::Auto,
|
||||
stylo::MaxSize::MinContent => taffy::Dimension::Auto,
|
||||
stylo::MaxSize::FitContent => taffy::Dimension::Auto,
|
||||
stylo::MaxSize::FitContentFunction(_) => taffy::Dimension::Auto,
|
||||
stylo::MaxSize::Stretch => taffy::Dimension::Auto,
|
||||
|
||||
// Anchor positioning will be flagged off for time being
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue