tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5364Rust 86Markdown 12TOML 91822 Definitions

⎇ 4e1c35c5d40729fdaafc40afeea863aa12ed1d5a src/style/grid.rs Rust · 571 lines · 24.7 KB History Who touched what raw

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