tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 499HTML 245JavaScript 8Markdown 71218 Sutichaykuna

⎇ 08c16a7c36ce61a1f6b10a792710e39701a2dffc src/style/grid.rs Rust · 582 siq'ikuna · 25.1 KB Ñawpa willay Pi imata llamkarqan ch'uya

Grid: selectively rerun track sizing (#341) 08c16a7c3 · Nico Burns ·

1//! Style types for CSS Grid layout
2use super::{AlignContent, LengthPercentage, Style};
3use crate::axis::{AbsoluteAxis, AbstractAxis};
4use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine};
5use crate::geometry::{Line, MinMax};
6use crate::style_helpers::*;
7use crate::sys::GridTrackVec;
8use core::cmp::{max, min};
9
10/// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used.
11///
12/// The "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items.
13///
14/// Defaults to [`GridAutoFlow::Row`]
15///
16/// [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow)
17#[derive(Copy, Clone, PartialEq, Eq, Debug)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub enum GridAutoFlow {
20    /// Items are placed by filling each row in turn, adding new rows as necessary
21    Row,
22    /// Items are placed by filling each column in turn, adding new columns as necessary.
23    Column,
24    /// Combines `Row` with the dense packing algorithm.
25    RowDense,
26    /// Combines `Column` with the dense packing algorithm.
27    ColumnDense,
28}
29
30impl Default for GridAutoFlow {
31    fn default() -> Self {
32        Self::Row
33    }
34}
35
36impl GridAutoFlow {
37    /// Whether grid auto placement uses the sparse placement algorithm or the dense placement algorithm
38    /// See: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow#values
39    pub fn is_dense(&self) -> bool {
40        match self {
41            Self::Row | Self::Column => false,
42            Self::RowDense | Self::ColumnDense => true,
43        }
44    }
45
46    /// Whether grid auto placement fills areas row-wise or column-wise
47    /// See: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow#values
48    pub fn primary_axis(&self) -> AbsoluteAxis {
49        match self {
50            Self::Row | Self::RowDense => AbsoluteAxis::Horizontal,
51            Self::Column | Self::ColumnDense => AbsoluteAxis::Vertical,
52        }
53    }
54}
55
56/// A grid line placement specification which is generic over the coordinate system that it uses to define
57/// grid line positions.
58///
59/// GenericGridPlacement<GridLine> is aliased as GridPlacement and is exposed to users of Taffy to define styles.
60/// GenericGridPlacement<OriginZeroLine> is aliased as OriginZeroGridPlacement and is used internally for placement computations.
61///
62/// See [`crate::compute::grid::type::coordinates`] for documentation on the different coordinate systems.
63#[derive(Copy, Clone, PartialEq, Eq, Debug)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65pub enum GenericGridPlacement<LineType: GridCoordinate> {
66    /// Place item according to the auto-placement algorithm, and the parent's grid_auto_flow property
67    Auto,
68    /// Place item at specified line (column or row) index
69    Line(LineType),
70    /// Item should span specified number of tracks (columns or rows)
71    Span(u16),
72}
73
74/// A grid line placement using the normalized OriginZero coordinates to specify line positions.
75pub(crate) type OriginZeroGridPlacement = GenericGridPlacement<OriginZeroLine>;
76
77/// A grid line placement specification. Used for grid-[row/column]-[start/end]. Named tracks are not implemented.
78///
79/// Defaults to [`GridLine::Auto`]
80///
81/// [Specification](https://www.w3.org/TR/css3-grid-layout/#typedef-grid-row-start-grid-line)
82pub type GridPlacement = GenericGridPlacement<GridLine>;
83impl TaffyAuto for GridPlacement {
84    const AUTO: Self = Self::Auto;
85}
86impl TaffyGridLine for GridPlacement {
87    fn from_line_index(index: i16) -> Self {
88        GridPlacement::Line(GridLine::from(index))
89    }
90}
91impl TaffyGridLine for Line<GridPlacement> {
92    fn from_line_index(index: i16) -> Self {
93        Line { start: GridPlacement::from_line_index(index), end: GridPlacement::Auto }
94    }
95}
96impl TaffyGridSpan for GridPlacement {
97    fn from_span(span: u16) -> Self {
98        GridPlacement::Span(span)
99    }
100}
101impl TaffyGridSpan for Line<GridPlacement> {
102    fn from_span(span: u16) -> Self {
103        Line { start: GridPlacement::from_span(span), end: GridPlacement::Auto }
104    }
105}
106
107impl Default for GridPlacement {
108    fn default() -> Self {
109        Self::Auto
110    }
111}
112
113impl GridPlacement {
114    /// Apply a mapping function if the [`GridPlacement`] is a `Track`. Otherwise return `self` unmodified.
115    pub fn into_origin_zero_placement(self, explicit_track_count: u16) -> OriginZeroGridPlacement {
116        match self {
117            Self::Auto => OriginZeroGridPlacement::Auto,
118            Self::Span(span) => OriginZeroGridPlacement::Span(span),
119            // Grid line zero is an invalid index, so it gets treated as Auto
120            // See: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row-start#values
121            Self::Line(line) => match line.as_i16() {
122                0 => OriginZeroGridPlacement::Auto,
123                _ => OriginZeroGridPlacement::Line(line.into_origin_zero_line(explicit_track_count)),
124            },
125        }
126    }
127}
128
129impl<T: GridCoordinate> Line<GenericGridPlacement<T>> {
130    #[inline]
131    /// Whether the track position is definite in this axis (or the item will need auto placement)
132    /// The track position is definite if least one of the start and end positions is a track index
133    pub fn is_definite(&self) -> bool {
134        matches!((self.start, self.end), (GenericGridPlacement::Line(_), _) | (_, GenericGridPlacement::Line(_)))
135    }
136
137    /// Resolves the span for an indefinite placement (a placement that does not consist of two `Track`s).
138    /// Panics if called on a definite placement
139    pub fn indefinite_span(&self) -> u16 {
140        use GenericGridPlacement as GP;
141        match (self.start, self.end) {
142            (GP::Line(_), GP::Auto) => 1,
143            (GP::Auto, GP::Line(_)) => 1,
144            (GP::Auto, GP::Auto) => 1,
145            (GP::Line(_), GP::Span(span)) => span,
146            (GP::Span(span), GP::Line(_)) => span,
147            (GP::Span(span), GP::Auto) => span,
148            (GP::Auto, GP::Span(span)) => span,
149            (GP::Span(span), GP::Span(_)) => span,
150            (GP::Line(_), GP::Line(_)) => panic!("indefinite_span should only be called on indefinite grid tracks"),
151        }
152    }
153}
154
155impl Line<GridPlacement> {
156    /// Apply a mapping function if the [`GridPlacement`] is a `Track`. Otherwise return `self` unmodified.
157    pub fn into_origin_zero(&self, explicit_track_count: u16) -> Line<OriginZeroGridPlacement> {
158        Line {
159            start: self.start.into_origin_zero_placement(explicit_track_count),
160            end: self.end.into_origin_zero_placement(explicit_track_count),
161        }
162    }
163}
164
165impl Line<OriginZeroGridPlacement> {
166    /// If at least one of the of the start and end positions is a track index then the other end can be resolved
167    /// into a track index purely based on the information contained with the placement specification
168    pub fn resolve_definite_grid_lines(&self) -> Line<OriginZeroLine> {
169        use OriginZeroGridPlacement as GP;
170        match (self.start, self.end) {
171            (GP::Line(line1), GP::Line(line2)) => {
172                if line1 == line2 {
173                    Line { start: line1, end: line1 + 1 }
174                } else {
175                    Line { start: min(line1, line2), end: max(line1, line2) }
176                }
177            }
178            (GP::Line(line), GP::Span(span)) => Line { start: line, end: line + span },
179            (GP::Line(line), GP::Auto) => Line { start: line, end: line + 1 },
180            (GP::Span(span), GP::Line(line)) => Line { start: line - span, end: line },
181            (GP::Auto, GP::Line(line)) => Line { start: line - 1, end: line },
182            _ => panic!("resolve_definite_grid_tracks should only be called on definite grid tracks"),
183        }
184    }
185
186    /// For absolutely positioned items:
187    ///   - Tracks resolve to definite tracks
188    ///   - For Spans:
189    ///      - If the other position is a Track, they resolve to a definite track relative to the other track
190    ///      - Else resolve to None
191    ///   - Auto resolves to None
192    ///
193    /// When finally positioning the item, a value of None means that the item's grid area is bounded by the grid
194    /// container's border box on that side.
195    pub fn resolve_absolutely_positioned_grid_tracks(&self) -> Line<Option<OriginZeroLine>> {
196        use OriginZeroGridPlacement as GP;
197        match (self.start, self.end) {
198            (GP::Line(track1), GP::Line(track2)) => {
199                if track1 == track2 {
200                    Line { start: Some(track1), end: Some(track1 + 1) }
201                } else {
202                    Line { start: Some(min(track1, track2)), end: Some(max(track1, track2)) }
203                }
204            }
205            (GP::Line(track), GP::Span(span)) => Line { start: Some(track), end: Some(track + span) },
206            (GP::Line(track), GP::Auto) => Line { start: Some(track), end: None },
207            (GP::Span(span), GP::Line(track)) => Line { start: Some(track - span), end: Some(track) },
208            (GP::Auto, GP::Line(track)) => Line { start: None, end: Some(track) },
209            _ => Line { start: None, end: None },
210        }
211    }
212
213    /// If neither of the start and end positions is a track index then the other end can be resolved
214    /// into a track index if a definite start position is supplied externally
215    pub fn resolve_indefinite_grid_tracks(&self, start: OriginZeroLine) -> Line<OriginZeroLine> {
216        use OriginZeroGridPlacement as GP;
217        match (self.start, self.end) {
218            (GP::Auto, GP::Auto) => Line { start, end: start + 1 },
219            (GP::Span(span), GP::Auto) => Line { start, end: start + span },
220            (GP::Auto, GP::Span(span)) => Line { start, end: start + span },
221            (GP::Span(span), GP::Span(_)) => Line { start, end: start + span },
222            _ => panic!("resolve_indefinite_grid_tracks should only be called on indefinite grid tracks"),
223        }
224    }
225}
226
227/// Represents the start and end points of a GridItem within a given axis
228impl Default for Line<GridPlacement> {
229    fn default() -> Self {
230        Line { start: GridPlacement::Auto, end: GridPlacement::Auto }
231    }
232}
233
234/// Maximum track sizing function
235///
236/// Specifies the maximum size of a grid track. A grid track will automatically size between it's minimum and maximum size based
237/// on the size of it's contents, the amount of available space, and the sizing constraint the grid is being size under.
238/// See https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
239#[derive(Copy, Clone, PartialEq, Debug)]
240pub enum MaxTrackSizingFunction {
241    /// Track maximum size should be a fixed points or percentage value
242    Fixed(LengthPercentage),
243    /// Track maximum size should be content sized under a min-content constraint
244    MinContent,
245    /// Track maximum size should be content sized under a max-content constraint
246    MaxContent,
247    /// Track maximum size should be sized according to the fit-content formula
248    FitContent(LengthPercentage),
249    /// Track maximum size should be automatically sized
250    Auto,
251    /// The dimension as a fraction of the total available grid space.
252    /// Specified value is the numerator of the fraction. Denominator is the sum of all fraction specified in that grid dimension
253    /// Spec: https://www.w3.org/TR/css3-grid-layout/#fr-unit
254    Flex(f32),
255}
256impl TaffyAuto for MaxTrackSizingFunction {
257    const AUTO: Self = Self::Auto;
258}
259impl TaffyMinContent for MaxTrackSizingFunction {
260    const MIN_CONTENT: Self = Self::MinContent;
261}
262impl TaffyMaxContent for MaxTrackSizingFunction {
263    const MAX_CONTENT: Self = Self::MaxContent;
264}
265impl TaffyFitContent for MaxTrackSizingFunction {
266    fn fit_content(argument: LengthPercentage) -> Self {
267        Self::FitContent(argument)
268    }
269}
270impl TaffyZero for MaxTrackSizingFunction {
271    const ZERO: Self = Self::Fixed(LengthPercentage::ZERO);
272}
273impl FromPoints for MaxTrackSizingFunction {
274    fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
275        Self::Fixed(LengthPercentage::from_points(points))
276    }
277}
278impl FromPercent for MaxTrackSizingFunction {
279    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
280        Self::Fixed(LengthPercentage::from_percent(percent))
281    }
282}
283impl FromFlex for MaxTrackSizingFunction {
284    fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
285        Self::Flex(flex.into())
286    }
287}
288
289impl MaxTrackSizingFunction {
290    /// Returns true if the max track sizing function is `MinContent`, `MaxContent`, `FitContent` or `Auto`, else false.
291    #[inline(always)]
292    pub fn is_intrinsic(&self) -> bool {
293        matches!(self, Self::MinContent | Self::MaxContent | Self::FitContent(_) | Self::Auto)
294    }
295
296    /// Returns true if the max track sizing function is `MaxContent`, `FitContent` or `Auto` else false.
297    /// "In all cases, treat auto and fit-content() as max-content, except where specified otherwise for fit-content()."
298    /// See: https://www.w3.org/TR/css-grid-1/#algo-terms
299    #[inline(always)]
300    pub fn is_max_content_alike(&self) -> bool {
301        matches!(self, Self::MaxContent | Self::FitContent(_) | Self::Auto)
302    }
303
304    /// Returns true if the max track sizing function is `Flex`, else false.
305    #[inline(always)]
306    pub fn is_flexible(&self) -> bool {
307        matches!(self, Self::Flex(_))
308    }
309
310    /// Returns fixed point values directly. Attempts to resolve percentage values against
311    /// the passed available_space and returns if this results in a concrete value (which it
312    /// will if the available_space is `Some`). Otherwise returns None.
313    #[inline(always)]
314    pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
315        use MaxTrackSizingFunction::{Auto, *};
316        match self {
317            Fixed(LengthPercentage::Points(size)) => Some(size),
318            Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
319            MinContent | MaxContent | FitContent(_) | Auto | Flex(_) => None,
320        }
321    }
322
323    /// Resolve the maximum size of the track as defined by either:
324    ///     - A fixed track sizing function
325    ///     - A percentage track sizing function (with definite available space)
326    ///     - A fit-content sizing function with fixed argument
327    ///     - A fit-content sizing function with percentage argument (with definite available space)
328    /// All other kinds of track sizing function return None.
329    #[inline(always)]
330    pub fn definite_limit(self, parent_size: Option<f32>) -> Option<f32> {
331        use MaxTrackSizingFunction::FitContent;
332        match self {
333            FitContent(LengthPercentage::Points(size)) => Some(size),
334            FitContent(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
335            _ => self.definite_value(parent_size),
336        }
337    }
338
339    /// Resolve percentage values against the passed parent_size, returning Some(value)
340    /// Non-percentage values always return None.
341    #[inline(always)]
342    pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
343        use MaxTrackSizingFunction::{Auto, *};
344        match self {
345            Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
346            Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | FitContent(_) | Auto | Flex(_) => None,
347        }
348    }
349
350    /// Whether the track sizing functions depends on the size of the parent node
351    #[inline(always)]
352    pub fn uses_percentage(self) -> bool {
353        use MaxTrackSizingFunction::*;
354        matches!(self, Fixed(LengthPercentage::Percent(_)) | FitContent(LengthPercentage::Percent(_)))
355    }
356}
357
358/// Minimum track sizing function
359///
360/// Specifies the minimum size of a grid track. A grid track will automatically size between it's minimum and maximum size based
361/// on the size of it's contents, the amount of available space, and the sizing constraint the grid is being size under.
362/// See https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
363#[derive(Copy, Clone, PartialEq, Debug)]
364pub enum MinTrackSizingFunction {
365    /// Track minimum size should be a fixed points or percentage value
366    Fixed(LengthPercentage),
367    /// Track minimum size should be content sized under a min-content constraint
368    MinContent,
369    /// Track minimum size should be content sized under a max-content constraint
370    MaxContent,
371    /// Track minimum size should be automatically sized
372    Auto,
373}
374impl TaffyAuto for MinTrackSizingFunction {
375    const AUTO: Self = Self::Auto;
376}
377impl TaffyMinContent for MinTrackSizingFunction {
378    const MIN_CONTENT: Self = Self::MinContent;
379}
380impl TaffyMaxContent for MinTrackSizingFunction {
381    const MAX_CONTENT: Self = Self::MaxContent;
382}
383impl TaffyZero for MinTrackSizingFunction {
384    const ZERO: Self = Self::Fixed(LengthPercentage::ZERO);
385}
386impl FromPoints for MinTrackSizingFunction {
387    fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
388        Self::Fixed(LengthPercentage::from_points(points))
389    }
390}
391impl FromPercent for MinTrackSizingFunction {
392    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
393        Self::Fixed(LengthPercentage::from_percent(percent))
394    }
395}
396
397impl MinTrackSizingFunction {
398    /// Returns true if the min track sizing function is `MinContent`, `MaxContent` or `Auto`, else false.
399    #[inline(always)]
400    pub fn is_intrinsic(&self) -> bool {
401        matches!(self, Self::MinContent | Self::MaxContent | Self::Auto)
402    }
403
404    /// Returns fixed point values directly. Attempts to resolve percentage values against
405    /// the passed available_space and returns if this results in a concrete value (which it
406    /// will if the available_space is `Some`). Otherwise returns `None`.
407    #[inline(always)]
408    pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
409        use MinTrackSizingFunction::{Auto, *};
410        match self {
411            Fixed(LengthPercentage::Points(size)) => Some(size),
412            Fixed(LengthPercentage::Percent(fraction)) => parent_size.map(|size| fraction * size),
413            MinContent | MaxContent | Auto => None,
414        }
415    }
416
417    /// Resolve percentage values against the passed parent_size, returning Some(value)
418    /// Non-percentage values always return None.
419    #[inline(always)]
420    pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
421        use MinTrackSizingFunction::{Auto, *};
422        match self {
423            Fixed(LengthPercentage::Percent(fraction)) => Some(fraction * parent_size),
424            Fixed(LengthPercentage::Points(_)) | MinContent | MaxContent | Auto => None,
425        }
426    }
427
428    /// Whether the track sizing functions depends on the size of the parent node
429    #[inline(always)]
430    pub fn uses_percentage(self) -> bool {
431        use MinTrackSizingFunction::*;
432        matches!(self, Fixed(LengthPercentage::Percent(_)))
433    }
434}
435
436/// The sizing function for a grid track (row/column) (either auto-track or template track)
437/// May either be a MinMax variant which specifies separate values for the min-/max- track sizing functions
438/// or a scalar value which applies to both track sizing functions.
439pub type NonRepeatedTrackSizingFunction = MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>;
440impl NonRepeatedTrackSizingFunction {
441    /// Extract the min track sizing function
442    pub fn min_sizing_function(&self) -> MinTrackSizingFunction {
443        self.min
444    }
445    /// Extract the max track sizing function
446    pub fn max_sizing_function(&self) -> MaxTrackSizingFunction {
447        self.max
448    }
449    /// Determine whether at least one of the components ("min" and "max") are fixed sizing function
450    pub fn has_fixed_component(&self) -> bool {
451        matches!(self.min, MinTrackSizingFunction::Fixed(_)) || matches!(self.max, MaxTrackSizingFunction::Fixed(_))
452    }
453}
454impl TaffyAuto for NonRepeatedTrackSizingFunction {
455    const AUTO: Self = Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::AUTO };
456}
457impl TaffyMinContent for NonRepeatedTrackSizingFunction {
458    const MIN_CONTENT: Self =
459        Self { min: MinTrackSizingFunction::MIN_CONTENT, max: MaxTrackSizingFunction::MIN_CONTENT };
460}
461impl TaffyMaxContent for NonRepeatedTrackSizingFunction {
462    const MAX_CONTENT: Self =
463        Self { min: MinTrackSizingFunction::MAX_CONTENT, max: MaxTrackSizingFunction::MAX_CONTENT };
464}
465impl TaffyFitContent for NonRepeatedTrackSizingFunction {
466    fn fit_content(argument: LengthPercentage) -> Self {
467        Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::FitContent(argument) }
468    }
469}
470impl TaffyZero for NonRepeatedTrackSizingFunction {
471    const ZERO: Self = Self { min: MinTrackSizingFunction::ZERO, max: MaxTrackSizingFunction::ZERO };
472}
473impl FromPoints for NonRepeatedTrackSizingFunction {
474    fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
475        Self { min: MinTrackSizingFunction::from_points(points), max: MaxTrackSizingFunction::from_points(points) }
476    }
477}
478impl FromPercent for NonRepeatedTrackSizingFunction {
479    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
480        Self { min: MinTrackSizingFunction::from_percent(percent), max: MaxTrackSizingFunction::from_percent(percent) }
481    }
482}
483impl FromFlex for NonRepeatedTrackSizingFunction {
484    fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
485        Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::from_flex(flex) }
486    }
487}
488
489/// The first argument to a repeated track definition. This type represents the type of automatic repetition to perform.
490///
491/// See https://www.w3.org/TR/css-grid-1/#auto-repeat for an explanation of how auto-repeated track definitions work
492/// and the difference between AutoFit and AutoFill.
493#[derive(Clone, Copy, Debug, PartialEq, Eq)]
494pub enum GridTrackRepetition {
495    /// Auto-repeating track should be generated to fit the container
496    /// See: https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fill
497    AutoFill,
498    /// Auto-repeating track should be generated to fit the container
499    /// See: https://developer.mozilla.org/en-US/docs/Web/CSS/repeat#auto-fit
500    AutoFit,
501}
502
503/// The sizing function for a grid track (row/column)
504/// See https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
505#[derive(Clone, PartialEq, Debug)]
506pub enum TrackSizingFunction {
507    /// A single non-repeated track
508    Single(NonRepeatedTrackSizingFunction),
509    /// Automatically generate grid tracks to fit the available space using the specified definite track lengths
510    /// Only valid if every track in template (not just the repitition) has a fixed size.
511    AutoRepeat(GridTrackRepetition, GridTrackVec<NonRepeatedTrackSizingFunction>),
512}
513impl TrackSizingFunction {
514    /// Whether the track definition is a auto-repeated fragment
515    pub fn is_auto_repetition(&self) -> bool {
516        matches!(self, Self::AutoRepeat(_, _))
517    }
518}
519impl TaffyAuto for TrackSizingFunction {
520    const AUTO: Self = Self::Single(NonRepeatedTrackSizingFunction::AUTO);
521}
522impl TaffyMinContent for TrackSizingFunction {
523    const MIN_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MIN_CONTENT);
524}
525impl TaffyMaxContent for TrackSizingFunction {
526    const MAX_CONTENT: Self = Self::Single(NonRepeatedTrackSizingFunction::MAX_CONTENT);
527}
528impl TaffyFitContent for TrackSizingFunction {
529    fn fit_content(argument: LengthPercentage) -> Self {
530        Self::Single(NonRepeatedTrackSizingFunction::fit_content(argument))
531    }
532}
533impl TaffyZero for TrackSizingFunction {
534    const ZERO: Self = Self::Single(NonRepeatedTrackSizingFunction::ZERO);
535}
536impl FromPoints for TrackSizingFunction {
537    fn from_points<Input: Into<f32> + Copy>(points: Input) -> Self {
538        Self::Single(NonRepeatedTrackSizingFunction::from_points(points))
539    }
540}
541impl FromPercent for TrackSizingFunction {
542    fn from_percent<Input: Into<f32> + Copy>(percent: Input) -> Self {
543        Self::Single(NonRepeatedTrackSizingFunction::from_percent(percent))
544    }
545}
546impl FromFlex for TrackSizingFunction {
547    fn from_flex<Input: Into<f32> + Copy>(flex: Input) -> Self {
548        Self::Single(NonRepeatedTrackSizingFunction::from_flex(flex))
549    }
550}
551impl From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> for TrackSizingFunction {
552    fn from(input: MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>) -> Self {
553        Self::Single(input)
554    }
555}
556
557// Grid extensions to the Style struct
558impl Style {
559    /// Get a grid item's row or column placement depending on the axis passed
560    pub(crate) fn grid_template_tracks(&self, axis: AbsoluteAxis) -> &GridTrackVec<TrackSizingFunction> {
561        match axis {
562            AbsoluteAxis::Horizontal => &self.grid_template_columns,
563            AbsoluteAxis::Vertical => &self.grid_template_rows,
564        }
565    }
566
567    /// Get a grid item's row or column placement depending on the axis passed
568    pub(crate) fn grid_placement(&self, axis: AbsoluteAxis) -> Line<GridPlacement> {
569        match axis {
570            AbsoluteAxis::Horizontal => self.grid_column,
571            AbsoluteAxis::Vertical => self.grid_row,
572        }
573    }
574
575    /// Get a grid container's align-content or justify-content alignment depending on the axis passed
576    pub(crate) fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent {
577        match axis {
578            AbstractAxis::Inline => self.justify_content.unwrap_or(AlignContent::Stretch),
579            AbstractAxis::Block => self.align_content.unwrap_or(AlignContent::Stretch),
580        }
581    }
582}