Match grid replaced sizing semantics

This commit is contained in:
SGavrl committed 2026-08-03 12:35:09 +00:00
1 parent c678af5bf4
commit d5857fc889
12 files changed
+755 -97

No files matched your search

+23 -6
View File
@@ -19,6 +19,11 @@ use super::common::alignment::apply_alignment_fallback;
#[cfg(feature = "content_size")]
use super::common::content_size::compute_content_size_contribution;
#[inline]
fn resolve_flex_normal(alignment: AlignSelf) -> AlignSelf {
if alignment.keyword == AlignItemsKeyword::Normal { AlignSelf::STRETCH } else { alignment }
}
/// The intermediate results of a flexbox calculation for a single item
struct FlexItem {
/// The identifier for the associated node
@@ -451,7 +456,7 @@ fn compute_constants(
let box_sizing_adjustment =
if style.box_sizing() == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO };
let align_items = style.align_items().unwrap_or(AlignItems::STRETCH);
let align_items = resolve_flex_normal(style.align_items().unwrap_or(AlignItems::STRETCH));
let align_content = style.align_content().unwrap_or(AlignContent::STRETCH);
let justify_content = style.justify_content();
let layout_direction = style.direction();
@@ -569,7 +574,7 @@ fn generate_anonymous_flex_items(
border: child_style
.border()
.resolve_or_zero(constants.node_inner_size.width, |val, basis| tree.calc(val, basis)),
align_self: child_style.align_self().unwrap_or(constants.align_items),
align_self: resolve_flex_normal(child_style.align_self().unwrap_or(constants.align_items)),
overflow: child_style.overflow(),
scrollbar_width: child_style.scrollbar_width(),
flex_grow: child_style.flex_grow(),
@@ -1847,7 +1852,7 @@ fn align_flex_items_along_cross_axis(
}
}
}
AlignItemsKeyword::Stretch => {
AlignItemsKeyword::Normal | AlignItemsKeyword::Stretch => {
if constants.is_wrap_reverse ^ cross_axis_should_reverse {
free_space
} else {
@@ -2182,7 +2187,7 @@ fn perform_absolute_layout_on_absolute_children(
let overflow = child_style.overflow();
let scrollbar_width = child_style.scrollbar_width();
let aspect_ratio = child_style.aspect_ratio();
let align_self = child_style.align_self().unwrap_or(constants.align_items);
let align_self = resolve_flex_normal(child_style.align_self().unwrap_or(constants.align_items));
let margin = child_style
.margin()
.map(|margin| margin.resolve_to_option(inset_relative_size.width, |val, basis| tree.calc(val, basis)));
@@ -2453,11 +2458,23 @@ fn perform_absolute_layout_on_absolute_children(
(AlignItemsKeyword::End, true) => {
constants.content_box_inset.cross_start(constants.dir) + resolved_margin.cross_start(constants.dir)
}
(AlignItemsKeyword::Baseline | AlignItemsKeyword::Stretch | AlignItemsKeyword::FlexStart, false)
(
AlignItemsKeyword::Normal
| AlignItemsKeyword::Baseline
| AlignItemsKeyword::Stretch
| AlignItemsKeyword::FlexStart,
false,
)
| (AlignItemsKeyword::FlexEnd, true) => {
constants.content_box_inset.cross_start(constants.dir) + resolved_margin.cross_start(constants.dir)
}
(AlignItemsKeyword::Baseline | AlignItemsKeyword::Stretch | AlignItemsKeyword::FlexStart, true)
(
AlignItemsKeyword::Normal
| AlignItemsKeyword::Baseline
| AlignItemsKeyword::Stretch
| AlignItemsKeyword::FlexStart,
true,
)
| (AlignItemsKeyword::FlexEnd, false) => {
constants.container_size.cross(constants.dir)
- constants.content_box_inset.cross_end(constants.dir)
+187 -30
View File
@@ -103,11 +103,12 @@ pub(super) fn align_and_position_item(
let box_sizing_adjustment =
if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };
let aspect_ratio_adjustment =
if style.aspect_ratio_uses_content_box() { padding_border_size } else { box_sizing_adjustment };
let inherent_size = style
.size()
.maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let min_size = style
.min_size()
@@ -122,26 +123,15 @@ pub(super) fn align_and_position_item(
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
// Resolve default alignment styles if they are set on neither the parent or the node itself
// Note: if the child has a preferred aspect ratio but neither width or height are set, then the width is stretched
// and the then height is calculated from the width according the aspect ratio
// See: https://www.w3.org/TR/css-grid-1/#grid-item-sizing
let alignment_styles = InBothAbsAxis {
horizontal: justify_self.or(container_alignment_styles.horizontal).unwrap_or_else(|| {
if inherent_size.width.is_some() {
AlignSelf::START
} else {
AlignSelf::STRETCH
}
}),
vertical: align_self.or(container_alignment_styles.vertical).unwrap_or_else(|| {
if inherent_size.height.is_some() || aspect_ratio.is_some() {
AlignSelf::START
} else {
AlignSelf::STRETCH
}
}),
};
// Preserve `normal` provenance until both axes and the preferred aspect
// ratio are known. Explicit stretch in one axis can make the other normal
// axis ratio-derived, while two normal axes prefer inline-axis stretch.
let alignment_styles = super::resolve_item_alignment(
justify_self.or(container_alignment_styles.horizontal).unwrap_or(AlignSelf::NORMAL),
align_self.or(container_alignment_styles.vertical).unwrap_or(AlignSelf::NORMAL),
style.is_compressible_replaced(),
aspect_ratio.is_some(),
);
// Note: This is not a bug. It is part of the CSS spec that both horizontal and vertical margins
// resolve against the WIDTH of the grid area.
@@ -179,10 +169,7 @@ pub(super) fn align_and_position_item(
None
});
// Reapply aspect ratio after stretch and absolute position width adjustments
let Size { width, height } = Size { width, height: inherent_size.height }.maybe_apply_aspect_ratio(aspect_ratio);
let height = height.or_else(|| {
let height = inherent_size.height.or_else(|| {
if position == Position::Absolute {
if let (Some(top), Some(bottom)) = (inset_vertical.start, inset_vertical.end) {
return Some(f32_max(grid_area_minus_item_margins_size.height - top - bottom, 0.0));
@@ -203,8 +190,12 @@ pub(super) fn align_and_position_item(
None
});
// Reapply aspect ratio after stretch and absolute position height adjustments
let Size { width, height } = Size { width, height }.maybe_apply_aspect_ratio(aspect_ratio);
// Stretch is resolved before preferred-ratio transfer. If both axes are
// stretched (or otherwise definite), the ratio does not overwrite either
// one. If only one axis is definite, it supplies the other through the
// ratio. This matches replaced grid sizing in Blink and Gecko.
let Size { width, height } =
super::apply_preferred_aspect_ratio(Size { width, height }, aspect_ratio, aspect_ratio_adjustment);
// Clamp size by min and max width/height
let Size { width, height } = Size { width, height }.maybe_clamp(min_size, max_size);
@@ -290,7 +281,7 @@ pub(super) fn align_and_position_item(
let (x, x_margin) = align_item_within_area(
Line { start: grid_area.left, end: grid_area.right },
justify_self.unwrap_or(alignment_styles.horizontal),
alignment_styles.horizontal,
width,
position,
inset_horizontal,
@@ -300,7 +291,7 @@ pub(super) fn align_and_position_item(
);
let (y, y_margin) = align_item_within_area(
Line { start: grid_area.top, end: grid_area.bottom },
align_self.unwrap_or(alignment_styles.vertical),
alignment_styles.vertical,
height,
position,
inset_vertical,
@@ -388,7 +379,8 @@ pub(super) fn align_item_within_area(
// Compute offset in the axis
let alignment_based_offset = match alignment_keyword {
// TODO: Add support for baseline alignment. For now we treat it as "start".
AlignItemsKeyword::Start
AlignItemsKeyword::Normal
| AlignItemsKeyword::Start
| AlignItemsKeyword::FlexStart
| AlignItemsKeyword::Baseline
| AlignItemsKeyword::Stretch => {
@@ -444,6 +436,7 @@ pub(super) fn align_item_within_area(
mod tests {
use super::{f32_max, f32_min};
use crate::prelude::*;
use crate::Point;
#[derive(Clone, Copy)]
struct IntrinsicInlineSize {
@@ -467,6 +460,46 @@ mod tests {
Size { width, height: known_dimensions.height.unwrap_or(10.0) }
}
#[derive(Clone, Copy)]
struct ReplacedIntrinsicSize {
width: f32,
height: f32,
}
fn measure_replaced_child(
known_dimensions: Size<Option<f32>>,
_available_space: Size<AvailableSpace>,
_node: NodeId,
context: Option<&mut ReplacedIntrinsicSize>,
_style: &Style,
) -> Size<f32> {
let intrinsic = context.copied().unwrap_or(ReplacedIntrinsicSize { width: 0.0, height: 0.0 });
let ratio = intrinsic.width / intrinsic.height;
match known_dimensions {
Size { width: Some(width), height: Some(height) } => Size { width, height },
Size { width: Some(width), height: None } => Size { width, height: width / ratio },
Size { width: None, height: Some(height) } => Size { width: height * ratio, height },
Size { width: None, height: None } => Size { width: intrinsic.width, height: intrinsic.height },
}
}
fn layout_replaced_grid_item(mut item_style: Style, mut root_style: Style) -> (Point<f32>, Size<f32>) {
let mut tree = TaffyTree::new();
tree.disable_rounding();
item_style.aspect_ratio = Some(2.0);
let item = tree
.new_leaf_with_context(item_style, ReplacedIntrinsicSize { width: 100.0, height: 50.0 })
.unwrap();
root_style.display = Display::Grid;
root_style.size = Size { width: length(300.0), height: length(200.0) };
root_style.grid_template_columns = vec![length(300.0)];
root_style.grid_template_rows = vec![length(200.0)];
let root = tree.new_with_children(root_style, &[item]).unwrap();
tree.compute_layout_with_measure(root, Size::MAX_CONTENT, measure_replaced_child).unwrap();
let layout = tree.layout(item).unwrap();
(layout.location, layout.size)
}
fn inline_margins(left_auto: bool, right_auto: bool) -> Rect<LengthPercentageAuto> {
Rect {
left: if left_auto { auto() } else { zero() },
@@ -626,6 +659,130 @@ mod tests {
assert_eq!(content_box_max, 290.0);
}
#[test]
fn grid_normal_uses_natural_replaced_size_but_stretches_ordinary_items() {
let (_, replaced) = layout_replaced_grid_item(
Style { item_is_replaced: true, ..Style::default() },
Style::default(),
);
assert_eq!(replaced, Size { width: 100.0, height: 50.0 });
let (_, ordinary) = layout_replaced_grid_item(Style::default(), Style::default());
assert_eq!(ordinary, Size { width: 300.0, height: 150.0 });
}
#[test]
fn ordinary_grid_aspect_ratio_preserves_normal_alignment_provenance() {
let cases = [
(None, None, None, None, Size { width: 300.0, height: 150.0 }),
(None, Some(AlignSelf::STRETCH), None, None, Size { width: 400.0, height: 200.0 }),
(Some(AlignSelf::STRETCH), None, None, None, Size { width: 300.0, height: 150.0 }),
(
Some(AlignSelf::STRETCH),
Some(AlignSelf::STRETCH),
None,
None,
Size { width: 300.0, height: 200.0 },
),
(None, Some(AlignSelf::START), None, None, Size { width: 300.0, height: 150.0 }),
(Some(AlignSelf::START), None, None, None, Size { width: 400.0, height: 200.0 }),
(None, None, Some(AlignItems::STRETCH), None, Size { width: 400.0, height: 200.0 }),
(None, None, None, Some(AlignItems::STRETCH), Size { width: 300.0, height: 150.0 }),
];
for (justify_self, align_self, align_items, justify_items, expected) in cases {
let (_, actual) = layout_replaced_grid_item(
Style { justify_self, align_self, ..Style::default() },
Style { align_items, justify_items, ..Style::default() },
);
assert_eq!(actual, expected, "justify={justify_self:?}, align={align_self:?}");
}
}
#[test]
fn replaced_grid_normal_applies_percentage_minimums_without_implicit_stretch() {
let (_, inline_min) = layout_replaced_grid_item(
Style {
item_is_replaced: true,
min_size: Size { width: percent(0.5), height: Dimension::auto() },
..Style::default()
},
Style::default(),
);
assert_eq!(inline_min, Size { width: 150.0, height: 75.0 });
let (_, block_min) = layout_replaced_grid_item(
Style {
item_is_replaced: true,
min_size: Size { width: Dimension::auto(), height: percent(0.5) },
..Style::default()
},
Style::default(),
);
assert_eq!(block_min, Size { width: 200.0, height: 100.0 });
}
#[test]
fn replaced_grid_explicit_stretch_precedes_aspect_ratio_transfer() {
let base = Style { item_is_replaced: true, ..Style::default() };
let (_, inline_stretch) = layout_replaced_grid_item(
Style { justify_self: Some(AlignSelf::STRETCH), ..base.clone() },
Style::default(),
);
assert_eq!(inline_stretch, Size { width: 300.0, height: 150.0 });
let (_, block_stretch) = layout_replaced_grid_item(
Style { align_self: Some(AlignSelf::STRETCH), ..base.clone() },
Style::default(),
);
assert_eq!(block_stretch, Size { width: 400.0, height: 200.0 });
let (_, both_stretch) = layout_replaced_grid_item(
Style {
justify_self: Some(AlignSelf::STRETCH),
align_self: Some(AlignSelf::STRETCH),
..base.clone()
},
Style::default(),
);
assert_eq!(both_stretch, Size { width: 300.0, height: 200.0 });
let (_, definite_inline) = layout_replaced_grid_item(
Style {
size: Size { width: length(120.0), height: Dimension::auto() },
align_self: Some(AlignSelf::STRETCH),
..base.clone()
},
Style::default(),
);
assert_eq!(definite_inline, Size { width: 120.0, height: 200.0 });
let (_, definite_block) = layout_replaced_grid_item(
Style {
size: Size { width: Dimension::auto(), height: length(80.0) },
justify_self: Some(AlignSelf::STRETCH),
..base
},
Style::default(),
);
assert_eq!(definite_block, Size { width: 300.0, height: 80.0 });
}
#[test]
fn replaced_grid_normal_and_auto_margins_remain_natural() {
let (location, size) = layout_replaced_grid_item(
Style {
item_is_replaced: true,
min_size: Size { width: percent(0.5), height: Dimension::auto() },
margin: Rect { left: auto(), right: zero(), top: zero(), bottom: zero() },
..Style::default()
},
Style { justify_items: Some(AlignItems::NORMAL), ..Style::default() },
);
assert_eq!(size, Size { width: 150.0, height: 75.0 });
assert_eq!(location.x, 150.0);
}
#[test]
fn overflowing_auto_margins_override_unsafe_self_alignment() {
let area = Line { start: 0.0, end: 300.0 };
+76 -2
View File
@@ -34,6 +34,80 @@ mod track_sizing;
mod types;
mod util;
/// Resolve grid item `normal` alignment without losing the authored/default
/// provenance needed by preferred-aspect-ratio sizing. With an aspect ratio,
/// one implicit stretch axis supplies the other; an explicit alignment in the
/// opposite axis decides which implicit axis remains stretchable.
#[inline]
fn resolve_item_alignment(
horizontal: AlignSelf,
vertical: AlignSelf,
is_compressible_replaced: bool,
has_preferred_aspect_ratio: bool,
) -> InBothAbsAxis<AlignSelf> {
if is_compressible_replaced {
return InBothAbsAxis {
horizontal: horizontal.resolve_normal(AlignSelf::START),
vertical: vertical.resolve_normal(AlignSelf::START),
};
}
if !has_preferred_aspect_ratio {
return InBothAbsAxis {
horizontal: horizontal.resolve_normal(AlignSelf::STRETCH),
vertical: vertical.resolve_normal(AlignSelf::STRETCH),
};
}
let horizontal_is_normal = horizontal == AlignSelf::NORMAL;
let vertical_is_normal = vertical == AlignSelf::NORMAL;
InBothAbsAxis {
horizontal: if horizontal_is_normal {
if !vertical_is_normal && vertical == AlignSelf::STRETCH {
AlignSelf::START
} else {
AlignSelf::STRETCH
}
} else {
horizontal
},
vertical: if vertical_is_normal {
if !horizontal_is_normal && horizontal != AlignSelf::STRETCH {
AlignSelf::STRETCH
} else {
AlignSelf::START
}
} else {
vertical
},
}
}
#[inline]
fn apply_preferred_aspect_ratio(
size: Size<Option<f32>>,
aspect_ratio: Option<f32>,
box_sizing_adjustment: Size<f32>,
) -> Size<Option<f32>> {
let Some(aspect_ratio) = aspect_ratio else { return size };
match size {
Size { width: Some(width), height: None } => Size {
width: Some(width),
height: Some(
f32_max(width - box_sizing_adjustment.width, 0.0) / aspect_ratio
+ box_sizing_adjustment.height,
),
},
Size { width: None, height: Some(height) } => Size {
width: Some(
f32_max(height - box_sizing_adjustment.height, 0.0) * aspect_ratio
+ box_sizing_adjustment.width,
),
height: Some(height),
},
_ => size,
}
}
/// Grid layout algorithm
/// This consists of a few phases:
/// - Resolving the explicit grid
@@ -225,8 +299,8 @@ pub fn compute_grid_layout<Tree: LayoutGridContainer>(
in_flow_children_iter,
direction,
style.grid_auto_flow(),
align_items.unwrap_or(AlignItems::STRETCH),
justify_items.unwrap_or(AlignItems::STRETCH),
align_items.unwrap_or(AlignItems::NORMAL),
justify_items.unwrap_or(AlignItems::NORMAL),
&name_resolver,
);
+30 -11
View File
@@ -45,6 +45,8 @@ pub(in super::super) struct GridItem {
pub max_size: Size<Dimension>,
/// The item's aspect_ratio style
pub aspect_ratio: Option<f32>,
/// Intrinsic ratios apply to the content box even under border-box sizing.
pub aspect_ratio_uses_content_box: bool,
/// The item's padding style
pub padding: Rect<LengthPercentage>,
/// The item's border style
@@ -104,12 +106,13 @@ impl GridItem {
parent_justify_items: AlignItems,
source_order: u16,
) -> Self {
let is_compressible_replaced = style.is_compressible_replaced();
GridItem {
node,
source_order,
row: row_span,
column: col_span,
is_compressible_replaced: style.is_compressible_replaced(),
is_compressible_replaced,
intrinsic_size_containment: style.intrinsic_size_containment(),
overflow: style.overflow(),
box_sizing: style.box_sizing(),
@@ -117,6 +120,7 @@ impl GridItem {
min_size: style.min_size(),
max_size: style.max_size(),
aspect_ratio: style.aspect_ratio(),
aspect_ratio_uses_content_box: style.aspect_ratio_uses_content_box(),
padding: style.padding(),
border: style.border(),
margin: style.margin(),
@@ -263,10 +267,14 @@ impl GridItem {
let padding_border_size = (padding + border).sum_axes();
let box_sizing_adjustment =
if self.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };
let aspect_ratio_adjustment = if self.aspect_ratio_uses_content_box {
padding_border_size
} else {
box_sizing_adjustment
};
let inherent_size = self
.size
.maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let min_size = self
.min_size
@@ -280,6 +288,12 @@ impl GridItem {
.maybe_add(box_sizing_adjustment);
let grid_area_minus_item_margins_size = grid_area_size.maybe_sub(margins);
let alignment = super::super::resolve_item_alignment(
self.justify_self,
self.align_self,
self.is_compressible_replaced,
aspect_ratio.is_some(),
);
// If node is absolutely positioned and width is not set explicitly, then deduce it
// from left, right and container_content_box if both are set.
@@ -288,29 +302,34 @@ impl GridItem {
// - Alignment style is "stretch"
// - The node is not absolutely positioned
// - The node does not have auto margins in this axis.
if !self.margin.left.is_auto() && !self.margin.right.is_auto() && self.justify_self == AlignSelf::STRETCH {
if !self.margin.left.is_auto()
&& !self.margin.right.is_auto()
&& alignment.horizontal == AlignSelf::STRETCH
{
return grid_area_minus_item_margins_size.width;
}
None
});
// Reapply aspect ratio after stretch and absolute position width adjustments
let Size { width, height } =
Size { width, height: inherent_size.height }.maybe_apply_aspect_ratio(aspect_ratio);
let height = height.or_else(|| {
let height = inherent_size.height.or_else(|| {
// Apply height based on stretch alignment if:
// - Alignment style is "stretch"
// - The node is not absolutely positioned
// - The node does not have auto margins in this axis.
if !self.margin.top.is_auto() && !self.margin.bottom.is_auto() && self.align_self == AlignSelf::STRETCH {
if !self.margin.top.is_auto()
&& !self.margin.bottom.is_auto()
&& alignment.vertical == AlignSelf::STRETCH
{
return grid_area_minus_item_margins_size.height;
}
None
});
// Reapply aspect ratio after stretch and absolute position height adjustments
let Size { width, height } = Size { width, height }.maybe_apply_aspect_ratio(aspect_ratio);
let Size { width, height } = super::super::apply_preferred_aspect_ratio(
Size { width, height },
aspect_ratio,
aspect_ratio_adjustment,
);
// Clamp size by min and max width/height
let Size { width, height } = Size { width, height }.maybe_clamp(min_size, max_size);
+14
View File
@@ -20,6 +20,8 @@ use crate::util::parse::{CssParseResult, FromCss, Parser, Token};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum AlignItemsKeyword {
/// Use the layout mode's normal alignment behavior.
Normal,
/// Items are packed toward the start of the axis.
Start,
/// Items are packed toward the end of the axis.
@@ -131,6 +133,8 @@ pub struct AlignItems {
}
impl AlignItems {
/// Use the layout mode's normal alignment behavior.
pub const NORMAL: Self = Self { keyword: AlignItemsKeyword::Normal, safety: AlignmentSafety::Unsafe };
/// Items are packed toward the start of the axis.
pub const START: Self = Self { keyword: AlignItemsKeyword::Start, safety: AlignmentSafety::Unsafe };
/// Items are packed toward the end of the axis.
@@ -172,6 +176,12 @@ impl AlignItems {
pub const fn keyword(self) -> AlignItemsKeyword {
self.keyword
}
/// Resolve the context-dependent `normal` keyword to its used alignment.
#[inline]
pub const fn resolve_normal(self, normal: Self) -> Self {
if matches!(self.keyword, AlignItemsKeyword::Normal) { normal } else { self }
}
}
#[cfg(feature = "parse")]
@@ -201,6 +211,7 @@ impl FromCss for AlignItems {
_ => Err(input.new_unexpected_token_error(Token::Ident(pos))),
}
},
"normal" => Ok(Self::NORMAL),
"start" => Ok(Self::START),
"end" => Ok(Self::END),
"flex-start" => Ok(Self::FLEX_START),
@@ -362,6 +373,7 @@ pub type JustifyContent = AlignContent;
/// `unknown_variant` errors. Mirrors the spellings produced by `Serialize`.
#[cfg(feature = "serde")]
const ALIGN_ITEMS_NAMES: &[&str] = &[
"Normal",
"Start",
"End",
"FlexStart",
@@ -380,6 +392,7 @@ const ALIGN_ITEMS_NAMES: &[&str] = &[
impl serde::Serialize for AlignItems {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let name = match (self.keyword, self.safety) {
(AlignItemsKeyword::Normal, _) => "Normal",
(AlignItemsKeyword::Start, AlignmentSafety::Unsafe) => "Start",
(AlignItemsKeyword::End, AlignmentSafety::Unsafe) => "End",
(AlignItemsKeyword::FlexStart, AlignmentSafety::Unsafe) => "FlexStart",
@@ -408,6 +421,7 @@ impl<'de> serde::Deserialize<'de> for AlignItems {
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(match v {
"Normal" => AlignItems::NORMAL,
"Start" => AlignItems::START,
"End" => AlignItems::END,
"FlexStart" => AlignItems::FLEX_START,
+18
View File
@@ -99,6 +99,12 @@ pub trait CoreStyle {
fn is_compressible_replaced(&self) -> bool {
false
}
/// Whether the preferred aspect ratio is intrinsic and therefore always
/// applies to the content box, independently of `box-sizing`.
#[inline(always)]
fn aspect_ratio_uses_content_box(&self) -> bool {
false
}
/// Which box do size styles apply to
#[inline(always)]
fn box_sizing(&self) -> BoxSizing {
@@ -442,6 +448,8 @@ pub struct Style<S: CheapCloneStr = DefaultCheapStr> {
/// Is it a replaced element like an image or form field?
/// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
pub item_is_replaced: bool,
/// Whether `aspect_ratio` came from intrinsic media metadata.
pub item_aspect_ratio_is_intrinsic: bool,
/// Whether descendants are ignored for intrinsic size contributions in each axis.
///
/// Ordinary final layout is unaffected, allowing an auto-sized grid item to
@@ -596,6 +604,7 @@ impl<S: CheapCloneStr> Style<S> {
display: Display::DEFAULT,
item_is_table: false,
item_is_replaced: false,
item_aspect_ratio_is_intrinsic: false,
intrinsic_size_containment: Size { width: false, height: false },
box_sizing: BoxSizing::BorderBox,
direction: Direction::Ltr,
@@ -693,6 +702,10 @@ impl<S: CheapCloneStr> CoreStyle for Style<S> {
self.item_is_replaced
}
#[inline(always)]
fn aspect_ratio_uses_content_box(&self) -> bool {
self.item_aspect_ratio_is_intrinsic
}
#[inline(always)]
fn box_sizing(&self) -> BoxSizing {
self.box_sizing
}
@@ -762,6 +775,10 @@ impl<T: CoreStyle> CoreStyle for &'_ T {
(*self).is_compressible_replaced()
}
#[inline(always)]
fn aspect_ratio_uses_content_box(&self) -> bool {
(*self).aspect_ratio_uses_content_box()
}
#[inline(always)]
fn box_sizing(&self) -> BoxSizing {
(*self).box_sizing()
}
@@ -1222,6 +1239,7 @@ mod tests {
display: Default::default(),
item_is_table: false,
item_is_replaced: false,
item_aspect_ratio_is_intrinsic: false,
intrinsic_size_containment: Size { width: false, height: false },
box_sizing: Default::default(),
#[cfg(feature = "float_layout")]