1use super::types::{GridTrack, GridTrackKind, TrackCounts};
4use crate::geometry::AbsoluteAxis;
5use crate::style::{LengthPercentage, RepetitionCount, TrackSizingFunction};
6use crate::style_helpers::TaffyAuto;
7use crate::util::sys::{ceil, floor, Vec};
8use crate::util::MaybeMath;
9use crate::util::ResolveOrZero;
10use core::cmp::min;
11
12use super::MAX_GRID_TRACKS;
13use crate::{GenericGridTemplateComponent, GenericRepetition, GridContainerStyle};
14
15pub(crate) enum AutoRepeatStrategy {
17 MaxRepetitionsThatDoNotOverflow,
21 MinRepetitionsThatDoOverflow,
24}
25
26pub(crate) fn compute_explicit_grid_size_in_axis(
28 style: &impl GridContainerStyle,
29 auto_fit_container_size: Option<f32>,
30 auto_fit_strategy: AutoRepeatStrategy,
31 resolve_calc_value: impl Fn(*const (), f32) -> f32,
32 axis: AbsoluteAxis,
33) -> (u16, u16) {
34 let template = match axis {
35 AbsoluteAxis::Horizontal => style.grid_template_columns(),
36 AbsoluteAxis::Vertical => style.grid_template_rows(),
37 };
38 let Some(template) = template else {
39 return (0, 0);
40 };
41
42 let track_count = template.len();
44 if track_count == 0 {
45 return (0, 0);
46 }
47
48 let template_has_repetitions_with_zero_tracks = template.clone().any(|track_def| match track_def {
51 GenericGridTemplateComponent::Single(_) => false,
52 GenericGridTemplateComponent::Repeat(repeat) => repeat.track_count() == 0,
53 });
54 if template_has_repetitions_with_zero_tracks {
55 return (0, 0);
56 }
57
58 let non_auto_repeating_track_count = template
61 .clone()
62 .fold(0u32, |track_count, track_def| {
63 let additional_tracks = match track_def {
64 GenericGridTemplateComponent::Single(_) => 1u32,
65 GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
66 RepetitionCount::Count(count) => count as u32 * repeat.track_count() as u32,
67 RepetitionCount::AutoFit | RepetitionCount::AutoFill => 0,
68 },
69 };
70 track_count.saturating_add(additional_tracks)
71 })
72 .min(MAX_GRID_TRACKS as u32) as u16;
73
74 let auto_repetition_count: u16 = template.clone().filter(|track_def| track_def.is_auto_repetition()).count() as u16;
75 let all_track_defs_have_fixed_component = template.clone().all(|track_def| match track_def {
76 GenericGridTemplateComponent::Single(sizing_function) => sizing_function.has_fixed_component(),
77 GenericGridTemplateComponent::Repeat(repeat) => {
78 repeat.tracks().all(|sizing_function| sizing_function.has_fixed_component())
79 }
80 });
81
82 let template_is_valid =
83 auto_repetition_count == 0 || (auto_repetition_count == 1 && all_track_defs_have_fixed_component);
84
85 if !template_is_valid {
88 return (0, 0);
89 }
90
91 if auto_repetition_count == 0 {
94 return (0, non_auto_repeating_track_count);
95 }
96
97 let mut auto_repeat_insertion_point = 0u32;
98 let repetition_definition = template
99 .clone()
100 .find_map(|def| match def {
101 GenericGridTemplateComponent::Single(_) => {
102 auto_repeat_insertion_point = auto_repeat_insertion_point.saturating_add(1);
103 None
104 }
105 GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
106 RepetitionCount::Count(count) => {
107 auto_repeat_insertion_point =
108 auto_repeat_insertion_point.saturating_add(count as u32 * repeat.track_count() as u32);
109 None
110 }
111 RepetitionCount::AutoFit | RepetitionCount::AutoFill => Some(repeat),
112 },
113 })
114 .unwrap();
115 let repetition_definition_iter = repetition_definition.tracks();
116 let repetition_track_count = repetition_definition_iter.len().min(u16::MAX as usize) as u16;
117
118 let num_repetitions: u32 = match auto_fit_container_size {
120 None => 1,
121 Some(inner_container_size) => {
122 let parent_size = Some(inner_container_size);
123
124 fn track_definite_value(
127 sizing_function: TrackSizingFunction,
128 parent_size: Option<f32>,
129 calc_resolver: impl Fn(*const (), f32) -> f32,
130 ) -> f32 {
131 let max_size = sizing_function.max.definite_value(parent_size, &calc_resolver);
132 let min_size = sizing_function.min.definite_value(parent_size, &calc_resolver);
133 max_size.map(|max| max.maybe_max(min_size)).or(min_size).unwrap()
134 }
135
136 let non_repeating_track_used_space: f32 = template
137 .clone()
138 .map(|track_def| match track_def {
139 GenericGridTemplateComponent::Single(sizing_function) => {
140 track_definite_value(sizing_function, parent_size, &resolve_calc_value)
141 }
142 GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
143 RepetitionCount::Count(count) => {
144 let sum = repeat
145 .tracks()
146 .map(|sizing_function| {
147 track_definite_value(sizing_function, parent_size, &resolve_calc_value)
148 })
149 .sum::<f32>();
150 sum * (count as f32)
151 }
152 RepetitionCount::AutoFit | RepetitionCount::AutoFill => 0.0,
153 },
154 })
155 .sum();
156 let gap_size = style.gap().get_abs(axis).resolve_or_zero(Some(inner_container_size), &resolve_calc_value);
157
158 let per_repetition_track_used_space: f32 = repetition_definition_iter
160 .map(|sizing_function| track_definite_value(sizing_function, parent_size, &resolve_calc_value))
161 .sum::<f32>();
162
163 let first_repetition_and_non_repeating_tracks_used_space = non_repeating_track_used_space
166 + per_repetition_track_used_space
167 + ((non_auto_repeating_track_count as u32 + repetition_track_count as u32).saturating_sub(1) as f32
168 * gap_size);
169
170 if first_repetition_and_non_repeating_tracks_used_space > inner_container_size {
173 1u32
174 } else {
175 let per_repetition_gap_used_space = (repetition_track_count as f32) * gap_size;
176 let per_repetition_used_space = per_repetition_track_used_space + per_repetition_gap_used_space;
177 let num_repetition_that_fit = (inner_container_size
178 - first_repetition_and_non_repeating_tracks_used_space)
179 / per_repetition_used_space;
180
181 match auto_fit_strategy {
190 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow => {
191 (floor(num_repetition_that_fit) as u32).saturating_add(1)
192 }
193 AutoRepeatStrategy::MinRepetitionsThatDoOverflow => {
194 (ceil(num_repetition_that_fit) as u32).saturating_add(1)
195 }
196 }
197 }
198 }
199 };
200
201 let remaining_tracks = (MAX_GRID_TRACKS as u32).saturating_sub(auto_repeat_insertion_point);
205 let num_repetitions = if remaining_tracks == 0 {
206 0
207 } else {
208 let max_repetitions = (remaining_tracks + repetition_track_count as u32 - 1) / repetition_track_count as u32;
209 num_repetitions.clamp(1, max_repetitions) as u16
210 };
211
212 let grid_template_track_count = min(
213 non_auto_repeating_track_count as u32 + (repetition_track_count as u32 * num_repetitions as u32),
214 MAX_GRID_TRACKS as u32,
215 ) as u16;
216 (num_repetitions, grid_template_track_count)
217}
218
219pub(super) fn initialize_grid_tracks(
222 tracks: &mut Vec<GridTrack>,
223 counts: TrackCounts,
224 style: &impl GridContainerStyle,
225 axis: AbsoluteAxis,
226 auto_repetition_count: u16,
227 track_has_items: impl Fn(usize) -> bool,
228) {
229 let track_template;
231 let auto_tracks;
232 let gap;
233 match axis {
234 AbsoluteAxis::Horizontal => {
235 track_template = style.grid_template_columns();
236 auto_tracks = style.grid_auto_columns();
237 gap = style.gap().width;
238 }
239 AbsoluteAxis::Vertical => {
240 track_template = style.grid_template_rows();
241 auto_tracks = style.grid_auto_rows();
242 gap = style.gap().height;
243 }
244 };
245
246 tracks.clear();
249 tracks.reserve((counts.len() * 2) + 1);
250 tracks.push(GridTrack::gutter(gap));
251
252 let auto_track_count = auto_tracks.len();
253
254 if counts.negative_implicit > 0 {
256 if auto_track_count == 0 {
257 let iter = core::iter::repeat(TrackSizingFunction::AUTO);
258 create_implicit_tracks(tracks, counts.negative_implicit, iter, gap)
259 } else {
260 let offset = auto_track_count - (counts.negative_implicit as usize % auto_track_count);
261 let iter = auto_tracks.clone().cycle().skip(offset);
262 create_implicit_tracks(tracks, counts.negative_implicit, iter, gap)
263 }
264 }
265
266 let mut current_track_index = (counts.negative_implicit) as usize;
267
268 let explicit_track_limit = (counts.negative_implicit + counts.explicit) as usize;
271
272 if counts.explicit > 0 {
276 if let Some(track_template) = track_template {
277 track_template.for_each(|track_sizing_function| {
278 match track_sizing_function {
279 GenericGridTemplateComponent::Single(sizing_function) => {
280 if current_track_index < explicit_track_limit {
281 tracks.push(GridTrack::new(
282 sizing_function.min_sizing_function(),
283 sizing_function.max_sizing_function(),
284 ));
285 tracks.push(GridTrack::gutter(gap));
286 current_track_index += 1;
287 }
288 }
289 GenericGridTemplateComponent::Repeat(repeat) => match repeat.count() {
290 RepetitionCount::Count(count) => {
291 let repeated_track_count = (repeat.track_count() as usize * count as usize)
292 .min(explicit_track_limit - current_track_index);
293 let track_iter = repeat.tracks();
294 let track_iter = track_iter.cycle().take(repeated_track_count);
295 track_iter.for_each(|sizing_function| {
296 tracks.push(GridTrack::new(
297 sizing_function.min_sizing_function(),
298 sizing_function.max_sizing_function(),
299 ));
300 tracks.push(GridTrack::gutter(gap));
301 current_track_index += 1;
302 });
303 }
304 RepetitionCount::AutoFit | RepetitionCount::AutoFill => {
305 let auto_repeated_track_count = (repeat.track_count() as usize
306 * auto_repetition_count as usize)
307 .min(explicit_track_limit - current_track_index);
308 let iter = repeat.tracks().cycle();
309 for track_def in iter.take(auto_repeated_track_count) {
310 let mut track =
311 GridTrack::new(track_def.min_sizing_function(), track_def.max_sizing_function());
312 let mut gutter = GridTrack::gutter(gap);
313
314 if repeat.count() == RepetitionCount::AutoFit && !track_has_items(current_track_index) {
316 track.collapse();
317 gutter.collapse();
318 }
319
320 tracks.push(track);
321 tracks.push(gutter);
322
323 current_track_index += 1;
324 }
325
326 let is_last = current_track_index == counts.len();
328
329 if repeat.count() == RepetitionCount::AutoFit && is_last {
340 for previous_track in tracks.iter_mut().rev() {
341 if previous_track.kind == GridTrackKind::Track && !previous_track.is_collapsed {
342 break;
343 }
344 previous_track.collapse();
345 }
346 }
347 }
348 },
349 }
350 });
351 }
352 }
353
354 let grid_area_tracks = (counts.negative_implicit + counts.explicit) - current_track_index as u16;
355
356 if auto_track_count == 0 {
358 let iter = core::iter::repeat(TrackSizingFunction::AUTO);
359 create_implicit_tracks(tracks, counts.positive_implicit + grid_area_tracks, iter, gap)
360 } else {
361 let iter = auto_tracks.clone().cycle();
362 create_implicit_tracks(tracks, counts.positive_implicit + grid_area_tracks, iter, gap)
363 }
364
365 tracks.first_mut().unwrap().collapse();
367 tracks.last_mut().unwrap().collapse();
368}
369
370fn create_implicit_tracks(
372 tracks: &mut Vec<GridTrack>,
373 count: u16,
374 mut auto_tracks_iter: impl Iterator<Item = TrackSizingFunction>,
375 gap: LengthPercentage,
376) {
377 for _ in 0..count {
378 let track_def = auto_tracks_iter.next().unwrap();
379 tracks.push(GridTrack::new(track_def.min_sizing_function(), track_def.max_sizing_function()));
380 tracks.push(GridTrack::gutter(gap));
381 }
382}
383
384#[cfg(test)]
385mod test {
386 use super::compute_explicit_grid_size_in_axis;
387 use super::initialize_grid_tracks;
388 use crate::compute::grid::explicit_grid::AutoRepeatStrategy;
389 use crate::compute::grid::types::GridTrackKind;
390 use crate::compute::grid::types::TrackCounts;
391 use crate::compute::grid::util::*;
392 use crate::geometry::AbsoluteAxis;
393 use crate::prelude::*;
394 use crate::sys::DefaultCheapStr;
395
396 #[test]
397 fn explicit_grid_sizing_no_repeats() {
398 let grid_style = (600.0, 600.0, 2, 4).into_grid();
399 let preferred_size = grid_style.size.map(|s| s.into_option());
400 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
401 &grid_style,
402 preferred_size.get_abs(AbsoluteAxis::Horizontal),
403 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
404 |_, _| 42.42,
405 AbsoluteAxis::Horizontal,
406 );
407 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
408 &grid_style,
409 preferred_size.get_abs(AbsoluteAxis::Vertical),
410 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
411 |_, _| 42.42,
412 AbsoluteAxis::Vertical,
413 );
414 assert_eq!(col_count, 2);
415 assert_eq!(row_count, 4);
416 assert_eq!(auto_col_reps, 0);
417 assert_eq!(auto_row_reps, 0);
418 }
419
420 #[test]
421 fn explicit_grid_sizing_auto_fill_exact_fit() {
422 use RepetitionCount::AutoFill;
423 let grid_style: Style<DefaultCheapStr> = Style {
424 display: Display::Grid,
425 size: Size { width: length(120.0), height: length(80.0) },
426 grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
427 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
428 ..Default::default()
429 };
430 let preferred_size = grid_style.size.map(|s| s.into_option());
431 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
432 &grid_style,
433 preferred_size.get_abs(AbsoluteAxis::Horizontal),
434 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
435 |_, _| 42.42,
436 AbsoluteAxis::Horizontal,
437 );
438 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
439 &grid_style,
440 preferred_size.get_abs(AbsoluteAxis::Vertical),
441 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
442 |_, _| 42.42,
443 AbsoluteAxis::Vertical,
444 );
445 assert_eq!(col_count, 3);
446 assert_eq!(row_count, 4);
447 assert_eq!(auto_col_reps, 3);
448 assert_eq!(auto_row_reps, 4);
449 }
450
451 #[test]
452 fn explicit_grid_sizing_auto_fill_non_exact_fit() {
453 use RepetitionCount::AutoFill;
454 let grid_style: Style<DefaultCheapStr> = Style {
455 display: Display::Grid,
456 size: Size { width: length(140.0), height: length(90.0) },
457 grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
458 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
459 ..Default::default()
460 };
461 let preferred_size = grid_style.size.map(|s| s.into_option());
462 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
463 &grid_style,
464 preferred_size.get_abs(AbsoluteAxis::Horizontal),
465 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
466 |_, _| 42.42,
467 AbsoluteAxis::Horizontal,
468 );
469 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
470 &grid_style,
471 preferred_size.get_abs(AbsoluteAxis::Vertical),
472 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
473 |_, _| 42.42,
474 AbsoluteAxis::Vertical,
475 );
476 assert_eq!(col_count, 3);
477 assert_eq!(row_count, 4);
478 assert_eq!(auto_col_reps, 3);
479 assert_eq!(auto_row_reps, 4);
480 }
481
482 #[test]
483 fn explicit_grid_sizing_auto_fill_min_size_exact_fit() {
484 use RepetitionCount::AutoFill;
485 let grid_style: Style<DefaultCheapStr> = Style {
486 display: Display::Grid,
487 min_size: Size { width: length(120.0), height: length(80.0) },
488 grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
489 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
490 ..Default::default()
491 };
492 let inner_container_size = Size { width: Some(120.0), height: Some(80.0) };
493 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
494 &grid_style,
495 inner_container_size.get_abs(AbsoluteAxis::Horizontal),
496 AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
497 |_, _| 42.42,
498 AbsoluteAxis::Horizontal,
499 );
500 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
501 &grid_style,
502 inner_container_size.get_abs(AbsoluteAxis::Vertical),
503 AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
504 |_, _| 42.42,
505 AbsoluteAxis::Vertical,
506 );
507 assert_eq!(col_count, 3);
508 assert_eq!(row_count, 4);
509 assert_eq!(auto_col_reps, 3);
510 assert_eq!(auto_row_reps, 4);
511 }
512
513 #[test]
514 fn explicit_grid_sizing_auto_fill_min_size_non_exact_fit() {
515 use RepetitionCount::AutoFill;
516 let grid_style: Style<DefaultCheapStr> = Style {
517 display: Display::Grid,
518 min_size: Size { width: length(140.0), height: length(90.0) },
519 grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
520 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
521 ..Default::default()
522 };
523 let inner_container_size = Size { width: Some(140.0), height: Some(90.0) };
524 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
525 &grid_style,
526 inner_container_size.get_abs(AbsoluteAxis::Horizontal),
527 AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
528 |_, _| 42.42,
529 AbsoluteAxis::Horizontal,
530 );
531 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
532 &grid_style,
533 inner_container_size.get_abs(AbsoluteAxis::Vertical),
534 AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
535 |_, _| 42.42,
536 AbsoluteAxis::Vertical,
537 );
538 assert_eq!(col_count, 4);
539 assert_eq!(row_count, 5);
540 assert_eq!(auto_col_reps, 4);
541 assert_eq!(auto_row_reps, 5);
542 }
543
544 #[test]
545 fn explicit_grid_sizing_auto_fill_multiple_repeated_tracks() {
546 use RepetitionCount::AutoFill;
547 let grid_style: Style<DefaultCheapStr> = Style {
548 display: Display::Grid,
549 size: Size { width: length(140.0), height: length(100.0) },
550 grid_template_columns: vec![repeat(AutoFill, vec![length(40.0), length(20.0)])],
551 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0), length(10.0)])],
552 ..Default::default()
553 };
554 let preferred_size = grid_style.size.map(|s| s.into_option());
555 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
556 &grid_style,
557 preferred_size.get_abs(AbsoluteAxis::Horizontal),
558 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
559 |_, _| 42.42,
560 AbsoluteAxis::Horizontal,
561 );
562 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
563 &grid_style,
564 preferred_size.get_abs(AbsoluteAxis::Vertical),
565 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
566 |_, _| 42.42,
567 AbsoluteAxis::Vertical,
568 );
569 assert_eq!(col_count, 4); assert_eq!(row_count, 6); assert_eq!(auto_col_reps, 2);
572 assert_eq!(auto_row_reps, 3);
573 }
574
575 #[test]
576 fn explicit_grid_sizing_auto_fill_gap() {
577 use RepetitionCount::AutoFill;
578 let grid_style: Style<DefaultCheapStr> = Style {
579 display: Display::Grid,
580 size: Size { width: length(140.0), height: length(100.0) },
581 grid_template_columns: vec![repeat(AutoFill, vec![length(40.0)])],
582 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
583 gap: length(20.0),
584 ..Default::default()
585 };
586 let preferred_size = grid_style.size.map(|s| s.into_option());
587 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
588 &grid_style,
589 preferred_size.get_abs(AbsoluteAxis::Horizontal),
590 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
591 |_, _| 42.42,
592 AbsoluteAxis::Horizontal,
593 );
594 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
595 &grid_style,
596 preferred_size.get_abs(AbsoluteAxis::Vertical),
597 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
598 |_, _| 42.42,
599 AbsoluteAxis::Vertical,
600 );
601 assert_eq!(col_count, 2); assert_eq!(row_count, 3); assert_eq!(auto_col_reps, 2);
604 assert_eq!(auto_row_reps, 3);
605 }
606
607 #[test]
608 fn explicit_grid_sizing_no_defined_size() {
609 use RepetitionCount::AutoFill;
610 let grid_style: Style<DefaultCheapStr> = Style {
611 display: Display::Grid,
612 grid_template_columns: vec![repeat(AutoFill, vec![length(40.0), percent(0.5), length(20.0)])],
613 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
614 gap: length(20.0),
615 ..Default::default()
616 };
617 let preferred_size = grid_style.size.map(|s| s.into_option());
618 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
619 &grid_style,
620 preferred_size.get_abs(AbsoluteAxis::Horizontal),
621 AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
622 |_, _| 42.42,
623 AbsoluteAxis::Horizontal,
624 );
625 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
626 &grid_style,
627 preferred_size.get_abs(AbsoluteAxis::Vertical),
628 AutoRepeatStrategy::MinRepetitionsThatDoOverflow,
629 |_, _| 42.42,
630 AbsoluteAxis::Vertical,
631 );
632 assert_eq!(col_count, 3);
633 assert_eq!(row_count, 1);
634 assert_eq!(auto_col_reps, 1);
635 assert_eq!(auto_row_reps, 1);
636 }
637
638 #[test]
639 fn explicit_grid_sizing_mix_repeated_and_non_repeated() {
640 use RepetitionCount::AutoFill;
641 let grid_style: Style<DefaultCheapStr> = Style {
642 display: Display::Grid,
643 size: Size { width: length(140.0), height: length(100.0) },
644 grid_template_columns: vec![length(20.0), repeat(AutoFill, vec![length(40.0)])],
645 grid_template_rows: vec![length(40.0), repeat(AutoFill, vec![length(20.0)])],
646 gap: length(20.0),
647 ..Default::default()
648 };
649 let preferred_size = grid_style.size.map(|s| s.into_option());
650 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
651 &grid_style,
652 preferred_size.get_abs(AbsoluteAxis::Horizontal),
653 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
654 |_, _| 42.42,
655 AbsoluteAxis::Horizontal,
656 );
657 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
658 &grid_style,
659 preferred_size.get_abs(AbsoluteAxis::Vertical),
660 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
661 |_, _| 42.42,
662 AbsoluteAxis::Vertical,
663 );
664 assert_eq!(col_count, 3); assert_eq!(row_count, 2); assert_eq!(auto_col_reps, 2);
667 assert_eq!(auto_row_reps, 1);
668 }
669
670 #[test]
671 fn explicit_grid_sizing_mix_with_padding() {
672 use RepetitionCount::AutoFill;
673 let grid_style: Style<DefaultCheapStr> = Style {
674 display: Display::Grid,
675 size: Size { width: length(120.0), height: length(120.0) },
676 padding: Rect { left: length(10.0), right: length(10.0), top: length(20.0), bottom: length(20.0) },
677 grid_template_columns: vec![repeat(AutoFill, vec![length(20.0)])],
678 grid_template_rows: vec![repeat(AutoFill, vec![length(20.0)])],
679 ..Default::default()
680 };
681 let inner_container_size = Size { width: Some(100.0), height: Some(80.0) };
682 let (auto_col_reps, col_count) = compute_explicit_grid_size_in_axis(
683 &grid_style,
684 inner_container_size.get_abs(AbsoluteAxis::Horizontal),
685 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
686 |_, _| 42.42,
687 AbsoluteAxis::Horizontal,
688 );
689 let (auto_row_reps, row_count) = compute_explicit_grid_size_in_axis(
690 &grid_style,
691 inner_container_size.get_abs(AbsoluteAxis::Vertical),
692 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
693 |_, _| 42.42,
694 AbsoluteAxis::Vertical,
695 );
696 assert_eq!(col_count, 5); assert_eq!(row_count, 4); assert_eq!(auto_col_reps, 5);
699 assert_eq!(auto_row_reps, 4);
700 }
701
702 #[test]
703 fn auto_repeat_clamping_preserves_template_source_order() {
704 use RepetitionCount::{AutoFill, Count};
705
706 let auto_repeat_first: Style<DefaultCheapStr> = Style {
707 display: Display::Grid,
708 grid_template_columns: vec![repeat(AutoFill, vec![length(2.0)]), repeat(Count(10_000), vec![length(37.0)])],
709 ..Default::default()
710 };
711 let (repetitions, track_count) = compute_explicit_grid_size_in_axis(
712 &auto_repeat_first,
713 None,
714 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
715 |_, _| 42.42,
716 AbsoluteAxis::Horizontal,
717 );
718 assert_eq!((repetitions, track_count), (1, 10_000));
719 let mut tracks = Vec::new();
720 initialize_grid_tracks(
721 &mut tracks,
722 TrackCounts::from_raw(0, track_count, 0),
723 &auto_repeat_first,
724 AbsoluteAxis::Horizontal,
725 repetitions,
726 |_| false,
727 );
728 assert_eq!(tracks[1].min_track_sizing_function, MinTrackSizingFunction::from_length(2.0));
729 assert_eq!(tracks[3].min_track_sizing_function, MinTrackSizingFunction::from_length(37.0));
730
731 let auto_repeat_last: Style<DefaultCheapStr> = Style {
732 display: Display::Grid,
733 grid_template_columns: vec![repeat(Count(10_000), vec![length(37.0)]), repeat(AutoFill, vec![length(2.0)])],
734 ..Default::default()
735 };
736 let (repetitions, track_count) = compute_explicit_grid_size_in_axis(
737 &auto_repeat_last,
738 None,
739 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
740 |_, _| 42.42,
741 AbsoluteAxis::Horizontal,
742 );
743 assert_eq!((repetitions, track_count), (0, 10_000));
744 }
745
746 #[test]
747 fn explicit_track_count_accumulation_saturates() {
748 use RepetitionCount::{AutoFill, Count};
749
750 let repeated_tracks = vec![length(1.0); 32_769];
751 let grid_style: Style<DefaultCheapStr> = Style {
752 display: Display::Grid,
753 grid_template_columns: vec![
754 repeat(Count(u16::MAX), repeated_tracks.clone()),
755 repeat(Count(u16::MAX), repeated_tracks),
756 repeat(AutoFill, vec![length(1.0)]),
757 ],
758 ..Default::default()
759 };
760 let result = compute_explicit_grid_size_in_axis(
761 &grid_style,
762 None,
763 AutoRepeatStrategy::MaxRepetitionsThatDoNotOverflow,
764 |_, _| 42.42,
765 AbsoluteAxis::Horizontal,
766 );
767 assert_eq!(result, (0, 10_000));
768 }
769
770 #[test]
771 fn test_initialize_grid_tracks() {
772 let minpx0 = MinTrackSizingFunction::from_length(0.0);
773 let minpx20 = MinTrackSizingFunction::from_length(20.0);
774 let minpx100 = MinTrackSizingFunction::from_length(100.0);
775
776 let maxpx0 = MaxTrackSizingFunction::from_length(0.0);
777 let maxpx20 = MaxTrackSizingFunction::from_length(20.0);
778 let maxpx100 = MaxTrackSizingFunction::from_length(100.0);
779
780 let grid_style: Style<DefaultCheapStr> = Style {
782 display: Display::Grid,
783 gap: length(20.0),
784 grid_template_columns: vec![length(100.0), minmax(length(100.0), fr(2.0)), fr(1.0)],
785 grid_auto_columns: vec![auto(), length(100.0)],
786 ..Default::default()
787 };
788 let track_counts = TrackCounts {
789 negative_implicit: 3,
790 explicit: grid_style.grid_template_columns.len() as u16,
791 positive_implicit: 3,
792 };
793
794 let mut tracks = Vec::new();
796 initialize_grid_tracks(&mut tracks, track_counts, &grid_style, AbsoluteAxis::Horizontal, 0, |_| false);
797
798 let expected = vec![
800 (GridTrackKind::Gutter, minpx0, maxpx0),
802 (GridTrackKind::Track, minpx100, maxpx100),
804 (GridTrackKind::Gutter, minpx20, maxpx20),
805 (GridTrackKind::Track, auto(), auto()),
806 (GridTrackKind::Gutter, minpx20, maxpx20),
807 (GridTrackKind::Track, minpx100, maxpx100),
808 (GridTrackKind::Gutter, minpx20, maxpx20),
809 (GridTrackKind::Track, minpx100, maxpx100),
811 (GridTrackKind::Gutter, minpx20, maxpx20),
812 (GridTrackKind::Track, minpx100, MaxTrackSizingFunction::from_fr(2.0)), (GridTrackKind::Gutter, minpx20, maxpx20),
814 (GridTrackKind::Track, auto(), MaxTrackSizingFunction::from_fr(1.0)), (GridTrackKind::Gutter, minpx20, maxpx20),
816 (GridTrackKind::Track, auto(), auto()),
818 (GridTrackKind::Gutter, minpx20, maxpx20),
819 (GridTrackKind::Track, minpx100, maxpx100),
820 (GridTrackKind::Gutter, minpx20, maxpx20),
821 (GridTrackKind::Track, auto(), auto()),
822 (GridTrackKind::Gutter, minpx0, maxpx0),
823 ];
824
825 assert_eq!(tracks.len(), expected.len(), "Number of tracks doesn't match");
826
827 for (idx, (actual, (kind, min, max))) in tracks.into_iter().zip(expected).enumerate() {
828 assert_eq!(actual.kind, kind, "Track {idx} (0-based index)");
829 assert_eq!(actual.min_track_sizing_function, min, "Track {idx} (0-based index)");
830 assert_eq!(actual.max_track_sizing_function, max, "Track {idx} (0-based index)");
831 }
832 }
833}