1use super::types::{CellOccupancyMatrix, CellOccupancyState, GridItem};
4use super::{NamedLineResolver, OriginZeroLine, MAX_OZ_LINE, MIN_OZ_LINE};
5use crate::geometry::Line;
6use crate::geometry::{AbsoluteAxis, InBothAbsAxis};
7use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement};
8use crate::tree::NodeId;
9use crate::util::sys::Vec;
10use crate::{CoreStyle, GridItemStyle};
11
12#[inline]
13fn advance_position(position: OriginZeroLine) -> OriginZeroLine {
15 OriginZeroLine(position.0.saturating_add(1))
16}
17
18#[inline]
19fn resolve_indefinite_grid_span(position: OriginZeroLine, span: u16) -> Line<OriginZeroLine> {
21 let position = position.0 as i32;
22 let span = span as i32;
23 let line = |value: i32| OriginZeroLine(value.clamp(i16::MIN as i32, i16::MAX as i32) as i16);
24 Line { start: line(position), end: line(position + span) }
25}
26
27#[allow(clippy::too_many_arguments)]
32pub(super) fn place_grid_items<'a, S, ChildIter>(
33 cell_occupancy_matrix: &mut CellOccupancyMatrix,
34 items: &mut Vec<GridItem>,
35 children_iter: impl Fn() -> ChildIter,
36 grid_auto_flow: GridAutoFlow,
37 align_items: AlignItems,
38 justify_items: AlignItems,
39 named_line_resolver: &NamedLineResolver<<S as CoreStyle>::CustomIdent>,
40) where
41 S: GridItemStyle + 'a,
42 ChildIter: Iterator<Item = (usize, NodeId, S)>,
43{
44 let primary_axis = grid_auto_flow.primary_axis();
45 let secondary_axis = primary_axis.other_axis();
46 let explicit_col_count = cell_occupancy_matrix.track_counts(AbsoluteAxis::Horizontal).explicit;
47
48 let map_child_style_to_origin_zero_placement = {
49 let explicit_row_count = cell_occupancy_matrix.track_counts(AbsoluteAxis::Vertical).explicit;
50 move |(index, node, style): (usize, NodeId, S)| -> (_, _, _, S) {
51 let origin_zero_placement = InBothAbsAxis {
52 horizontal: named_line_resolver
53 .resolve_column_names(&style.grid_column())
54 .map(|placement| placement.into_origin_zero_placement(explicit_col_count)),
55 vertical: named_line_resolver
56 .resolve_row_names(&style.grid_row())
57 .map(|placement| placement.into_origin_zero_placement(explicit_row_count)),
58 };
59 (index, node, origin_zero_placement, style)
60 }
61 };
62
63 let mut idx = 0;
65 children_iter()
66 .map(map_child_style_to_origin_zero_placement)
67 .filter(|(_, _, placement, _)| placement.horizontal.is_definite() && placement.vertical.is_definite())
68 .for_each(|(index, child_node, child_placement, style)| {
69 idx += 1;
70 #[cfg(test)]
71 println!("Definite Item {idx}\n==============");
72
73 let (row_span, col_span) = place_definite_grid_item(child_placement, primary_axis);
74 record_grid_placement(
75 cell_occupancy_matrix,
76 items,
77 child_node,
78 index,
79 style,
80 align_items,
81 justify_items,
82 primary_axis,
83 row_span,
84 col_span,
85 CellOccupancyState::DefinitelyPlaced,
86 );
87 });
88
89 let mut idx = 0;
91 children_iter()
92 .map(map_child_style_to_origin_zero_placement)
93 .filter(|(_, _, placement, _)| {
94 placement.get(secondary_axis).is_definite() && !placement.get(primary_axis).is_definite()
95 })
96 .for_each(|(index, child_node, child_placement, style)| {
97 idx += 1;
98 #[cfg(test)]
99 println!("Definite Secondary Item {idx}\n==============");
100
101 let (primary_span, secondary_span) =
102 place_definite_secondary_axis_item(&*cell_occupancy_matrix, child_placement, grid_auto_flow);
103
104 record_grid_placement(
105 cell_occupancy_matrix,
106 items,
107 child_node,
108 index,
109 style,
110 align_items,
111 justify_items,
112 primary_axis,
113 primary_span,
114 secondary_span,
115 CellOccupancyState::AutoPlaced,
116 );
117 });
118
119 let primary_axis = grid_auto_flow.primary_axis();
139 let secondary_axis = primary_axis.other_axis();
140 let primary_axis_grid_start_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_start_line();
141 let secondary_axis_grid_start_line = cell_occupancy_matrix.track_counts(secondary_axis).implicit_start_line();
142 let grid_start_position = (primary_axis_grid_start_line, secondary_axis_grid_start_line);
143 let mut grid_position = grid_start_position;
144 let mut idx = 0;
145 children_iter()
146 .map(map_child_style_to_origin_zero_placement)
147 .filter(|(_, _, placement, _)| !placement.get(secondary_axis).is_definite())
148 .for_each(|(index, child_node, child_placement, style)| {
149 idx += 1;
150 #[cfg(test)]
151 println!("\nAuto Item {idx}\n==============");
152
153 let (primary_span, secondary_span) = place_indefinitely_positioned_item(
155 &*cell_occupancy_matrix,
156 child_placement,
157 grid_auto_flow,
158 grid_position,
159 );
160
161 record_grid_placement(
163 cell_occupancy_matrix,
164 items,
165 child_node,
166 index,
167 style,
168 align_items,
169 justify_items,
170 primary_axis,
171 primary_span,
172 secondary_span,
173 CellOccupancyState::AutoPlaced,
174 );
175
176 grid_position = match grid_auto_flow.is_dense() {
179 true => grid_start_position,
180 false => (primary_span.end, secondary_span.start),
181 };
182 });
183}
184
185fn place_definite_grid_item(
188 placement: InBothAbsAxis<Line<OriginZeroGridPlacement>>,
189 primary_axis: AbsoluteAxis,
190) -> (Line<OriginZeroLine>, Line<OriginZeroLine>) {
191 let primary_span = placement.get(primary_axis).resolve_definite_grid_lines();
193 let secondary_span = placement.get(primary_axis.other_axis()).resolve_definite_grid_lines();
194
195 (primary_span, secondary_span)
196}
197
198fn place_definite_secondary_axis_item(
201 cell_occupancy_matrix: &CellOccupancyMatrix,
202 placement: InBothAbsAxis<Line<OriginZeroGridPlacement>>,
203 auto_flow: GridAutoFlow,
204) -> (Line<OriginZeroLine>, Line<OriginZeroLine>) {
205 let primary_axis = auto_flow.primary_axis();
206 let secondary_axis = primary_axis.other_axis();
207 let primary_axis_grid_start_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_start_line();
208
209 let secondary_axis_placement = placement.get(secondary_axis).resolve_definite_grid_lines();
210 let starting_position = match auto_flow.is_dense() {
211 true => primary_axis_grid_start_line,
212 false => cell_occupancy_matrix
213 .last_of_type(primary_axis, secondary_axis_placement.start, CellOccupancyState::AutoPlaced)
214 .unwrap_or(primary_axis_grid_start_line),
215 };
216 let primary_axis_span = placement.get(primary_axis).indefinite_span();
217
218 let mut position: OriginZeroLine = starting_position;
219 loop {
220 let primary_axis_placement = resolve_indefinite_grid_span(position, primary_axis_span);
221
222 let collision = cell_occupancy_matrix.line_area_collision_jump(
223 primary_axis,
224 primary_axis_placement,
225 secondary_axis_placement,
226 );
227
228 match collision {
229 None => return (primary_axis_placement, secondary_axis_placement),
230 Some(next_position) => position = next_position,
231 }
232 }
233}
234
235fn place_indefinitely_positioned_item(
238 cell_occupancy_matrix: &CellOccupancyMatrix,
239 placement: InBothAbsAxis<Line<OriginZeroGridPlacement>>,
240 auto_flow: GridAutoFlow,
241 grid_position: (OriginZeroLine, OriginZeroLine),
242) -> (Line<OriginZeroLine>, Line<OriginZeroLine>) {
243 let primary_axis = auto_flow.primary_axis();
244 let secondary_axis = primary_axis.other_axis();
245
246 let primary_placement_style = placement.get(primary_axis);
247 let secondary_placement_style = placement.get(secondary_axis);
248
249 let secondary_span = secondary_placement_style.indefinite_span();
250 let has_definite_primary_axis_position = primary_placement_style.is_definite();
251 let primary_axis_grid_start_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_start_line();
252 let primary_axis_grid_end_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_end_line();
253 let secondary_axis_grid_start_line = cell_occupancy_matrix.track_counts(secondary_axis).implicit_start_line();
254
255 let (mut primary_idx, mut secondary_idx) = grid_position;
256
257 if has_definite_primary_axis_position {
258 let primary_span = primary_placement_style.resolve_definite_grid_lines();
259
260 secondary_idx = match auto_flow.is_dense() {
262 true => secondary_axis_grid_start_line,
264 false => {
265 if primary_span.start < primary_idx {
266 advance_position(secondary_idx)
267 } else {
268 secondary_idx
269 }
270 }
271 };
272
273 loop {
276 let secondary_span = resolve_indefinite_grid_span(secondary_idx, secondary_span);
277
278 let collision =
280 cell_occupancy_matrix.line_area_collision_jump(secondary_axis, secondary_span, primary_span);
281 if let Some(next_position) = collision {
282 secondary_idx = next_position;
283 continue;
284 }
285
286 return (primary_span, secondary_span);
288 }
289 } else {
290 let primary_span = primary_placement_style.indefinite_span();
291
292 let spans_all_primary_tracks = primary_span as usize >= cell_occupancy_matrix.track_counts(primary_axis).len();
295
296 loop {
300 let primary_span = resolve_indefinite_grid_span(primary_idx, primary_span);
301 let secondary_span = resolve_indefinite_grid_span(secondary_idx, secondary_span);
302
303 let primary_out_of_bounds = primary_span.end > primary_axis_grid_end_line;
306 if primary_out_of_bounds {
307 if primary_idx == primary_axis_grid_start_line {
311 return (primary_span, secondary_span);
312 }
313 secondary_idx = advance_position(secondary_idx);
314 primary_idx = primary_axis_grid_start_line;
315 continue;
316 }
317
318 if spans_all_primary_tracks {
322 match cell_occupancy_matrix.occupied_track_jump(secondary_axis, secondary_span) {
323 Some(next_position) => {
324 secondary_idx = next_position;
325 primary_idx = primary_axis_grid_start_line;
326 continue;
327 }
328 None => return (primary_span, secondary_span),
329 }
330 }
331
332 let collision = cell_occupancy_matrix.line_area_collision_jump(primary_axis, primary_span, secondary_span);
334 if let Some(next_position) = collision {
335 primary_idx = next_position;
336 continue;
337 }
338
339 return (primary_span, secondary_span);
341 }
342 }
343}
344
345fn clamp_span_to_limited_grid(span: Line<OriginZeroLine>) -> Line<OriginZeroLine> {
350 let start = span.start.0.clamp(MIN_OZ_LINE, MAX_OZ_LINE - 1);
351 let end = span.end.0.clamp(start + 1, MAX_OZ_LINE);
352 Line { start: OriginZeroLine(start), end: OriginZeroLine(end) }
353}
354
355#[allow(clippy::too_many_arguments)]
358fn record_grid_placement<S: GridItemStyle>(
359 cell_occupancy_matrix: &mut CellOccupancyMatrix,
360 items: &mut Vec<GridItem>,
361 node: NodeId,
362 index: usize,
363 style: S,
364 parent_align_items: AlignItems,
365 parent_justify_items: AlignItems,
366 primary_axis: AbsoluteAxis,
367 primary_span: Line<OriginZeroLine>,
368 secondary_span: Line<OriginZeroLine>,
369 placement_type: CellOccupancyState,
370) {
371 #[cfg(test)]
372 println!("BEFORE placement:");
373 #[cfg(test)]
374 println!("{cell_occupancy_matrix:?}");
375
376 let primary_span = clamp_span_to_limited_grid(primary_span);
379 let secondary_span = clamp_span_to_limited_grid(secondary_span);
380
381 cell_occupancy_matrix.mark_area_as(primary_axis, primary_span, secondary_span, placement_type);
383
384 let (col_span, row_span) = match primary_axis {
386 AbsoluteAxis::Horizontal => (primary_span, secondary_span),
387 AbsoluteAxis::Vertical => (secondary_span, primary_span),
388 };
389 items.push(GridItem::new_with_placement_style_and_order(
390 node,
391 col_span,
392 row_span,
393 style,
394 parent_align_items,
395 parent_justify_items,
396 index as u16,
397 ));
398
399 #[cfg(test)]
400 println!("AFTER placement:");
401 #[cfg(test)]
402 println!("{cell_occupancy_matrix:?}");
403 #[cfg(test)]
404 println!("\n");
405}
406
407#[cfg(test)]
408mod tests {
409 use super::*;
410
411 mod test_placement_algorithm {
412 use crate::compute::grid::implicit_grid::compute_grid_size_estimate;
413 use crate::compute::grid::types::TrackCounts;
414 use crate::compute::grid::util::*;
415 use crate::compute::grid::CellOccupancyMatrix;
416 use crate::compute::grid::NamedLineResolver;
417 use crate::compute::grid::OriginZeroLine;
418 use crate::prelude::*;
419 use crate::style::GridAutoFlow;
420
421 use super::super::place_grid_items;
422
423 type ExpectedPlacement = (i16, i16, i16, i16);
424
425 fn placement_test_runner(
426 explicit_col_count: u16,
427 explicit_row_count: u16,
428 children: Vec<(usize, Style, ExpectedPlacement)>,
429 expected_col_counts: TrackCounts,
430 expected_row_counts: TrackCounts,
431 flow: GridAutoFlow,
432 ) {
433 let children_iter = || children.iter().map(|(index, style, _)| (*index, NodeId::from(*index), style));
435 let child_styles_iter = children.iter().map(|(_, style, _)| style);
436 let estimated_sizes = compute_grid_size_estimate(explicit_col_count, explicit_row_count, child_styles_iter);
437 let mut items = Vec::new();
438 let mut cell_occupancy_matrix =
439 CellOccupancyMatrix::with_track_counts(estimated_sizes.0, estimated_sizes.1);
440 let mut name_resolver = NamedLineResolver::new(&Style::DEFAULT, 0, 0);
441 name_resolver.set_explicit_column_count(explicit_col_count);
442 name_resolver.set_explicit_row_count(explicit_row_count);
443
444 place_grid_items(
446 &mut cell_occupancy_matrix,
447 &mut items,
448 children_iter,
449 flow,
450 AlignSelf::START,
451 AlignSelf::START,
452 &name_resolver,
454 );
455
456 let mut sorted_children = children.clone();
458 sorted_children.sort_by_key(|child| child.0);
459 for (idx, ((id, _style, expected_placement), item)) in sorted_children.iter().zip(items.iter()).enumerate()
460 {
461 assert_eq!(item.node, NodeId::from(*id));
462 let actual_placement = (item.column.start, item.column.end, item.row.start, item.row.end);
463 assert_eq!(actual_placement, (*expected_placement).into_oz(), "Item {idx} (0-indexed)");
464 }
465
466 let actual_row_counts = *cell_occupancy_matrix.track_counts(crate::compute::grid::AbsoluteAxis::Vertical);
468 assert_eq!(actual_row_counts, expected_row_counts, "row track counts");
469 let actual_col_counts = *cell_occupancy_matrix.track_counts(crate::compute::grid::AbsoluteAxis::Horizontal);
470 assert_eq!(actual_col_counts, expected_col_counts, "column track counts");
471 }
472
473 #[test]
474 fn test_only_fixed_placement() {
475 let flow = GridAutoFlow::Row;
476 let explicit_col_count = 2;
477 let explicit_row_count = 2;
478 let children = {
479 vec![
480 (1, (line(1), auto(), line(1), auto()).into_grid_child(), (0, 1, 0, 1)),
482 (2, (line(-4), auto(), line(-3), auto()).into_grid_child(), (-1, 0, 0, 1)),
483 (3, (line(-3), auto(), line(-4), auto()).into_grid_child(), (0, 1, -1, 0)),
484 (4, (line(3), span(2), line(5), auto()).into_grid_child(), (2, 4, 4, 5)),
485 ]
486 };
487 let expected_cols = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 2 };
488 let expected_rows = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 3 };
489 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
490 }
491
492 #[test]
493 fn test_placement_spanning_origin() {
494 let flow = GridAutoFlow::Row;
495 let explicit_col_count = 2;
496 let explicit_row_count = 2;
497 let children = {
498 vec![
499 (1, (line(-1), line(-1), line(-1), line(-1)).into_grid_child(), (2, 3, 2, 3)),
501 (2, (line(-1), span(2), line(-1), span(2)).into_grid_child(), (2, 4, 2, 4)),
502 (3, (line(-4), line(-4), line(-4), line(-4)).into_grid_child(), (-1, 0, -1, 0)),
503 (4, (line(-4), span(2), line(-4), span(2)).into_grid_child(), (-1, 1, -1, 1)),
504 ]
505 };
506 let expected_cols = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 2 };
507 let expected_rows = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 2 };
508 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
509 }
510
511 #[test]
512 fn test_only_auto_placement_row_flow() {
513 let flow = GridAutoFlow::Row;
514 let explicit_col_count = 2;
515 let explicit_row_count = 2;
516 let children = {
517 let auto_child = (auto(), auto(), auto(), auto()).into_grid_child();
518 vec![
519 (1, auto_child.clone(), (0, 1, 0, 1)),
521 (2, auto_child.clone(), (1, 2, 0, 1)),
522 (3, auto_child.clone(), (0, 1, 1, 2)),
523 (4, auto_child.clone(), (1, 2, 1, 2)),
524 (5, auto_child.clone(), (0, 1, 2, 3)),
525 (6, auto_child.clone(), (1, 2, 2, 3)),
526 (7, auto_child.clone(), (0, 1, 3, 4)),
527 (8, auto_child.clone(), (1, 2, 3, 4)),
528 ]
529 };
530 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
531 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 2 };
532 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
533 }
534
535 #[test]
536 fn test_only_auto_placement_column_flow() {
537 let flow = GridAutoFlow::Column;
538 let explicit_col_count = 2;
539 let explicit_row_count = 2;
540 let children = {
541 let auto_child = (auto(), auto(), auto(), auto()).into_grid_child();
542 vec![
543 (1, auto_child.clone(), (0, 1, 0, 1)),
545 (2, auto_child.clone(), (0, 1, 1, 2)),
546 (3, auto_child.clone(), (1, 2, 0, 1)),
547 (4, auto_child.clone(), (1, 2, 1, 2)),
548 (5, auto_child.clone(), (2, 3, 0, 1)),
549 (6, auto_child.clone(), (2, 3, 1, 2)),
550 (7, auto_child.clone(), (3, 4, 0, 1)),
551 (8, auto_child.clone(), (3, 4, 1, 2)),
552 ]
553 };
554 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 2 };
555 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
556 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
557 }
558
559 #[test]
560 fn test_oversized_item() {
561 let flow = GridAutoFlow::Row;
562 let explicit_col_count = 2;
563 let explicit_row_count = 2;
564 let children = {
565 vec![
566 (1, (span(5), auto(), auto(), auto()).into_grid_child(), (0, 5, 0, 1)),
568 ]
569 };
570 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 3 };
571 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
572 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
573 }
574
575 #[test]
576 fn test_fixed_in_secondary_axis() {
577 let flow = GridAutoFlow::Row;
578 let explicit_col_count = 2;
579 let explicit_row_count = 2;
580 let children = {
581 vec![
582 (1, (span(2), auto(), line(1), auto()).into_grid_child(), (0, 2, 0, 1)),
584 (2, (auto(), auto(), line(2), auto()).into_grid_child(), (0, 1, 1, 2)),
585 (3, (auto(), auto(), line(1), auto()).into_grid_child(), (2, 3, 0, 1)),
586 (4, (auto(), auto(), line(4), auto()).into_grid_child(), (0, 1, 3, 4)),
587 ]
588 };
589 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 1 };
590 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 2 };
591 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
592 }
593
594 #[test]
595 fn test_definite_in_secondary_axis_with_fully_definite_negative() {
596 let flow = GridAutoFlow::Row;
597 let explicit_col_count = 2;
598 let explicit_row_count = 2;
599 let children = {
600 vec![
601 (2, (auto(), auto(), line(2), auto()).into_grid_child(), (0, 1, 1, 2)),
603 (1, (line(-4), auto(), line(2), auto()).into_grid_child(), (-1, 0, 1, 2)),
604 (3, (auto(), auto(), line(1), auto()).into_grid_child(), (-1, 0, 0, 1)),
605 ]
606 };
607 let expected_cols = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 0 };
608 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
609 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
610 }
611
612 #[test]
613 fn test_dense_packing_algorithm() {
614 let flow = GridAutoFlow::RowDense;
615 let explicit_col_count = 4;
616 let explicit_row_count = 4;
617 let children = {
618 vec![
619 (1, (line(2), auto(), line(1), auto()).into_grid_child(), (1, 2, 0, 1)), (2, (span(2), auto(), auto(), auto()).into_grid_child(), (2, 4, 0, 1)), (3, (auto(), auto(), auto(), auto()).into_grid_child(), (0, 1, 0, 1)), ]
624 };
625 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
626 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
627 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
628 }
629
630 #[test]
631 fn test_sparse_packing_algorithm() {
632 let flow = GridAutoFlow::Row;
633 let explicit_col_count = 4;
634 let explicit_row_count = 4;
635 let children = {
636 vec![
637 (1, (auto(), span(3), auto(), auto()).into_grid_child(), (0, 3, 0, 1)), (2, (auto(), span(3), auto(), auto()).into_grid_child(), (0, 3, 1, 2)), (3, (auto(), span(1), auto(), auto()).into_grid_child(), (3, 4, 1, 2)), ]
642 };
643 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
644 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
645 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
646 }
647
648 #[test]
649 fn test_auto_placement_in_negative_tracks() {
650 let flow = GridAutoFlow::RowDense;
651 let explicit_col_count = 2;
652 let explicit_row_count = 2;
653 let children = {
654 vec![
655 (1, (line(-5), auto(), line(1), auto()).into_grid_child(), (-2, -1, 0, 1)), (2, (auto(), auto(), line(2), auto()).into_grid_child(), (-2, -1, 1, 2)), (3, (auto(), auto(), auto(), auto()).into_grid_child(), (-1, 0, 0, 1)), ]
660 };
661 let expected_cols = TrackCounts { negative_implicit: 2, explicit: 2, positive_implicit: 0 };
662 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
663 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
664 }
665
666 #[test]
667 fn test_overlarge_placement_is_clamped() {
668 let explicit_col_count = 9_000;
669 let explicit_row_count = 0;
670 let style = (line(-19_005), auto(), auto(), auto()).into_grid_child();
671 let children = [(0, style)];
672 let estimated_sizes = compute_grid_size_estimate(
673 explicit_col_count,
674 explicit_row_count,
675 children.iter().map(|(_, style)| style),
676 );
677 let mut items = Vec::new();
678 let mut cell_occupancy_matrix =
679 CellOccupancyMatrix::with_track_counts(estimated_sizes.0, estimated_sizes.1);
680 let mut name_resolver = NamedLineResolver::new(&Style::DEFAULT, 0, 0);
681 name_resolver.set_explicit_column_count(explicit_col_count);
682 name_resolver.set_explicit_row_count(explicit_row_count);
683 place_grid_items(
684 &mut cell_occupancy_matrix,
685 &mut items,
686 || children.iter().map(|(index, style)| (*index, NodeId::from(*index), style)),
687 GridAutoFlow::Row,
688 AlignSelf::START,
689 AlignSelf::START,
690 &name_resolver,
691 );
692 assert_eq!(items[0].column, Line { start: OriginZeroLine(-10_000), end: OriginZeroLine(-9_999) });
693 }
694 }
695
696 #[test]
697 fn auto_placement_cursor_saturates_at_integer_bounds() {
698 assert_eq!(advance_position(OriginZeroLine(i16::MAX)), OriginZeroLine(i16::MAX));
699 }
700
701 #[test]
702 fn indefinite_spans_saturate_at_integer_bounds() {
703 assert_eq!(
704 resolve_indefinite_grid_span(OriginZeroLine(i16::MAX), 1),
705 Line { start: OriginZeroLine(i16::MAX), end: OriginZeroLine(i16::MAX) }
706 );
707 }
708}