Grid: Add support for repeat() with an integer repetition count (#342)
* Add support for repeat() with an integer repetition count
* Add tests for integer repeat
* Fix clippy lints
* Make repeat() helper function accept u16 and 'auto-fit' and 'auto-fill' strings
* Fix typo
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
ebd376fbebd0ba73c79aa00d1835918680ef82a0 · por Nico Burns · 2023-02-03T01:26:04Z (hace 3 años) · padre 2fa6cc64f · ver el árbol en este commit
Delta semántico · 26
benches/generated/grid_repeat_integer.rs
benches/generated/grid_repeat_mixed.rs
src/compute/grid/explicit_grid.rs
tests/generated/grid_repeat_integer.rs
tests/generated/grid_repeat_mixed.rs
diff --git a/benches/generated/grid_repeat_integer.rs b/benches/generated/grid_repeat_integer.rs
new file mode 100644
index 000000000..30cc71e4f
--- /dev/null
+++ b/benches/generated/grid_repeat_integer.rs
@@ -0,0 +1,30 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node7 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node8 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ display: taffy::style::Display::Grid,
+ grid_template_rows: vec![repeat(GridTrackRepetition::Count(3u16), vec![points(40f32)])],
+ grid_template_columns: vec![repeat(GridTrackRepetition::Count(3u16), vec![points(40f32)])],
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(120f32),
+ height: taffy::style::Dimension::Points(120f32),
+ },
+ ..Default::default()
+ },
+ &[node0, node1, node2, node3, node4, node5, node6, node7, node8],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/grid_repeat_mixed.rs b/benches/generated/grid_repeat_mixed.rs
new file mode 100644
index 000000000..dc90474ad
--- /dev/null
+++ b/benches/generated/grid_repeat_mixed.rs
@@ -0,0 +1,38 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node7 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node8 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ display: taffy::style::Display::Grid,
+ grid_template_rows: vec![
+ points(40f32),
+ repeat(GridTrackRepetition::Count(1u16), vec![points(40f32)]),
+ repeat(GridTrackRepetition::AutoFill, vec![points(40f32)]),
+ ],
+ grid_template_columns: vec![
+ points(40f32),
+ repeat(GridTrackRepetition::Count(1u16), vec![points(40f32)]),
+ repeat(GridTrackRepetition::AutoFill, vec![points(40f32)]),
+ ],
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(120f32),
+ height: taffy::style::Dimension::Points(120f32),
+ },
+ ..Default::default()
+ },
+ &[node0, node1, node2, node3, node4, node5, node6, node7, node8],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/mod.rs b/benches/generated/mod.rs
index dcd569813..b83f9958a 100644
--- a/benches/generated/mod.rs
+++ b/benches/generated/mod.rs
@@ -577,6 +577,10 @@ mod grid_placement_definite_in_secondary_axis_with_fully_definite_negative;
#[cfg(feature = "grid")]
mod grid_relayout_vertical_text;
#[cfg(feature = "grid")]
+mod grid_repeat_integer;
+#[cfg(feature = "grid")]
+mod grid_repeat_mixed;
+#[cfg(feature = "grid")]
mod grid_size_child_fixed_tracks;
mod justify_content_column_center;
mod justify_content_column_flex_end;
@@ -1268,6 +1272,10 @@ fn benchmark(c: &mut Criterion) {
#[cfg(feature = "grid")]
grid_relayout_vertical_text::compute();
#[cfg(feature = "grid")]
+ grid_repeat_integer::compute();
+ #[cfg(feature = "grid")]
+ grid_repeat_mixed::compute();
+ #[cfg(feature = "grid")]
grid_size_child_fixed_tracks::compute();
justify_content_column_center::compute();
justify_content_column_flex_end::compute();
diff --git a/scripts/gentest/src/main.rs b/scripts/gentest/src/main.rs
index a8512071d..890fad8de 100644
--- a/scripts/gentest/src/main.rs
+++ b/scripts/gentest/src/main.rs
@@ -797,9 +797,7 @@ fn generate_track_definition(track_definition: &serde_json::Map<String, Value>)
match unit {
"auto-fill" => quote!(GridTrackRepetition::AutoFill),
- // Not yet implemented in taffy
"auto-fit" => quote!(GridTrackRepetition::AutoFit),
- // Not yet implemented in taffy
"integer" => {
let repetition_count = value();
quote!(GridTrackRepetition::Count(#repetition_count))
diff --git a/src/compute/grid/explicit_grid.rs b/src/compute/grid/explicit_grid.rs
index ef85bb389..1bcdb2f24 100644
--- a/src/compute/grid/explicit_grid.rs
+++ b/src/compute/grid/explicit_grid.rs
@@ -19,11 +19,33 @@ pub(crate) fn compute_explicit_grid_size_in_axis(style: &Style, axis: AbsoluteAx
return 0;
}
+ // If there are any repetitions that contains no tracks, then the whole definition should be considered invalid
+ // and we default to no explicit tracks
+ let template_has_repetitions_with_zero_tracks = template.iter().any(|track_def| match track_def {
+ TrackSizingFunction::Single(_) => false,
+ TrackSizingFunction::Repeat(_, tracks) => tracks.is_empty(),
+ });
+ if template_has_repetitions_with_zero_tracks {
+ return 0;
+ }
+
+ // Compute that number of track generated by single track definition and repetitions with a fixed repetition count
+ let non_auto_repeating_track_count = template
+ .iter()
+ .map(|track_def| {
+ use GridTrackRepetition::{AutoFill, AutoFit, Count};
+ match track_def {
+ TrackSizingFunction::Single(_) => 1,
+ TrackSizingFunction::Repeat(Count(count), tracks) => count * tracks.len() as u16,
+ TrackSizingFunction::Repeat(AutoFit | AutoFill, _) => 0,
+ }
+ })
+ .sum::<u16>();
+
let auto_repetition_count = template.iter().filter(|track_def| track_def.is_auto_repetition()).count() as u16;
- let non_repeating_track_count = (template.len() as u16) - auto_repetition_count;
let all_track_defs_have_fixed_component = template.iter().all(|track_def| match track_def {
TrackSizingFunction::Single(sizing_function) => sizing_function.has_fixed_component(),
- TrackSizingFunction::AutoRepeat(_, tracks) => {
+ TrackSizingFunction::Repeat(_, tracks) => {
tracks.iter().all(|sizing_function| sizing_function.has_fixed_component())
}
});
@@ -40,23 +62,22 @@ pub(crate) fn compute_explicit_grid_size_in_axis(style: &Style, axis: AbsoluteAx
// If there are no repetitions, then the number of explicit tracks is simply equal to the lengths of the track definition
// vector (as each item in the Vec represents one track).
if auto_repetition_count == 0 {
- return template.len() as u16;
+ return non_auto_repeating_track_count;
}
let repetition_definition = template
.iter()
- .find_map(|def| match def {
- TrackSizingFunction::Single(_) => None,
- TrackSizingFunction::AutoRepeat(_, tracks) => Some(tracks),
+ .find_map(|def| {
+ use GridTrackRepetition::{AutoFill, AutoFit, Count};
+ match def {
+ TrackSizingFunction::Single(_) => None,
+ TrackSizingFunction::Repeat(Count(_), _) => None,
+ TrackSizingFunction::Repeat(AutoFit | AutoFill, tracks) => Some(tracks),
+ }
})
.unwrap();
let repetition_track_count = repetition_definition.len() as u16;
- // If the repetition contains no tracks, then the whole definition should be considered invalid and we default to no explcit tracks
- if repetition_track_count == 0 {
- return 0u16;
- }
-
// Otherwise, run logic to resolve the auto-repeated track count:
//
// If the grid container has a definite size or max size in the relevant axis:
@@ -93,9 +114,21 @@ pub(crate) fn compute_explicit_grid_size_in_axis(style: &Style, axis: AbsoluteAx
let non_repeating_track_used_space: f32 = template
.iter()
- .map(|track_def| match track_def {
- TrackSizingFunction::Single(sizing_function) => track_definite_value(sizing_function, parent_size),
- TrackSizingFunction::AutoRepeat(_, _) => 0.0,
+ .map(|track_def| {
+ use GridTrackRepetition::{AutoFill, AutoFit, Count};
+ match track_def {
+ TrackSizingFunction::Single(sizing_function) => {
+ track_definite_value(sizing_function, parent_size)
+ }
+ TrackSizingFunction::Repeat(Count(count), repeated_tracks) => {
+ let sum = repeated_tracks
+ .iter()
+ .map(|sizing_function| track_definite_value(sizing_function, parent_size))
+ .sum::<f32>();
+ sum * (*count as f32)
+ }
+ TrackSizingFunction::Repeat(AutoFit | AutoFill, _) => 0.0,
+ }
})
.sum();
let gap_size = style.gap.get_abs(axis).resolve_or_zero(Some(inner_container_size));
@@ -110,7 +143,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis(style: &Style, axis: AbsoluteAx
// depends on the number of non-repeating tracks in the template
let first_repetition_and_non_repeating_tracks_used_space = non_repeating_track_used_space
+ per_repetition_track_used_space
- + ((non_repeating_track_count + repetition_track_count).saturating_sub(1) as f32 * gap_size);
+ + ((non_auto_repeating_track_count + repetition_track_count).saturating_sub(1) as f32 * gap_size);
// If a single repetition already overflows the container then we return 1 as the repetition count
// (the number of repetitions is floored at 1)
@@ -138,7 +171,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis(style: &Style, axis: AbsoluteAx
}
};
- non_repeating_track_count + (repetition_track_count * num_repetitions)
+ non_auto_repeating_track_count + (repetition_track_count * num_repetitions)
}
/// Resolve the track sizing functions of explicit tracks, automatically created tracks, and gutters
@@ -175,31 +208,48 @@ pub(super) fn initialize_grid_tracks(
// An explicit check against the count (rather than just relying on track_template being empty) is required here
// because a count of zero can result from the track_template being invalid, in which case it should be ignored.
if counts.explicit > 0 {
- track_template.iter().for_each(|track_sizing_function| match track_sizing_function {
- TrackSizingFunction::Single(sizing_function) => {
- tracks
- .push(GridTrack::new(sizing_function.min_sizing_function(), sizing_function.max_sizing_function()));
- tracks.push(GridTrack::gutter(gap));
- current_track_index += 1;
- }
- TrackSizingFunction::AutoRepeat(repetition_kind, repeated_tracks) => {
- let auto_repeated_track_count = (counts.explicit - (track_template.len() as u16 - 1)) as usize;
- let iter = repeated_tracks.iter().copied().cycle();
- for track_def in iter.take(auto_repeated_track_count) {
- let mut track = GridTrack::new(track_def.min_sizing_function(), track_def.max_sizing_function());
- let mut gutter = GridTrack::gutter(gap);
-
- // Auto-fit tracks that don't contain should be collapsed.
- if *repetition_kind == GridTrackRepetition::AutoFit && !track_has_items(current_track_index) {
- track.collapse();
- gutter.collapse();
- }
-
- tracks.push(track);
- tracks.push(gutter);
-
+ track_template.iter().for_each(|track_sizing_function| {
+ use GridTrackRepetition::{AutoFill, AutoFit, Count};
+ match track_sizing_function {
+ TrackSizingFunction::Single(sizing_function) => {
+ tracks.push(GridTrack::new(
+ sizing_function.min_sizing_function(),
+ sizing_function.max_sizing_function(),
+ ));
+ tracks.push(GridTrack::gutter(gap));
current_track_index += 1;
}
+ TrackSizingFunction::Repeat(Count(count), repeated_tracks) => {
+ let track_iter = repeated_tracks.iter().cycle().take(repeated_tracks.len() * *count as usize);
+ track_iter.for_each(|sizing_function| {
+ tracks.push(GridTrack::new(
+ sizing_function.min_sizing_function(),
+ sizing_function.max_sizing_function(),
+ ));
+ tracks.push(GridTrack::gutter(gap));
+ current_track_index += 1;
+ });
+ }
+ TrackSizingFunction::Repeat(repetition_kind @ (AutoFit | AutoFill), repeated_tracks) => {
+ let auto_repeated_track_count = (counts.explicit - (track_template.len() as u16 - 1)) as usize;
+ let iter = repeated_tracks.iter().copied().cycle();
+ for track_def in iter.take(auto_repeated_track_count) {
+ let mut track =
+ GridTrack::new(track_def.min_sizing_function(), track_def.max_sizing_function());
+ let mut gutter = GridTrack::gutter(gap);
+
+ // Auto-fit tracks that don't contain should be collapsed.
+ if *repetition_kind == AutoFit && !track_has_items(current_track_index) {
+ track.collapse();
+ gutter.collapse();
+ }
+
+ tracks.push(track);
+ tracks.push(gutter);
+
+ current_track_index += 1;
+ }
+ }
}
});
}
diff --git a/src/style/grid.rs b/src/style/grid.rs
index 388a9290d..3d9d4b4b2 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -6,6 +6,7 @@ use crate::geometry::{Line, MinMax};
use crate::style_helpers::*;
use crate::sys::GridTrackVec;
use core::cmp::{max, min};
+use core::convert::Infallible;
/// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used.
///
@@ -492,12 +493,42 @@ impl FromFlex for NonRepeatedTrackSizingFunction {
/// and the difference between AutoFit and AutoFill.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GridTrackRepetition {
- /// Auto-repeating track should be generated to fit the container
+ /// Auto-repeating tracks should be generated to fit the container
/// See: https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fill
AutoFill,
- /// Auto-repeating track should be generated to fit the container
+ /// Auto-repeating tracks should be generated to fit the container
/// See: https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fit
AutoFit,
+ /// The specified tracks should be repeated exacts N times
+ Count(u16),
+}
+impl TryFrom<u16> for GridTrackRepetition {
+ type Error = Infallible;
+ fn try_from(value: u16) -> Result<Self, Infallible> {
+ Ok(Self::Count(value))
+ }
+}
+
+/// Error returned when trying to convert a string to a GridTrackRepetition and that string is not
+/// either "auto-fit" or "auto-fill"
+#[derive(Debug)]
+pub struct InvalidStringRepetitionValue;
+#[cfg(feature = "std")]
+impl std::error::Error for InvalidStringRepetitionValue {}
+impl core::fmt::Display for InvalidStringRepetitionValue {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ f.write_str("&str can only be converted to GridTrackRepetition if it's value is 'auto-fit' or 'auto-fill'")
+ }
+}
+impl<'a> TryFrom<&'a str> for GridTrackRepetition {
+ type Error = InvalidStringRepetitionValue;
+ fn try_from(value: &str) -> Result<Self, InvalidStringRepetitionValue> {
+ match value {
+ "auto-fit" => Ok(Self::AutoFit),
+ "auto-fill" => Ok(Self::AutoFill),
+ _ => Err(InvalidStringRepetitionValue),
+ }
+ }
}
/// The sizing function for a grid track (row/column)
@@ -508,12 +539,12 @@ pub enum TrackSizingFunction {
Single(NonRepeatedTrackSizingFunction),
/// Automatically generate grid tracks to fit the available space using the specified definite track lengths
/// Only valid if every track in template (not just the repitition) has a fixed size.
- AutoRepeat(GridTrackRepetition, GridTrackVec<NonRepeatedTrackSizingFunction>),
+ Repeat(GridTrackRepetition, GridTrackVec<NonRepeatedTrackSizingFunction>),
}
impl TrackSizingFunction {
/// Whether the track definition is a auto-repeated fragment
pub fn is_auto_repetition(&self) -> bool {
- matches!(self, Self::AutoRepeat(_, _))
+ matches!(self, Self::Repeat(GridTrackRepetition::AutoFit | GridTrackRepetition::AutoFill, _))
}
}
impl TaffyAuto for TrackSizingFunction {
diff --git a/src/style_helpers.rs b/src/style_helpers.rs
index eaf3f7949..69d790421 100644
--- a/src/style_helpers.rs
+++ b/src/style_helpers.rs
@@ -3,6 +3,7 @@ use crate::{
geometry::{MinMax, Point, Rect, Size},
style::LengthPercentage,
};
+use core::fmt::Debug;
#[cfg(feature = "grid")]
use crate::style::{
@@ -12,11 +13,36 @@ use crate::style::{
/// Returns an auto-repeated track definition
#[cfg(feature = "grid")]
-pub fn repeat(
- repetition_kind: GridTrackRepetition,
- track_list: Vec<NonRepeatedTrackSizingFunction>,
-) -> TrackSizingFunction {
- TrackSizingFunction::AutoRepeat(repetition_kind, track_list)
+pub fn repeat<Input>(repetition_kind: Input, track_list: Vec<NonRepeatedTrackSizingFunction>) -> TrackSizingFunction
+where
+ Input: TryInto<GridTrackRepetition>,
+ <Input as TryInto<GridTrackRepetition>>::Error: Debug,
+{
+ TrackSizingFunction::Repeat(repetition_kind.try_into().unwrap(), track_list)
+}
+
+#[cfg(feature = "grid")]
+#[cfg(test)]
+mod repeat_fn_tests {
+ use super::repeat;
+ use crate::style::{GridTrackRepetition, NonRepeatedTrackSizingFunction, TrackSizingFunction};
+
+ const TEST_VEC: Vec<NonRepeatedTrackSizingFunction> = Vec::new();
+
+ #[test]
+ fn test_repeat_u16() {
+ assert_eq!(repeat(123, TEST_VEC), TrackSizingFunction::Repeat(GridTrackRepetition::Count(123), TEST_VEC));
+ }
+
+ #[test]
+ fn test_repeat_auto_fit_str() {
+ assert_eq!(repeat("auto-fit", TEST_VEC), TrackSizingFunction::Repeat(GridTrackRepetition::AutoFit, TEST_VEC));
+ }
+
+ #[test]
+ fn test_repeat_auto_fill_str() {
+ assert_eq!(repeat("auto-fill", TEST_VEC), TrackSizingFunction::Repeat(GridTrackRepetition::AutoFill, TEST_VEC));
+ }
}
/// Specifies a grid line to place a grid item between in CSS Grid Line coordinates:
diff --git a/test_fixtures/grid_repeat_integer.html b/test_fixtures/grid_repeat_integer.html
new file mode 100644
index 000000000..67e5341c5
--- /dev/null
+++ b/test_fixtures/grid_repeat_integer.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="height: 120px; width: 120px; display: grid; grid-template-columns: repeat(3, 40px);grid-template-rows: repeat(3, 40px)">
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/grid_repeat_mixed.html b/test_fixtures/grid_repeat_mixed.html
new file mode 100644
index 000000000..5859bb34a
--- /dev/null
+++ b/test_fixtures/grid_repeat_mixed.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="height: 120px; width: 120px; display: grid; grid-template-columns: 40px repeat(1, 40px) repeat(auto-fill, 40px);grid-template-rows: 40px repeat(1, 40px) repeat(auto-fill, 40px)">
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/generated/grid_repeat_integer.rs b/tests/generated/grid_repeat_integer.rs
new file mode 100644
index 000000000..ec241849c
--- /dev/null
+++ b/tests/generated/grid_repeat_integer.rs
@@ -0,0 +1,85 @@
+#[test]
+fn grid_repeat_integer() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node7 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node8 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ display: taffy::style::Display::Grid,
+ grid_template_rows: vec![repeat(GridTrackRepetition::Count(3u16), vec![points(40f32)])],
+ grid_template_columns: vec![repeat(GridTrackRepetition::Count(3u16), vec![points(40f32)])],
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(120f32),
+ height: taffy::style::Dimension::Points(120f32),
+ },
+ ..Default::default()
+ },
+ &[node0, node1, node2, node3, node4, node5, node6, node7, node8],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 120f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 120f32, size.width);
+ assert_eq!(size.height, 120f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 120f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node1).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.height);
+ assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node2).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 40f32, size.height);
+ assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 80f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.x);
+ assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 40f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node4).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, size.height);
+ assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, location.x);
+ assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node5).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, size.height);
+ assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 80f32, location.x);
+ assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node6).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node6.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node6.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node6.data(), 0f32, location.x);
+ assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node6.data(), 80f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node7).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node7.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node7.data(), 40f32, size.height);
+ assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node7.data(), 40f32, location.x);
+ assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node7.data(), 80f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node8).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node8.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node8.data(), 40f32, size.height);
+ assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node8.data(), 80f32, location.x);
+ assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node8.data(), 80f32, location.y);
+}
diff --git a/tests/generated/grid_repeat_mixed.rs b/tests/generated/grid_repeat_mixed.rs
new file mode 100644
index 000000000..155eb259b
--- /dev/null
+++ b/tests/generated/grid_repeat_mixed.rs
@@ -0,0 +1,93 @@
+#[test]
+fn grid_repeat_mixed() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node7 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node8 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ display: taffy::style::Display::Grid,
+ grid_template_rows: vec![
+ points(40f32),
+ repeat(GridTrackRepetition::Count(1u16), vec![points(40f32)]),
+ repeat(GridTrackRepetition::AutoFill, vec![points(40f32)]),
+ ],
+ grid_template_columns: vec![
+ points(40f32),
+ repeat(GridTrackRepetition::Count(1u16), vec![points(40f32)]),
+ repeat(GridTrackRepetition::AutoFill, vec![points(40f32)]),
+ ],
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(120f32),
+ height: taffy::style::Dimension::Points(120f32),
+ },
+ ..Default::default()
+ },
+ &[node0, node1, node2, node3, node4, node5, node6, node7, node8],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 120f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 120f32, size.width);
+ assert_eq!(size.height, 120f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 120f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node1).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.height);
+ assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node2).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 40f32, size.height);
+ assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 80f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node3).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.x);
+ assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 40f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node4).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, size.height);
+ assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, location.x);
+ assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 40f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node5).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, size.height);
+ assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 80f32, location.x);
+ assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 40f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node6).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node6.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node6.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node6.data(), 0f32, location.x);
+ assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node6.data(), 80f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node7).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node7.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node7.data(), 40f32, size.height);
+ assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node7.data(), 40f32, location.x);
+ assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node7.data(), 80f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node8).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node8.data(), 40f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node8.data(), 40f32, size.height);
+ assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node8.data(), 80f32, location.x);
+ assert_eq!(location.y, 80f32, "y of node {:?}. Expected {}. Actual {}", node8.data(), 80f32, location.y);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index 1c1f11387..73b8c371b 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -576,6 +576,10 @@ mod grid_placement_definite_in_secondary_axis_with_fully_definite_negative;
#[cfg(feature = "grid")]
mod grid_relayout_vertical_text;
#[cfg(feature = "grid")]
+mod grid_repeat_integer;
+#[cfg(feature = "grid")]
+mod grid_repeat_mixed;
+#[cfg(feature = "grid")]
mod grid_size_child_fixed_tracks;
mod justify_content_column_center;
mod justify_content_column_flex_end;