1use crate::geometry::Line;
4use crate::style::{GenericGridPlacement, GridPlacement};
5use crate::{CheapCloneStr, Direction, GridItemStyle};
6use core::cmp::{max, min};
7
8use super::types::TrackCounts;
9use super::OriginZeroLine;
10
11pub(crate) fn compute_grid_size_estimate<'a, S: GridItemStyle + 'a>(
20 explicit_col_count: u16,
21 explicit_row_count: u16,
22 direction: Direction,
23 child_styles_iter: impl Iterator<Item = S>,
24) -> (TrackCounts, TrackCounts) {
25 let (col_min, col_max, col_max_span, row_min, row_max, row_max_span) =
28 get_known_child_positions(child_styles_iter, explicit_col_count, explicit_row_count, direction);
29
30 let negative_implicit_inline_tracks = col_min.implied_negative_implicit_tracks();
34 let explicit_inline_tracks = explicit_col_count;
35 let mut positive_implicit_inline_tracks = col_max.implied_positive_implicit_tracks(explicit_col_count);
36 let negative_implicit_block_tracks = row_min.implied_negative_implicit_tracks();
37 let explicit_block_tracks = explicit_row_count;
38 let mut positive_implicit_block_tracks = row_max.implied_positive_implicit_tracks(explicit_row_count);
39
40 let tot_inline_tracks = negative_implicit_inline_tracks + explicit_inline_tracks + positive_implicit_inline_tracks;
43 if tot_inline_tracks < col_max_span {
44 positive_implicit_inline_tracks = col_max_span - explicit_inline_tracks - negative_implicit_inline_tracks;
45 }
46
47 let tot_block_tracks = negative_implicit_block_tracks + explicit_block_tracks + positive_implicit_block_tracks;
48 if tot_block_tracks < row_max_span {
49 positive_implicit_block_tracks = row_max_span - explicit_block_tracks - negative_implicit_block_tracks;
50 }
51
52 let column_counts =
53 TrackCounts::from_raw(negative_implicit_inline_tracks, explicit_inline_tracks, positive_implicit_inline_tracks);
54
55 let row_counts =
56 TrackCounts::from_raw(negative_implicit_block_tracks, explicit_block_tracks, positive_implicit_block_tracks);
57
58 (column_counts, row_counts)
59}
60
61fn get_known_child_positions<'a, S: GridItemStyle + 'a>(
66 children_iter: impl Iterator<Item = S>,
67 explicit_col_count: u16,
68 explicit_row_count: u16,
69 direction: Direction,
70) -> (OriginZeroLine, OriginZeroLine, u16, OriginZeroLine, OriginZeroLine, u16) {
71 let (mut col_min, mut col_max, mut col_max_span) = (OriginZeroLine(0), OriginZeroLine(0), 0);
72 let (mut row_min, mut row_max, mut row_max_span) = (OriginZeroLine(0), OriginZeroLine(0), 0);
73 children_iter.for_each(|child_style| {
74 let col_line = child_style.grid_column();
75 let row_line = child_style.grid_row();
76
77 let (mut child_col_min, mut child_col_max, child_col_span) =
80 child_min_line_max_line_span::<S::CustomIdent>(col_line, explicit_col_count);
81 let (child_row_min, child_row_max, child_row_span) =
82 child_min_line_max_line_span::<S::CustomIdent>(row_line, explicit_row_count);
83
84 if direction.is_rtl() && (child_col_min != OriginZeroLine(0) || child_col_max != OriginZeroLine(0)) {
87 let explicit_col_end_line = explicit_col_count as i16;
88 let mirrored_min = OriginZeroLine(explicit_col_end_line - child_col_max.0);
89 let mirrored_max = OriginZeroLine(explicit_col_end_line - child_col_min.0);
90 child_col_min = mirrored_min;
91 child_col_max = mirrored_max;
92 }
93
94 col_min = min(col_min, child_col_min);
95 col_max = max(col_max, child_col_max);
96 col_max_span = max(col_max_span, child_col_span);
97 row_min = min(row_min, child_row_min);
98 row_max = max(row_max, child_row_max);
99 row_max_span = max(row_max_span, child_row_span);
100 });
101
102 (col_min, col_max, col_max_span, row_min, row_max, row_max_span)
103}
104
105#[inline]
110fn child_min_line_max_line_span<S: CheapCloneStr>(
111 line: Line<GridPlacement<S>>,
112 explicit_track_count: u16,
113) -> (OriginZeroLine, OriginZeroLine, u16) {
114 use GenericGridPlacement::*;
115
116 let oz_line = line.into_origin_zero_ignoring_named(explicit_track_count);
125
126 let min = match (oz_line.start, oz_line.end) {
127 (Line(track1), Line(track2)) => {
129 if track1 == track2 {
131 track1
132 } else {
133 min(track1, track2)
134 }
135 }
136
137 (Line(track), Auto) => track,
139 (Line(track), Span(_)) => track,
140
141 (Auto, Line(track)) => track,
143 (Span(span), Line(track)) => track - span,
144
145 (Auto | Span(_), Auto | Span(_)) => OriginZeroLine(0),
148 };
149
150 let max = match (oz_line.start, oz_line.end) {
151 (Line(track1), Line(track2)) => {
153 if track1 == track2 {
155 track1 + 1
156 } else {
157 max(track1, track2)
158 }
159 }
160
161 (Line(track), Auto) => track + 1,
163 (Line(track), Span(span)) => track + span,
164
165 (Auto, Line(track)) => track,
167 (Span(_), Line(track)) => track,
168
169 (Auto | Span(_), Auto | Span(_)) => OriginZeroLine(0),
172 };
173
174 let span = match (oz_line.start, oz_line.end) {
177 (Auto | Span(_), Auto | Span(_)) => oz_line.indefinite_span(),
178 _ => 1,
179 };
180
181 (min, max, span)
182}
183
184#[allow(clippy::bool_assert_comparison)]
185#[cfg(test)]
186mod tests {
187 mod test_child_min_max_line {
188 type S = String;
189 use super::super::child_min_line_max_line_span;
190 use super::super::OriginZeroLine;
191 use crate::geometry::Line;
192 use crate::style_helpers::*;
193
194 #[test]
195 fn child_min_max_line_auto() {
196 let (min_col, max_col, span) = child_min_line_max_line_span::<S>(Line { start: line(5), end: span(6) }, 6);
197 assert_eq!(min_col, OriginZeroLine(4));
198 assert_eq!(max_col, OriginZeroLine(10));
199 assert_eq!(span, 1);
200 }
201
202 #[test]
203 fn child_min_max_line_negative_track() {
204 let (min_col, max_col, span) = child_min_line_max_line_span::<S>(Line { start: line(-5), end: span(3) }, 6);
205 assert_eq!(min_col, OriginZeroLine(2));
206 assert_eq!(max_col, OriginZeroLine(5));
207 assert_eq!(span, 1);
208 }
209 }
210
211 mod test_initial_grid_sizing {
212 use super::super::compute_grid_size_estimate;
213 use crate::compute::grid::util::test_helpers::*;
214 use crate::style_helpers::*;
215 use crate::Direction;
216
217 #[test]
218 fn explicit_grid_sizing_with_children() {
219 let explicit_col_count = 6;
220 let explicit_row_count = 8;
221 let child_styles = [
222 (line(1), span(2), line(2), auto()).into_grid_child(),
223 (line(-4), auto(), line(-2), auto()).into_grid_child(),
224 ];
225 let (inline, block) =
226 compute_grid_size_estimate(explicit_col_count, explicit_row_count, Direction::Ltr, child_styles.iter());
227 assert_eq!(inline.negative_implicit, 0);
228 assert_eq!(inline.explicit, explicit_col_count);
229 assert_eq!(inline.positive_implicit, 0);
230 assert_eq!(block.negative_implicit, 0);
231 assert_eq!(block.explicit, explicit_row_count);
232 assert_eq!(block.positive_implicit, 0);
233 }
234
235 #[test]
236 fn negative_implicit_grid_sizing() {
237 let explicit_col_count = 4;
238 let explicit_row_count = 4;
239 let child_styles = [
240 (line(-6), span(2), line(-8), auto()).into_grid_child(),
241 (line(4), auto(), line(3), auto()).into_grid_child(),
242 ];
243 let (inline, block) =
244 compute_grid_size_estimate(explicit_col_count, explicit_row_count, Direction::Ltr, child_styles.iter());
245 assert_eq!(inline.negative_implicit, 1);
246 assert_eq!(inline.explicit, explicit_col_count);
247 assert_eq!(inline.positive_implicit, 0);
248 assert_eq!(block.negative_implicit, 3);
249 assert_eq!(block.explicit, explicit_row_count);
250 assert_eq!(block.positive_implicit, 0);
251 }
252 }
253}