1use super::types::{CellOccupancyMatrix, CellOccupancyState, GridItem};
4use super::{OriginZeroLine, MAX_OZ_LINE, MIN_OZ_LINE};
5use crate::geometry::Line;
6use crate::geometry::{AbsoluteAxis, InBothAbsAxis};
7use crate::style::{GridAutoFlow, OriginZeroGridPlacement};
8
9#[inline]
10fn advance_position(position: OriginZeroLine) -> OriginZeroLine {
12 OriginZeroLine(position.0.saturating_add(1))
13}
14
15#[inline]
16fn resolve_indefinite_grid_span(position: OriginZeroLine, span: u16) -> Line<OriginZeroLine> {
18 let position = position.0 as i32;
19 let span = span as i32;
20 let line = |value: i32| OriginZeroLine(value.clamp(i16::MIN as i32, i16::MAX as i32) as i16);
21 Line { start: line(position), end: line(position + span) }
22}
23
24pub(super) type ItemPlacement = InBothAbsAxis<Line<OriginZeroGridPlacement>>;
26
27pub(super) fn place_grid_items(
36 cell_occupancy_matrix: &mut CellOccupancyMatrix,
37 items: &mut [GridItem],
38 placements: &[ItemPlacement],
39 grid_auto_flow: GridAutoFlow,
40) {
41 debug_assert_eq!(items.len(), placements.len());
42 let primary_axis = grid_auto_flow.primary_axis();
43 let secondary_axis = primary_axis.other_axis();
44
45 for (item, &placement) in items.iter_mut().zip(placements.iter()) {
47 if !(placement.horizontal.is_definite() && placement.vertical.is_definite()) {
48 continue;
49 }
50 #[cfg(test)]
51 println!("Definite Item {}\n==============", item.source_order);
52
53 let (row_span, col_span) = place_definite_grid_item(placement, primary_axis);
54 record_grid_placement(
55 cell_occupancy_matrix,
56 item,
57 primary_axis,
58 row_span,
59 col_span,
60 CellOccupancyState::DefinitelyPlaced,
61 );
62 }
63
64 for (item, &placement) in items.iter_mut().zip(placements.iter()) {
66 if !(placement.get(secondary_axis).is_definite() && !placement.get(primary_axis).is_definite()) {
67 continue;
68 }
69 #[cfg(test)]
70 println!("Definite Secondary Item {}\n==============", item.source_order);
71
72 let (primary_span, secondary_span) =
73 place_definite_secondary_axis_item(&*cell_occupancy_matrix, placement, grid_auto_flow);
74
75 record_grid_placement(
76 cell_occupancy_matrix,
77 item,
78 primary_axis,
79 primary_span,
80 secondary_span,
81 CellOccupancyState::AutoPlaced,
82 );
83 }
84
85 let primary_axis = grid_auto_flow.primary_axis();
105 let secondary_axis = primary_axis.other_axis();
106 let primary_axis_grid_start_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_start_line();
107 let secondary_axis_grid_start_line = cell_occupancy_matrix.track_counts(secondary_axis).implicit_start_line();
108 let grid_start_position = (primary_axis_grid_start_line, secondary_axis_grid_start_line);
109 let mut grid_position = grid_start_position;
110 for (item, &placement) in items.iter_mut().zip(placements.iter()) {
111 if placement.get(secondary_axis).is_definite() {
112 continue;
113 }
114 #[cfg(test)]
115 println!("\nAuto Item {}\n==============", item.source_order);
116
117 let (primary_span, secondary_span) =
119 place_indefinitely_positioned_item(&*cell_occupancy_matrix, placement, grid_auto_flow, grid_position);
120
121 record_grid_placement(
123 cell_occupancy_matrix,
124 item,
125 primary_axis,
126 primary_span,
127 secondary_span,
128 CellOccupancyState::AutoPlaced,
129 );
130
131 grid_position = match grid_auto_flow.is_dense() {
134 true => grid_start_position,
135 false => (primary_span.end, secondary_span.start),
136 };
137 }
138}
139
140fn place_definite_grid_item(
143 placement: ItemPlacement,
144 primary_axis: AbsoluteAxis,
145) -> (Line<OriginZeroLine>, Line<OriginZeroLine>) {
146 let primary_span = placement.get(primary_axis).resolve_definite_grid_lines();
148 let secondary_span = placement.get(primary_axis.other_axis()).resolve_definite_grid_lines();
149
150 (primary_span, secondary_span)
151}
152
153fn place_definite_secondary_axis_item(
156 cell_occupancy_matrix: &CellOccupancyMatrix,
157 placement: ItemPlacement,
158 auto_flow: GridAutoFlow,
159) -> (Line<OriginZeroLine>, Line<OriginZeroLine>) {
160 let primary_axis = auto_flow.primary_axis();
161 let secondary_axis = primary_axis.other_axis();
162 let primary_axis_grid_start_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_start_line();
163
164 let secondary_axis_placement = placement.get(secondary_axis).resolve_definite_grid_lines();
165 let starting_position = match auto_flow.is_dense() {
166 true => primary_axis_grid_start_line,
167 false => cell_occupancy_matrix
168 .auto_placement_cursor(primary_axis, secondary_axis_placement.start)
169 .unwrap_or(primary_axis_grid_start_line),
170 };
171 let primary_axis_span = placement.get(primary_axis).indefinite_span();
172
173 let mut position: OriginZeroLine = starting_position;
174 loop {
175 let primary_axis_placement = resolve_indefinite_grid_span(position, primary_axis_span);
176
177 let collision = cell_occupancy_matrix.line_area_collision_jump(
178 primary_axis,
179 primary_axis_placement,
180 secondary_axis_placement,
181 );
182
183 match collision {
184 None => return (primary_axis_placement, secondary_axis_placement),
185 Some(next_position) => position = next_position,
186 }
187 }
188}
189
190fn place_indefinitely_positioned_item(
193 cell_occupancy_matrix: &CellOccupancyMatrix,
194 placement: ItemPlacement,
195 auto_flow: GridAutoFlow,
196 grid_position: (OriginZeroLine, OriginZeroLine),
197) -> (Line<OriginZeroLine>, Line<OriginZeroLine>) {
198 let primary_axis = auto_flow.primary_axis();
199 let secondary_axis = primary_axis.other_axis();
200
201 let primary_placement_style = placement.get(primary_axis);
202 let secondary_placement_style = placement.get(secondary_axis);
203
204 let secondary_span = secondary_placement_style.indefinite_span();
205 let has_definite_primary_axis_position = primary_placement_style.is_definite();
206 let primary_axis_grid_start_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_start_line();
207 let primary_axis_grid_end_line = cell_occupancy_matrix.track_counts(primary_axis).implicit_end_line();
208 let secondary_axis_grid_start_line = cell_occupancy_matrix.track_counts(secondary_axis).implicit_start_line();
209
210 let (mut primary_idx, mut secondary_idx) = grid_position;
211
212 if has_definite_primary_axis_position {
213 let primary_span = primary_placement_style.resolve_definite_grid_lines();
214
215 secondary_idx = match auto_flow.is_dense() {
217 true => secondary_axis_grid_start_line,
219 false => {
220 if primary_span.start < primary_idx {
221 advance_position(secondary_idx)
222 } else {
223 secondary_idx
224 }
225 }
226 };
227
228 loop {
231 let secondary_span = resolve_indefinite_grid_span(secondary_idx, secondary_span);
232
233 let collision =
235 cell_occupancy_matrix.line_area_collision_jump(secondary_axis, secondary_span, primary_span);
236 if let Some(next_position) = collision {
237 secondary_idx = next_position;
238 continue;
239 }
240
241 return (primary_span, secondary_span);
243 }
244 } else {
245 let primary_span = primary_placement_style.indefinite_span();
246
247 let spans_all_primary_tracks = primary_span as usize >= cell_occupancy_matrix.track_counts(primary_axis).len();
250
251 loop {
255 let primary_span = resolve_indefinite_grid_span(primary_idx, primary_span);
256 let secondary_span = resolve_indefinite_grid_span(secondary_idx, secondary_span);
257
258 let primary_out_of_bounds = primary_span.end > primary_axis_grid_end_line;
261 if primary_out_of_bounds {
262 if primary_idx == primary_axis_grid_start_line {
266 return (primary_span, secondary_span);
267 }
268 secondary_idx = advance_position(secondary_idx);
269 primary_idx = primary_axis_grid_start_line;
270 continue;
271 }
272
273 if spans_all_primary_tracks {
277 match cell_occupancy_matrix.occupied_track_jump(secondary_axis, secondary_span) {
278 Some(next_position) => {
279 secondary_idx = next_position;
280 primary_idx = primary_axis_grid_start_line;
281 continue;
282 }
283 None => return (primary_span, secondary_span),
284 }
285 }
286
287 let collision = cell_occupancy_matrix.line_area_collision_jump(primary_axis, primary_span, secondary_span);
289 if let Some(next_position) = collision {
290 primary_idx = next_position;
291 continue;
292 }
293
294 return (primary_span, secondary_span);
296 }
297 }
298}
299
300fn clamp_span_to_limited_grid(span: Line<OriginZeroLine>) -> Line<OriginZeroLine> {
305 let start = span.start.0.clamp(MIN_OZ_LINE, MAX_OZ_LINE - 1);
306 let end = span.end.0.clamp(start + 1, MAX_OZ_LINE);
307 Line { start: OriginZeroLine(start), end: OriginZeroLine(end) }
308}
309
310fn record_grid_placement(
313 cell_occupancy_matrix: &mut CellOccupancyMatrix,
314 item: &mut GridItem,
315 primary_axis: AbsoluteAxis,
316 primary_span: Line<OriginZeroLine>,
317 secondary_span: Line<OriginZeroLine>,
318 placement_type: CellOccupancyState,
319) {
320 #[cfg(test)]
321 println!("BEFORE placement:");
322 #[cfg(test)]
323 println!("{cell_occupancy_matrix:?}");
324
325 let primary_span = clamp_span_to_limited_grid(primary_span);
328 let secondary_span = clamp_span_to_limited_grid(secondary_span);
329
330 cell_occupancy_matrix.mark_area_as(primary_axis, primary_span, secondary_span, placement_type);
332
333 let (col_span, row_span) = match primary_axis {
335 AbsoluteAxis::Horizontal => (primary_span, secondary_span),
336 AbsoluteAxis::Vertical => (secondary_span, primary_span),
337 };
338 item.column = col_span;
339 item.row = row_span;
340
341 #[cfg(test)]
342 println!("AFTER placement:");
343 #[cfg(test)]
344 println!("{cell_occupancy_matrix:?}");
345 #[cfg(test)]
346 println!("\n");
347}
348
349#[cfg(test)]
350mod tests {
351 use super::*;
352
353 mod test_placement_algorithm {
354 use crate::compute::grid::implicit_grid::compute_grid_size_estimate;
355 use crate::compute::grid::types::TrackCounts;
356 use crate::compute::grid::util::test_helpers::{grid_items, resolve_named_lines};
357 use crate::compute::grid::util::*;
358 use crate::compute::grid::CellOccupancyMatrix;
359 use crate::compute::grid::NamedLineResolver;
360 use crate::compute::grid::OriginZeroLine;
361 use crate::prelude::*;
362 use crate::style::GridAutoFlow;
363
364 use super::super::place_grid_items;
365
366 type ExpectedPlacement = (i16, i16, i16, i16);
367
368 fn placement_test_runner(
369 explicit_col_count: u16,
370 explicit_row_count: u16,
371 children: Vec<(usize, Style, ExpectedPlacement)>,
372 expected_col_counts: TrackCounts,
373 expected_row_counts: TrackCounts,
374 flow: GridAutoFlow,
375 ) {
376 let mut name_resolver = NamedLineResolver::new(&Style::DEFAULT, 0, 0);
378 name_resolver.set_explicit_column_count(explicit_col_count);
379 name_resolver.set_explicit_row_count(explicit_row_count);
380 let mut items = grid_items(children.iter().map(|(index, style, _)| (*index, style)));
381 let placements = resolve_named_lines(
382 children.iter().map(|(_, style, _)| style),
383 &name_resolver,
384 explicit_col_count,
385 explicit_row_count,
386 );
387 let estimated_sizes = compute_grid_size_estimate(explicit_col_count, explicit_row_count, &placements);
388 let mut cell_occupancy_matrix =
389 CellOccupancyMatrix::with_track_counts(estimated_sizes.0, estimated_sizes.1);
390
391 place_grid_items(&mut cell_occupancy_matrix, &mut items, &placements, flow);
393
394 assert_eq!(items.len(), children.len());
396 for (idx, ((id, _style, expected_placement), item)) in children.iter().zip(items.iter()).enumerate() {
397 assert_eq!(item.node, NodeId::from(*id));
398 let actual_placement = (item.column.start, item.column.end, item.row.start, item.row.end);
399 assert_eq!(actual_placement, (*expected_placement).into_oz(), "Item {idx} (0-indexed)");
400 }
401
402 let actual_row_counts = *cell_occupancy_matrix.track_counts(crate::compute::grid::AbsoluteAxis::Vertical);
404 assert_eq!(actual_row_counts, expected_row_counts, "row track counts");
405 let actual_col_counts = *cell_occupancy_matrix.track_counts(crate::compute::grid::AbsoluteAxis::Horizontal);
406 assert_eq!(actual_col_counts, expected_col_counts, "column track counts");
407 }
408
409 #[test]
410 fn test_only_fixed_placement() {
411 let flow = GridAutoFlow::Row;
412 let explicit_col_count = 2;
413 let explicit_row_count = 2;
414 let children = {
415 vec![
416 (1, (line(1), auto(), line(1), auto()).into_grid_child(), (0, 1, 0, 1)),
418 (2, (line(-4), auto(), line(-3), auto()).into_grid_child(), (-1, 0, 0, 1)),
419 (3, (line(-3), auto(), line(-4), auto()).into_grid_child(), (0, 1, -1, 0)),
420 (4, (line(3), span(2), line(5), auto()).into_grid_child(), (2, 4, 4, 5)),
421 ]
422 };
423 let expected_cols = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 2 };
424 let expected_rows = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 3 };
425 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
426 }
427
428 #[test]
429 fn test_placement_spanning_origin() {
430 let flow = GridAutoFlow::Row;
431 let explicit_col_count = 2;
432 let explicit_row_count = 2;
433 let children = {
434 vec![
435 (1, (line(-1), line(-1), line(-1), line(-1)).into_grid_child(), (2, 3, 2, 3)),
437 (2, (line(-1), span(2), line(-1), span(2)).into_grid_child(), (2, 4, 2, 4)),
438 (3, (line(-4), line(-4), line(-4), line(-4)).into_grid_child(), (-1, 0, -1, 0)),
439 (4, (line(-4), span(2), line(-4), span(2)).into_grid_child(), (-1, 1, -1, 1)),
440 ]
441 };
442 let expected_cols = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 2 };
443 let expected_rows = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 2 };
444 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
445 }
446
447 #[test]
448 fn test_only_auto_placement_row_flow() {
449 let flow = GridAutoFlow::Row;
450 let explicit_col_count = 2;
451 let explicit_row_count = 2;
452 let children = {
453 let auto_child = (auto(), auto(), auto(), auto()).into_grid_child();
454 vec![
455 (1, auto_child.clone(), (0, 1, 0, 1)),
457 (2, auto_child.clone(), (1, 2, 0, 1)),
458 (3, auto_child.clone(), (0, 1, 1, 2)),
459 (4, auto_child.clone(), (1, 2, 1, 2)),
460 (5, auto_child.clone(), (0, 1, 2, 3)),
461 (6, auto_child.clone(), (1, 2, 2, 3)),
462 (7, auto_child.clone(), (0, 1, 3, 4)),
463 (8, auto_child.clone(), (1, 2, 3, 4)),
464 ]
465 };
466 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
467 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 2 };
468 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
469 }
470
471 #[test]
472 fn test_only_auto_placement_column_flow() {
473 let flow = GridAutoFlow::Column;
474 let explicit_col_count = 2;
475 let explicit_row_count = 2;
476 let children = {
477 let auto_child = (auto(), auto(), auto(), auto()).into_grid_child();
478 vec![
479 (1, auto_child.clone(), (0, 1, 0, 1)),
481 (2, auto_child.clone(), (0, 1, 1, 2)),
482 (3, auto_child.clone(), (1, 2, 0, 1)),
483 (4, auto_child.clone(), (1, 2, 1, 2)),
484 (5, auto_child.clone(), (2, 3, 0, 1)),
485 (6, auto_child.clone(), (2, 3, 1, 2)),
486 (7, auto_child.clone(), (3, 4, 0, 1)),
487 (8, auto_child.clone(), (3, 4, 1, 2)),
488 ]
489 };
490 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 2 };
491 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
492 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
493 }
494
495 #[test]
496 fn test_oversized_item() {
497 let flow = GridAutoFlow::Row;
498 let explicit_col_count = 2;
499 let explicit_row_count = 2;
500 let children = {
501 vec![
502 (1, (span(5), auto(), auto(), auto()).into_grid_child(), (0, 5, 0, 1)),
504 ]
505 };
506 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 3 };
507 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
508 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
509 }
510
511 #[test]
512 fn test_fixed_in_secondary_axis() {
513 let flow = GridAutoFlow::Row;
514 let explicit_col_count = 2;
515 let explicit_row_count = 2;
516 let children = {
517 vec![
518 (1, (span(2), auto(), line(1), auto()).into_grid_child(), (0, 2, 0, 1)),
520 (2, (auto(), auto(), line(2), auto()).into_grid_child(), (0, 1, 1, 2)),
521 (3, (auto(), auto(), line(1), auto()).into_grid_child(), (2, 3, 0, 1)),
522 (4, (auto(), auto(), line(4), auto()).into_grid_child(), (0, 1, 3, 4)),
523 ]
524 };
525 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 1 };
526 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 2 };
527 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
528 }
529
530 #[test]
531 fn test_definite_in_secondary_axis_with_fully_definite_negative() {
532 let flow = GridAutoFlow::Row;
533 let explicit_col_count = 2;
534 let explicit_row_count = 2;
535 let children = {
536 vec![
537 (2, (auto(), auto(), line(2), auto()).into_grid_child(), (0, 1, 1, 2)),
539 (1, (line(-4), auto(), line(2), auto()).into_grid_child(), (-1, 0, 1, 2)),
540 (3, (auto(), auto(), line(1), auto()).into_grid_child(), (-1, 0, 0, 1)),
541 ]
542 };
543 let expected_cols = TrackCounts { negative_implicit: 1, explicit: 2, positive_implicit: 0 };
544 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
545 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
546 }
547
548 #[test]
549 fn test_dense_packing_algorithm() {
550 let flow = GridAutoFlow::RowDense;
551 let explicit_col_count = 4;
552 let explicit_row_count = 4;
553 let children = {
554 vec![
555 (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)), ]
560 };
561 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
562 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
563 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
564 }
565
566 #[test]
567 fn test_sparse_packing_algorithm() {
568 let flow = GridAutoFlow::Row;
569 let explicit_col_count = 4;
570 let explicit_row_count = 4;
571 let children = {
572 vec![
573 (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)), ]
578 };
579 let expected_cols = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
580 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 4, positive_implicit: 0 };
581 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
582 }
583
584 #[test]
585 fn test_auto_placement_in_negative_tracks() {
586 let flow = GridAutoFlow::RowDense;
587 let explicit_col_count = 2;
588 let explicit_row_count = 2;
589 let children = {
590 vec![
591 (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)), ]
596 };
597 let expected_cols = TrackCounts { negative_implicit: 2, explicit: 2, positive_implicit: 0 };
598 let expected_rows = TrackCounts { negative_implicit: 0, explicit: 2, positive_implicit: 0 };
599 placement_test_runner(explicit_col_count, explicit_row_count, children, expected_cols, expected_rows, flow);
600 }
601
602 #[test]
603 fn test_overlarge_placement_is_clamped() {
604 let explicit_col_count = 9_000;
605 let explicit_row_count = 0;
606 let style = (line(-19_005), auto(), auto(), auto()).into_grid_child();
607 let children = [(0usize, style)];
608 let mut name_resolver = NamedLineResolver::new(&Style::DEFAULT, 0, 0);
609 name_resolver.set_explicit_column_count(explicit_col_count);
610 name_resolver.set_explicit_row_count(explicit_row_count);
611 let mut items = grid_items(children.iter().map(|(index, style)| (*index, style)));
612 let placements = resolve_named_lines(
613 children.iter().map(|(_, style)| style),
614 &name_resolver,
615 explicit_col_count,
616 explicit_row_count,
617 );
618 let estimated_sizes = compute_grid_size_estimate(explicit_col_count, explicit_row_count, &placements);
619 let mut cell_occupancy_matrix =
620 CellOccupancyMatrix::with_track_counts(estimated_sizes.0, estimated_sizes.1);
621 place_grid_items(&mut cell_occupancy_matrix, &mut items, &placements, GridAutoFlow::Row);
622 assert_eq!(items[0].column, Line { start: OriginZeroLine(-10_000), end: OriginZeroLine(-9_999) });
623 }
624 }
625
626 #[test]
627 fn auto_placement_cursor_saturates_at_integer_bounds() {
628 assert_eq!(advance_position(OriginZeroLine(i16::MAX)), OriginZeroLine(i16::MAX));
629 }
630
631 #[test]
632 fn indefinite_spans_saturate_at_integer_bounds() {
633 assert_eq!(
634 resolve_indefinite_grid_span(OriginZeroLine(i16::MAX), 1),
635 Line { start: OriginZeroLine(i16::MAX), end: OriginZeroLine(i16::MAX) }
636 );
637 }
638}