taffy/style/
mod.rs

1//! A typed representation of [CSS style properties](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) in Rust. Used as input to layout computation.
2mod alignment;
3mod available_space;
4mod compact_length;
5mod dimension;
6
7#[cfg(feature = "block_layout")]
8mod block;
9#[cfg(feature = "flexbox")]
10mod flex;
11#[cfg(feature = "grid")]
12mod grid;
13
14pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf};
15pub use self::available_space::AvailableSpace;
16pub use self::compact_length::CompactLength;
17pub use self::dimension::{Dimension, LengthPercentage, LengthPercentageAuto};
18use crate::sys::DefaultCheapStr;
19
20#[cfg(feature = "block_layout")]
21pub use self::block::{BlockContainerStyle, BlockItemStyle, TextAlign};
22#[cfg(feature = "flexbox")]
23pub use self::flex::{FlexDirection, FlexWrap, FlexboxContainerStyle, FlexboxItemStyle};
24#[cfg(feature = "grid")]
25pub use self::grid::{
26    GenericGridPlacement, GenericGridTemplateComponent, GenericRepetition, GridAutoFlow, GridContainerStyle,
27    GridItemStyle, GridPlacement, GridTemplateComponent, GridTemplateRepetition, MaxTrackSizingFunction,
28    MinTrackSizingFunction, RepetitionCount, TrackSizingFunction,
29};
30#[cfg(feature = "grid")]
31pub(crate) use self::grid::{GridAreaAxis, GridAreaEnd};
32#[cfg(feature = "grid")]
33pub use self::grid::{GridTemplateArea, NamedGridLine, TemplateLineNames};
34#[cfg(feature = "grid")]
35pub(crate) use self::grid::{NonNamedGridPlacement, OriginZeroGridPlacement};
36
37use crate::geometry::{Point, Rect, Size};
38use crate::style_helpers::TaffyAuto as _;
39use core::fmt::Debug;
40
41#[cfg(feature = "grid")]
42use crate::geometry::Line;
43#[cfg(feature = "serde")]
44use crate::style_helpers;
45#[cfg(feature = "grid")]
46use crate::util::sys::GridTrackVec;
47
48use crate::sys::String;
49
50/// Trait that represents a cheaply clonable string. If you're unsure what to use here
51/// consider `Arc<str>` or `string_cache::Atom`.
52#[cfg(any(feature = "alloc", feature = "std"))]
53pub trait CheapCloneStr:
54    AsRef<str> + for<'a> From<&'a str> + From<String> + PartialEq + Eq + Clone + Default + Debug + 'static
55{
56}
57#[cfg(any(feature = "alloc", feature = "std"))]
58impl<T> CheapCloneStr for T where
59    T: AsRef<str> + for<'a> From<&'a str> + From<String> + PartialEq + Eq + Clone + Default + Debug + 'static
60{
61}
62
63/// Trait that represents a cheaply clonable string. If you're unsure what to use here
64/// consider `Arc<str>` or `string_cache::Atom`.
65#[cfg(not(any(feature = "alloc", feature = "std")))]
66pub trait CheapCloneStr {}
67#[cfg(not(any(feature = "alloc", feature = "std")))]
68impl<T> CheapCloneStr for T {}
69
70/// The core set of styles that are shared between all CSS layout nodes
71///
72/// Note that all methods come with a default implementation which simply returns the default value for that style property
73/// but this is a just a convenience to save on boilerplate for styles that your implementation doesn't support. You will need
74/// to override the default implementation for each style property that your style type actually supports.
75pub trait CoreStyle {
76    /// The type of custom identifiers used to identify named grid lines and areas
77    type CustomIdent: CheapCloneStr;
78
79    /// Which box generation mode should be used
80    #[inline(always)]
81    fn box_generation_mode(&self) -> BoxGenerationMode {
82        BoxGenerationMode::DEFAULT
83    }
84    /// Is block layout?
85    #[inline(always)]
86    fn is_block(&self) -> bool {
87        false
88    }
89    /// Is it a compressible replaced element?
90    /// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
91    #[inline(always)]
92    fn is_compressible_replaced(&self) -> bool {
93        false
94    }
95    /// Which box do size styles apply to
96    #[inline(always)]
97    fn box_sizing(&self) -> BoxSizing {
98        BoxSizing::BorderBox
99    }
100
101    // Overflow properties
102    /// How children overflowing their container should affect layout
103    #[inline(always)]
104    fn overflow(&self) -> Point<Overflow> {
105        Style::<Self::CustomIdent>::DEFAULT.overflow
106    }
107    /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
108    #[inline(always)]
109    fn scrollbar_width(&self) -> f32 {
110        0.0
111    }
112
113    // Position properties
114    /// What should the `position` value of this struct use as a base offset?
115    #[inline(always)]
116    fn position(&self) -> Position {
117        Style::<Self::CustomIdent>::DEFAULT.position
118    }
119    /// How should the position of this element be tweaked relative to the layout defined?
120    #[inline(always)]
121    fn inset(&self) -> Rect<LengthPercentageAuto> {
122        Style::<Self::CustomIdent>::DEFAULT.inset
123    }
124
125    // Size properies
126    /// Sets the initial size of the item
127    #[inline(always)]
128    fn size(&self) -> Size<Dimension> {
129        Style::<Self::CustomIdent>::DEFAULT.size
130    }
131    /// Controls the minimum size of the item
132    #[inline(always)]
133    fn min_size(&self) -> Size<Dimension> {
134        Style::<Self::CustomIdent>::DEFAULT.min_size
135    }
136    /// Controls the maximum size of the item
137    #[inline(always)]
138    fn max_size(&self) -> Size<Dimension> {
139        Style::<Self::CustomIdent>::DEFAULT.max_size
140    }
141    /// Sets the preferred aspect ratio for the item
142    /// The ratio is calculated as width divided by height.
143    #[inline(always)]
144    fn aspect_ratio(&self) -> Option<f32> {
145        Style::<Self::CustomIdent>::DEFAULT.aspect_ratio
146    }
147
148    // Spacing Properties
149    /// How large should the margin be on each side?
150    #[inline(always)]
151    fn margin(&self) -> Rect<LengthPercentageAuto> {
152        Style::<Self::CustomIdent>::DEFAULT.margin
153    }
154    /// How large should the padding be on each side?
155    #[inline(always)]
156    fn padding(&self) -> Rect<LengthPercentage> {
157        Style::<Self::CustomIdent>::DEFAULT.padding
158    }
159    /// How large should the border be on each side?
160    #[inline(always)]
161    fn border(&self) -> Rect<LengthPercentage> {
162        Style::<Self::CustomIdent>::DEFAULT.border
163    }
164}
165
166/// Sets the layout used for the children of this node
167///
168/// The default values depends on on which feature flags are enabled. The order of precedence is: Flex, Grid, Block, None.
169#[derive(Copy, Clone, PartialEq, Eq, Debug)]
170#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
171pub enum Display {
172    /// The children will follow the block layout algorithm
173    #[cfg(feature = "block_layout")]
174    Block,
175    /// The children will follow the flexbox layout algorithm
176    #[cfg(feature = "flexbox")]
177    Flex,
178    /// The children will follow the CSS Grid layout algorithm
179    #[cfg(feature = "grid")]
180    Grid,
181    /// The node is hidden, and it's children will also be hidden
182    None,
183}
184
185impl Display {
186    /// The default Display mode
187    #[cfg(feature = "flexbox")]
188    pub const DEFAULT: Display = Display::Flex;
189
190    /// The default Display mode
191    #[cfg(all(feature = "grid", not(feature = "flexbox")))]
192    pub const DEFAULT: Display = Display::Grid;
193
194    /// The default Display mode
195    #[cfg(all(feature = "block_layout", not(feature = "flexbox"), not(feature = "grid")))]
196    pub const DEFAULT: Display = Display::Block;
197
198    /// The default Display mode
199    #[cfg(all(not(feature = "flexbox"), not(feature = "grid"), not(feature = "block_layout")))]
200    pub const DEFAULT: Display = Display::None;
201}
202
203impl Default for Display {
204    fn default() -> Self {
205        Self::DEFAULT
206    }
207}
208
209impl core::fmt::Display for Display {
210    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211        match self {
212            Display::None => write!(f, "NONE"),
213            #[cfg(feature = "block_layout")]
214            Display::Block => write!(f, "BLOCK"),
215            #[cfg(feature = "flexbox")]
216            Display::Flex => write!(f, "FLEX"),
217            #[cfg(feature = "grid")]
218            Display::Grid => write!(f, "GRID"),
219        }
220    }
221}
222
223/// An abstracted version of the CSS `display` property where any value other than "none" is represented by "normal"
224/// See: <https://www.w3.org/TR/css-display-3/#box-generation>
225#[derive(Copy, Clone, PartialEq, Eq, Debug)]
226#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
227pub enum BoxGenerationMode {
228    /// The node generates a box in the regular way
229    Normal,
230    /// The node and it's descendants generate no boxes (they are hidden)
231    None,
232}
233
234impl BoxGenerationMode {
235    /// The default of BoxGenerationMode
236    pub const DEFAULT: BoxGenerationMode = BoxGenerationMode::Normal;
237}
238
239impl Default for BoxGenerationMode {
240    fn default() -> Self {
241        Self::DEFAULT
242    }
243}
244
245/// The positioning strategy for this item.
246///
247/// This controls both how the origin is determined for the [`Style::position`] field,
248/// and whether or not the item will be controlled by flexbox's layout algorithm.
249///
250/// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position),
251/// which can be unintuitive.
252///
253/// [`Position::Relative`] is the default value, in contrast to the default behavior in CSS.
254#[derive(Copy, Clone, PartialEq, Eq, Debug)]
255#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
256pub enum Position {
257    /// The offset is computed relative to the final position given by the layout algorithm.
258    /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end.
259    Relative,
260    /// The offset is computed relative to this item's closest positioned ancestor, if any.
261    /// Otherwise, it is placed relative to the origin.
262    /// No space is created for the item in the page layout, and its size will not be altered.
263    ///
264    /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object.
265    Absolute,
266}
267
268impl Default for Position {
269    fn default() -> Self {
270        Self::Relative
271    }
272}
273
274/// Specifies whether size styles for this node are assigned to the node's "content box" or "border box"
275///
276/// - The "content box" is the node's inner size excluding padding, border and margin
277/// - The "border box" is the node's outer size including padding and border (but still excluding margin)
278///
279/// This property modifies the application of the following styles:
280///
281///   - `size`
282///   - `min_size`
283///   - `max_size`
284///   - `flex_basis`
285///
286/// See <https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing>
287#[derive(Copy, Clone, PartialEq, Eq, Debug)]
288#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
289pub enum BoxSizing {
290    /// Size styles such size, min_size, max_size specify the box's "border box" (the size excluding margin but including padding/border)
291    BorderBox,
292    /// Size styles such size, min_size, max_size specify the box's "content box" (the size excluding padding/border/margin)
293    ContentBox,
294}
295
296impl Default for BoxSizing {
297    fn default() -> Self {
298        Self::BorderBox
299    }
300}
301
302/// How children overflowing their container should affect layout
303///
304/// In CSS the primary effect of this property is to control whether contents of a parent container that overflow that container should
305/// be displayed anyway, be clipped, or trigger the container to become a scroll container. However it also has secondary effects on layout,
306/// the main ones being:
307///
308///   - The automatic minimum size Flexbox/CSS Grid items with non-`Visible` overflow is `0` rather than being content based
309///   - `Overflow::Scroll` nodes have space in the layout reserved for a scrollbar (width controlled by the `scrollbar_width` property)
310///
311/// In Taffy, we only implement the layout related secondary effects as we are not concerned with drawing/painting. The amount of space reserved for
312/// a scrollbar is controlled by the `scrollbar_width` property. If this is `0` then `Scroll` behaves identically to `Hidden`.
313///
314/// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow>
315#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
316#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
317pub enum Overflow {
318    /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
319    /// Content that overflows this node *should* contribute to the scroll region of its parent.
320    #[default]
321    Visible,
322    /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content.
323    /// Content that overflows this node should *not* contribute to the scroll region of its parent.
324    Clip,
325    /// The automatic minimum size of this node as a flexbox/grid item should be `0`.
326    /// Content that overflows this node should *not* contribute to the scroll region of its parent.
327    Hidden,
328    /// The automatic minimum size of this node as a flexbox/grid item should be `0`. Additionally, space should be reserved
329    /// for a scrollbar. The amount of space reserved is controlled by the `scrollbar_width` property.
330    /// Content that overflows this node should *not* contribute to the scroll region of its parent.
331    Scroll,
332}
333
334impl Overflow {
335    /// Returns true for overflow modes that contain their contents (`Overflow::Hidden`, `Overflow::Scroll`, `Overflow::Auto`)
336    /// or else false for overflow modes that allow their contains to spill (`Overflow::Visible`).
337    #[inline(always)]
338    pub(crate) fn is_scroll_container(self) -> bool {
339        match self {
340            Self::Visible | Self::Clip => false,
341            Self::Hidden | Self::Scroll => true,
342        }
343    }
344
345    /// Returns `Some(0.0)` if the overflow mode would cause the automatic minimum size of a Flexbox or CSS Grid item
346    /// to be `0`. Else returns None.
347    #[inline(always)]
348    pub(crate) fn maybe_into_automatic_min_size(self) -> Option<f32> {
349        match self.is_scroll_container() {
350            true => Some(0.0),
351            false => None,
352        }
353    }
354}
355
356/// A typed representation of the CSS style information for a single node.
357///
358/// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other.
359/// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct.
360///
361/// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly;
362/// information about the behavior on the web should transfer directly.
363///
364/// Detailed information about the exact behavior of each of these fields
365/// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name.
366/// The distinction between margin, padding and border is explained well in
367/// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model).
368///
369/// If the behavior does not match the flexbox layout algorithm on the web, please file a bug!
370#[derive(Clone, PartialEq, Debug)]
371#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
372#[cfg_attr(feature = "serde", serde(default))]
373pub struct Style<S: CheapCloneStr = DefaultCheapStr> {
374    /// This is a dummy field which is necessary to make Taffy compile with the `grid` feature disabled
375    /// It should always be set to `core::marker::PhantomData`.
376    pub dummy: core::marker::PhantomData<S>,
377    /// What layout strategy should be used?
378    pub display: Display,
379    /// Whether a child is display:table or not. This affects children of block layouts.
380    /// This should really be part of `Display`, but it is currently seperate because table layout isn't implemented
381    pub item_is_table: bool,
382    /// Is it a replaced element like an image or form field?
383    /// <https://drafts.csswg.org/css-sizing-3/#min-content-zero>
384    pub item_is_replaced: bool,
385    /// Should size styles apply to the content box or the border box of the node
386    pub box_sizing: BoxSizing,
387
388    // Overflow properties
389    /// How children overflowing their container should affect layout
390    pub overflow: Point<Overflow>,
391    /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
392    pub scrollbar_width: f32,
393
394    // Position properties
395    /// What should the `position` value of this struct use as a base offset?
396    pub position: Position,
397    /// How should the position of this element be tweaked relative to the layout defined?
398    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
399    pub inset: Rect<LengthPercentageAuto>,
400
401    // Size properties
402    /// Sets the initial size of the item
403    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
404    pub size: Size<Dimension>,
405    /// Controls the minimum size of the item
406    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
407    pub min_size: Size<Dimension>,
408    /// Controls the maximum size of the item
409    #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))]
410    pub max_size: Size<Dimension>,
411    /// Sets the preferred aspect ratio for the item
412    ///
413    /// The ratio is calculated as width divided by height.
414    pub aspect_ratio: Option<f32>,
415
416    // Spacing Properties
417    /// How large should the margin be on each side?
418    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
419    pub margin: Rect<LengthPercentageAuto>,
420    /// How large should the padding be on each side?
421    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
422    pub padding: Rect<LengthPercentage>,
423    /// How large should the border be on each side?
424    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
425    pub border: Rect<LengthPercentage>,
426
427    // Alignment properties
428    /// How this node's children aligned in the cross/block axis?
429    #[cfg(any(feature = "flexbox", feature = "grid"))]
430    pub align_items: Option<AlignItems>,
431    /// How this node should be aligned in the cross/block axis
432    /// Falls back to the parents [`AlignItems`] if not set
433    #[cfg(any(feature = "flexbox", feature = "grid"))]
434    pub align_self: Option<AlignSelf>,
435    /// How this node's children should be aligned in the inline axis
436    #[cfg(feature = "grid")]
437    pub justify_items: Option<AlignItems>,
438    /// How this node should be aligned in the inline axis
439    /// Falls back to the parents [`JustifyItems`] if not set
440    #[cfg(feature = "grid")]
441    pub justify_self: Option<AlignSelf>,
442    /// How should content contained within this item be aligned in the cross/block axis
443    #[cfg(any(feature = "flexbox", feature = "grid"))]
444    pub align_content: Option<AlignContent>,
445    /// How should content contained within this item be aligned in the main/inline axis
446    #[cfg(any(feature = "flexbox", feature = "grid"))]
447    pub justify_content: Option<JustifyContent>,
448    /// How large should the gaps between items in a grid or flex container be?
449    #[cfg(any(feature = "flexbox", feature = "grid"))]
450    #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))]
451    pub gap: Size<LengthPercentage>,
452
453    // Block container properties
454    /// How items elements should aligned in the inline axis
455    #[cfg(feature = "block_layout")]
456    pub text_align: TextAlign,
457
458    // Flexbox container properties
459    /// Which direction does the main axis flow in?
460    #[cfg(feature = "flexbox")]
461    pub flex_direction: FlexDirection,
462    /// Should elements wrap, or stay in a single line?
463    #[cfg(feature = "flexbox")]
464    pub flex_wrap: FlexWrap,
465
466    // Flexbox item properties
467    /// Sets the initial main axis size of the item
468    #[cfg(feature = "flexbox")]
469    pub flex_basis: Dimension,
470    /// The relative rate at which this item grows when it is expanding to fill space
471    ///
472    /// 0.0 is the default value, and this value must be positive.
473    #[cfg(feature = "flexbox")]
474    pub flex_grow: f32,
475    /// The relative rate at which this item shrinks when it is contracting to fit into space
476    ///
477    /// 1.0 is the default value, and this value must be positive.
478    #[cfg(feature = "flexbox")]
479    pub flex_shrink: f32,
480
481    // Grid container properies
482    /// Defines the track sizing functions (heights) of the grid rows
483    #[cfg(feature = "grid")]
484    pub grid_template_rows: GridTrackVec<GridTemplateComponent<S>>,
485    /// Defines the track sizing functions (widths) of the grid columns
486    #[cfg(feature = "grid")]
487    pub grid_template_columns: GridTrackVec<GridTemplateComponent<S>>,
488    /// Defines the size of implicitly created rows
489    #[cfg(feature = "grid")]
490    pub grid_auto_rows: GridTrackVec<TrackSizingFunction>,
491    /// Defined the size of implicitly created columns
492    #[cfg(feature = "grid")]
493    pub grid_auto_columns: GridTrackVec<TrackSizingFunction>,
494    /// Controls how items get placed into the grid for auto-placed items
495    #[cfg(feature = "grid")]
496    pub grid_auto_flow: GridAutoFlow,
497
498    // Grid container named properties
499    /// Defines the rectangular grid areas
500    #[cfg(feature = "grid")]
501    pub grid_template_areas: GridTrackVec<GridTemplateArea<S>>,
502    /// The named lines between the columns
503    #[cfg(feature = "grid")]
504    pub grid_template_column_names: GridTrackVec<GridTrackVec<S>>,
505    /// The named lines between the rows
506    #[cfg(feature = "grid")]
507    pub grid_template_row_names: GridTrackVec<GridTrackVec<S>>,
508
509    // Grid child properties
510    /// Defines which row in the grid the item should start and end at
511    #[cfg(feature = "grid")]
512    pub grid_row: Line<GridPlacement<S>>,
513    /// Defines which column in the grid the item should start and end at
514    #[cfg(feature = "grid")]
515    pub grid_column: Line<GridPlacement<S>>,
516}
517
518impl<S: CheapCloneStr> Style<S> {
519    /// The [`Default`] layout, in a form that can be used in const functions
520    pub const DEFAULT: Style<S> = Style {
521        dummy: core::marker::PhantomData,
522        display: Display::DEFAULT,
523        item_is_table: false,
524        item_is_replaced: false,
525        box_sizing: BoxSizing::BorderBox,
526        overflow: Point { x: Overflow::Visible, y: Overflow::Visible },
527        scrollbar_width: 0.0,
528        position: Position::Relative,
529        inset: Rect::auto(),
530        margin: Rect::zero(),
531        padding: Rect::zero(),
532        border: Rect::zero(),
533        size: Size::auto(),
534        min_size: Size::auto(),
535        max_size: Size::auto(),
536        aspect_ratio: None,
537        #[cfg(any(feature = "flexbox", feature = "grid"))]
538        gap: Size::zero(),
539        // Alignment
540        #[cfg(any(feature = "flexbox", feature = "grid"))]
541        align_items: None,
542        #[cfg(any(feature = "flexbox", feature = "grid"))]
543        align_self: None,
544        #[cfg(feature = "grid")]
545        justify_items: None,
546        #[cfg(feature = "grid")]
547        justify_self: None,
548        #[cfg(any(feature = "flexbox", feature = "grid"))]
549        align_content: None,
550        #[cfg(any(feature = "flexbox", feature = "grid"))]
551        justify_content: None,
552        // Block
553        #[cfg(feature = "block_layout")]
554        text_align: TextAlign::Auto,
555        // Flexbox
556        #[cfg(feature = "flexbox")]
557        flex_direction: FlexDirection::Row,
558        #[cfg(feature = "flexbox")]
559        flex_wrap: FlexWrap::NoWrap,
560        #[cfg(feature = "flexbox")]
561        flex_grow: 0.0,
562        #[cfg(feature = "flexbox")]
563        flex_shrink: 1.0,
564        #[cfg(feature = "flexbox")]
565        flex_basis: Dimension::AUTO,
566        // Grid
567        #[cfg(feature = "grid")]
568        grid_template_rows: GridTrackVec::new(),
569        #[cfg(feature = "grid")]
570        grid_template_columns: GridTrackVec::new(),
571        #[cfg(feature = "grid")]
572        grid_template_areas: GridTrackVec::new(),
573        #[cfg(feature = "grid")]
574        grid_template_column_names: GridTrackVec::new(),
575        #[cfg(feature = "grid")]
576        grid_template_row_names: GridTrackVec::new(),
577        #[cfg(feature = "grid")]
578        grid_auto_rows: GridTrackVec::new(),
579        #[cfg(feature = "grid")]
580        grid_auto_columns: GridTrackVec::new(),
581        #[cfg(feature = "grid")]
582        grid_auto_flow: GridAutoFlow::Row,
583        #[cfg(feature = "grid")]
584        grid_row: Line { start: GridPlacement::<S>::Auto, end: GridPlacement::<S>::Auto },
585        #[cfg(feature = "grid")]
586        grid_column: Line { start: GridPlacement::<S>::Auto, end: GridPlacement::<S>::Auto },
587    };
588}
589
590impl<S: CheapCloneStr> Default for Style<S> {
591    fn default() -> Self {
592        Style::DEFAULT
593    }
594}
595
596impl<S: CheapCloneStr> CoreStyle for Style<S> {
597    type CustomIdent = S;
598
599    #[inline(always)]
600    fn box_generation_mode(&self) -> BoxGenerationMode {
601        match self.display {
602            Display::None => BoxGenerationMode::None,
603            _ => BoxGenerationMode::Normal,
604        }
605    }
606    #[inline(always)]
607    #[cfg(feature = "block_layout")]
608    fn is_block(&self) -> bool {
609        matches!(self.display, Display::Block)
610    }
611    #[inline(always)]
612    fn is_compressible_replaced(&self) -> bool {
613        self.item_is_replaced
614    }
615    #[inline(always)]
616    fn box_sizing(&self) -> BoxSizing {
617        self.box_sizing
618    }
619    #[inline(always)]
620    fn overflow(&self) -> Point<Overflow> {
621        self.overflow
622    }
623    #[inline(always)]
624    fn scrollbar_width(&self) -> f32 {
625        self.scrollbar_width
626    }
627    #[inline(always)]
628    fn position(&self) -> Position {
629        self.position
630    }
631    #[inline(always)]
632    fn inset(&self) -> Rect<LengthPercentageAuto> {
633        self.inset
634    }
635    #[inline(always)]
636    fn size(&self) -> Size<Dimension> {
637        self.size
638    }
639    #[inline(always)]
640    fn min_size(&self) -> Size<Dimension> {
641        self.min_size
642    }
643    #[inline(always)]
644    fn max_size(&self) -> Size<Dimension> {
645        self.max_size
646    }
647    #[inline(always)]
648    fn aspect_ratio(&self) -> Option<f32> {
649        self.aspect_ratio
650    }
651    #[inline(always)]
652    fn margin(&self) -> Rect<LengthPercentageAuto> {
653        self.margin
654    }
655    #[inline(always)]
656    fn padding(&self) -> Rect<LengthPercentage> {
657        self.padding
658    }
659    #[inline(always)]
660    fn border(&self) -> Rect<LengthPercentage> {
661        self.border
662    }
663}
664
665impl<T: CoreStyle> CoreStyle for &'_ T {
666    type CustomIdent = T::CustomIdent;
667
668    #[inline(always)]
669    fn box_generation_mode(&self) -> BoxGenerationMode {
670        (*self).box_generation_mode()
671    }
672    #[inline(always)]
673    fn is_block(&self) -> bool {
674        (*self).is_block()
675    }
676    #[inline(always)]
677    fn is_compressible_replaced(&self) -> bool {
678        (*self).is_compressible_replaced()
679    }
680    #[inline(always)]
681    fn box_sizing(&self) -> BoxSizing {
682        (*self).box_sizing()
683    }
684    #[inline(always)]
685    fn overflow(&self) -> Point<Overflow> {
686        (*self).overflow()
687    }
688    #[inline(always)]
689    fn scrollbar_width(&self) -> f32 {
690        (*self).scrollbar_width()
691    }
692    #[inline(always)]
693    fn position(&self) -> Position {
694        (*self).position()
695    }
696    #[inline(always)]
697    fn inset(&self) -> Rect<LengthPercentageAuto> {
698        (*self).inset()
699    }
700    #[inline(always)]
701    fn size(&self) -> Size<Dimension> {
702        (*self).size()
703    }
704    #[inline(always)]
705    fn min_size(&self) -> Size<Dimension> {
706        (*self).min_size()
707    }
708    #[inline(always)]
709    fn max_size(&self) -> Size<Dimension> {
710        (*self).max_size()
711    }
712    #[inline(always)]
713    fn aspect_ratio(&self) -> Option<f32> {
714        (*self).aspect_ratio()
715    }
716    #[inline(always)]
717    fn margin(&self) -> Rect<LengthPercentageAuto> {
718        (*self).margin()
719    }
720    #[inline(always)]
721    fn padding(&self) -> Rect<LengthPercentage> {
722        (*self).padding()
723    }
724    #[inline(always)]
725    fn border(&self) -> Rect<LengthPercentage> {
726        (*self).border()
727    }
728}
729
730#[cfg(feature = "block_layout")]
731impl<S: CheapCloneStr> BlockContainerStyle for Style<S> {
732    #[inline(always)]
733    fn text_align(&self) -> TextAlign {
734        self.text_align
735    }
736}
737
738#[cfg(feature = "block_layout")]
739impl<T: BlockContainerStyle> BlockContainerStyle for &'_ T {
740    #[inline(always)]
741    fn text_align(&self) -> TextAlign {
742        (*self).text_align()
743    }
744}
745
746#[cfg(feature = "block_layout")]
747impl<S: CheapCloneStr> BlockItemStyle for Style<S> {
748    #[inline(always)]
749    fn is_table(&self) -> bool {
750        self.item_is_table
751    }
752}
753
754#[cfg(feature = "block_layout")]
755impl<T: BlockItemStyle> BlockItemStyle for &'_ T {
756    #[inline(always)]
757    fn is_table(&self) -> bool {
758        (*self).is_table()
759    }
760}
761
762#[cfg(feature = "flexbox")]
763impl<S: CheapCloneStr> FlexboxContainerStyle for Style<S> {
764    #[inline(always)]
765    fn flex_direction(&self) -> FlexDirection {
766        self.flex_direction
767    }
768    #[inline(always)]
769    fn flex_wrap(&self) -> FlexWrap {
770        self.flex_wrap
771    }
772    #[inline(always)]
773    fn gap(&self) -> Size<LengthPercentage> {
774        self.gap
775    }
776    #[inline(always)]
777    fn align_content(&self) -> Option<AlignContent> {
778        self.align_content
779    }
780    #[inline(always)]
781    fn align_items(&self) -> Option<AlignItems> {
782        self.align_items
783    }
784    #[inline(always)]
785    fn justify_content(&self) -> Option<JustifyContent> {
786        self.justify_content
787    }
788}
789
790#[cfg(feature = "flexbox")]
791impl<T: FlexboxContainerStyle> FlexboxContainerStyle for &'_ T {
792    #[inline(always)]
793    fn flex_direction(&self) -> FlexDirection {
794        (*self).flex_direction()
795    }
796    #[inline(always)]
797    fn flex_wrap(&self) -> FlexWrap {
798        (*self).flex_wrap()
799    }
800    #[inline(always)]
801    fn gap(&self) -> Size<LengthPercentage> {
802        (*self).gap()
803    }
804    #[inline(always)]
805    fn align_content(&self) -> Option<AlignContent> {
806        (*self).align_content()
807    }
808    #[inline(always)]
809    fn align_items(&self) -> Option<AlignItems> {
810        (*self).align_items()
811    }
812    #[inline(always)]
813    fn justify_content(&self) -> Option<JustifyContent> {
814        (*self).justify_content()
815    }
816}
817
818#[cfg(feature = "flexbox")]
819impl<S: CheapCloneStr> FlexboxItemStyle for Style<S> {
820    #[inline(always)]
821    fn flex_basis(&self) -> Dimension {
822        self.flex_basis
823    }
824    #[inline(always)]
825    fn flex_grow(&self) -> f32 {
826        self.flex_grow
827    }
828    #[inline(always)]
829    fn flex_shrink(&self) -> f32 {
830        self.flex_shrink
831    }
832    #[inline(always)]
833    fn align_self(&self) -> Option<AlignSelf> {
834        self.align_self
835    }
836}
837
838#[cfg(feature = "flexbox")]
839impl<T: FlexboxItemStyle> FlexboxItemStyle for &'_ T {
840    #[inline(always)]
841    fn flex_basis(&self) -> Dimension {
842        (*self).flex_basis()
843    }
844    #[inline(always)]
845    fn flex_grow(&self) -> f32 {
846        (*self).flex_grow()
847    }
848    #[inline(always)]
849    fn flex_shrink(&self) -> f32 {
850        (*self).flex_shrink()
851    }
852    #[inline(always)]
853    fn align_self(&self) -> Option<AlignSelf> {
854        (*self).align_self()
855    }
856}
857
858#[cfg(feature = "grid")]
859impl<S: CheapCloneStr> GridContainerStyle for Style<S> {
860    type Repetition<'a>
861        = &'a GridTemplateRepetition<S>
862    where
863        Self: 'a;
864
865    type TemplateTrackList<'a>
866        = core::iter::Map<
867        core::slice::Iter<'a, GridTemplateComponent<S>>,
868        fn(&'a GridTemplateComponent<S>) -> GenericGridTemplateComponent<S, &'a GridTemplateRepetition<S>>,
869    >
870    where
871        Self: 'a;
872
873    type AutoTrackList<'a>
874        = core::iter::Copied<core::slice::Iter<'a, TrackSizingFunction>>
875    where
876        Self: 'a;
877
878    #[cfg(feature = "grid")]
879    type TemplateLineNames<'a>
880        = core::iter::Map<core::slice::Iter<'a, GridTrackVec<S>>, fn(&GridTrackVec<S>) -> core::slice::Iter<'_, S>>
881    where
882        Self: 'a;
883    #[cfg(feature = "grid")]
884    type GridTemplateAreas<'a>
885        = core::iter::Cloned<core::slice::Iter<'a, GridTemplateArea<S>>>
886    where
887        Self: 'a;
888
889    #[inline(always)]
890    fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>> {
891        Some(self.grid_template_rows.iter().map(|c| c.as_component_ref()))
892    }
893    #[inline(always)]
894    fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
895        Some(self.grid_template_columns.iter().map(|c| c.as_component_ref()))
896    }
897    #[inline(always)]
898    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
899        self.grid_auto_rows.iter().copied()
900    }
901    #[inline(always)]
902    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
903        self.grid_auto_columns.iter().copied()
904    }
905    #[inline(always)]
906    fn grid_auto_flow(&self) -> GridAutoFlow {
907        self.grid_auto_flow
908    }
909    #[inline(always)]
910    fn gap(&self) -> Size<LengthPercentage> {
911        self.gap
912    }
913    #[inline(always)]
914    fn align_content(&self) -> Option<AlignContent> {
915        self.align_content
916    }
917    #[inline(always)]
918    fn justify_content(&self) -> Option<JustifyContent> {
919        self.justify_content
920    }
921    #[inline(always)]
922    fn align_items(&self) -> Option<AlignItems> {
923        self.align_items
924    }
925    #[inline(always)]
926    fn justify_items(&self) -> Option<AlignItems> {
927        self.justify_items
928    }
929
930    #[inline(always)]
931    #[cfg(feature = "grid")]
932    fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
933        Some(self.grid_template_areas.iter().cloned())
934    }
935
936    #[inline(always)]
937    #[cfg(feature = "grid")]
938    fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
939        Some(self.grid_template_column_names.iter().map(|names| names.iter()))
940    }
941
942    #[inline(always)]
943    #[cfg(feature = "grid")]
944    fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
945        Some(self.grid_template_row_names.iter().map(|names| names.iter()))
946    }
947}
948
949#[cfg(feature = "grid")]
950impl<T: GridContainerStyle> GridContainerStyle for &'_ T {
951    type Repetition<'a>
952        = T::Repetition<'a>
953    where
954        Self: 'a;
955
956    type TemplateTrackList<'a>
957        = T::TemplateTrackList<'a>
958    where
959        Self: 'a;
960
961    type AutoTrackList<'a>
962        = T::AutoTrackList<'a>
963    where
964        Self: 'a;
965
966    /// The type returned by grid_template_row_names and grid_template_column_names
967    #[cfg(feature = "grid")]
968    type TemplateLineNames<'a>
969        = T::TemplateLineNames<'a>
970    where
971        Self: 'a;
972    #[cfg(feature = "grid")]
973    type GridTemplateAreas<'a>
974        = T::GridTemplateAreas<'a>
975    where
976        Self: 'a;
977
978    #[inline(always)]
979    fn grid_template_rows(&self) -> Option<Self::TemplateTrackList<'_>> {
980        (*self).grid_template_rows()
981    }
982    #[inline(always)]
983    fn grid_template_columns(&self) -> Option<Self::TemplateTrackList<'_>> {
984        (*self).grid_template_columns()
985    }
986    #[inline(always)]
987    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
988        (*self).grid_auto_rows()
989    }
990    #[inline(always)]
991    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
992        (*self).grid_auto_columns()
993    }
994    #[cfg(feature = "grid")]
995    #[inline(always)]
996    fn grid_template_areas(&self) -> Option<Self::GridTemplateAreas<'_>> {
997        (*self).grid_template_areas()
998    }
999    #[cfg(feature = "grid")]
1000    #[inline(always)]
1001    fn grid_template_column_names(&self) -> Option<Self::TemplateLineNames<'_>> {
1002        (*self).grid_template_column_names()
1003    }
1004    #[cfg(feature = "grid")]
1005    #[inline(always)]
1006    fn grid_template_row_names(&self) -> Option<Self::TemplateLineNames<'_>> {
1007        (*self).grid_template_row_names()
1008    }
1009    #[inline(always)]
1010    fn grid_auto_flow(&self) -> GridAutoFlow {
1011        (*self).grid_auto_flow()
1012    }
1013    #[inline(always)]
1014    fn gap(&self) -> Size<LengthPercentage> {
1015        (*self).gap()
1016    }
1017    #[inline(always)]
1018    fn align_content(&self) -> Option<AlignContent> {
1019        (*self).align_content()
1020    }
1021    #[inline(always)]
1022    fn justify_content(&self) -> Option<JustifyContent> {
1023        (*self).justify_content()
1024    }
1025    #[inline(always)]
1026    fn align_items(&self) -> Option<AlignItems> {
1027        (*self).align_items()
1028    }
1029    #[inline(always)]
1030    fn justify_items(&self) -> Option<AlignItems> {
1031        (*self).justify_items()
1032    }
1033}
1034
1035#[cfg(feature = "grid")]
1036impl<S: CheapCloneStr> GridItemStyle for Style<S> {
1037    #[inline(always)]
1038    fn grid_row(&self) -> Line<GridPlacement<S>> {
1039        // TODO: Investigate eliminating clone
1040        self.grid_row.clone()
1041    }
1042    #[inline(always)]
1043    fn grid_column(&self) -> Line<GridPlacement<S>> {
1044        // TODO: Investigate eliminating clone
1045        self.grid_column.clone()
1046    }
1047    #[inline(always)]
1048    fn align_self(&self) -> Option<AlignSelf> {
1049        self.align_self
1050    }
1051    #[inline(always)]
1052    fn justify_self(&self) -> Option<AlignSelf> {
1053        self.justify_self
1054    }
1055}
1056
1057#[cfg(feature = "grid")]
1058impl<T: GridItemStyle> GridItemStyle for &'_ T {
1059    #[inline(always)]
1060    fn grid_row(&self) -> Line<GridPlacement<Self::CustomIdent>> {
1061        (*self).grid_row()
1062    }
1063    #[inline(always)]
1064    fn grid_column(&self) -> Line<GridPlacement<Self::CustomIdent>> {
1065        (*self).grid_column()
1066    }
1067    #[inline(always)]
1068    fn align_self(&self) -> Option<AlignSelf> {
1069        (*self).align_self()
1070    }
1071    #[inline(always)]
1072    fn justify_self(&self) -> Option<AlignSelf> {
1073        (*self).justify_self()
1074    }
1075}
1076
1077#[cfg(test)]
1078mod tests {
1079    use std::sync::Arc;
1080
1081    use super::Style;
1082    use crate::sys::DefaultCheapStr;
1083    use crate::{geometry::*, style_helpers::TaffyAuto as _};
1084
1085    #[test]
1086    fn defaults_match() {
1087        #[cfg(feature = "grid")]
1088        use super::GridPlacement;
1089
1090        let old_defaults: Style<DefaultCheapStr> = Style {
1091            dummy: core::marker::PhantomData,
1092            display: Default::default(),
1093            item_is_table: false,
1094            item_is_replaced: false,
1095            box_sizing: Default::default(),
1096            overflow: Default::default(),
1097            scrollbar_width: 0.0,
1098            position: Default::default(),
1099            #[cfg(feature = "flexbox")]
1100            flex_direction: Default::default(),
1101            #[cfg(feature = "flexbox")]
1102            flex_wrap: Default::default(),
1103            #[cfg(any(feature = "flexbox", feature = "grid"))]
1104            align_items: Default::default(),
1105            #[cfg(any(feature = "flexbox", feature = "grid"))]
1106            align_self: Default::default(),
1107            #[cfg(feature = "grid")]
1108            justify_items: Default::default(),
1109            #[cfg(feature = "grid")]
1110            justify_self: Default::default(),
1111            #[cfg(any(feature = "flexbox", feature = "grid"))]
1112            align_content: Default::default(),
1113            #[cfg(any(feature = "flexbox", feature = "grid"))]
1114            justify_content: Default::default(),
1115            inset: Rect::auto(),
1116            margin: Rect::zero(),
1117            padding: Rect::zero(),
1118            border: Rect::zero(),
1119            gap: Size::zero(),
1120            #[cfg(feature = "block_layout")]
1121            text_align: Default::default(),
1122            #[cfg(feature = "flexbox")]
1123            flex_grow: 0.0,
1124            #[cfg(feature = "flexbox")]
1125            flex_shrink: 1.0,
1126            #[cfg(feature = "flexbox")]
1127            flex_basis: super::Dimension::AUTO,
1128            size: Size::auto(),
1129            min_size: Size::auto(),
1130            max_size: Size::auto(),
1131            aspect_ratio: Default::default(),
1132            #[cfg(feature = "grid")]
1133            grid_template_rows: Default::default(),
1134            #[cfg(feature = "grid")]
1135            grid_template_columns: Default::default(),
1136            #[cfg(feature = "grid")]
1137            grid_template_row_names: Default::default(),
1138            #[cfg(feature = "grid")]
1139            grid_template_column_names: Default::default(),
1140            #[cfg(feature = "grid")]
1141            grid_template_areas: Default::default(),
1142            #[cfg(feature = "grid")]
1143            grid_auto_rows: Default::default(),
1144            #[cfg(feature = "grid")]
1145            grid_auto_columns: Default::default(),
1146            #[cfg(feature = "grid")]
1147            grid_auto_flow: Default::default(),
1148            #[cfg(feature = "grid")]
1149            grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1150            #[cfg(feature = "grid")]
1151            grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
1152        };
1153
1154        assert_eq!(Style::DEFAULT, Style::<DefaultCheapStr>::default());
1155        assert_eq!(Style::DEFAULT, old_defaults);
1156    }
1157
1158    // NOTE: Please feel free the update the sizes in this test as required. This test is here to prevent unintentional size changes
1159    // and to serve as accurate up-to-date documentation on the sizes.
1160    #[test]
1161    fn style_sizes() {
1162        use super::*;
1163        type S = crate::sys::DefaultCheapStr;
1164
1165        fn assert_type_size<T>(expected_size: usize) {
1166            let name = ::core::any::type_name::<T>();
1167            let name = name.replace("taffy::geometry::", "");
1168            let name = name.replace("taffy::style::dimension::", "");
1169            let name = name.replace("taffy::style::alignment::", "");
1170            let name = name.replace("taffy::style::flex::", "");
1171            let name = name.replace("taffy::style::grid::", "");
1172
1173            assert_eq!(
1174                ::core::mem::size_of::<T>(),
1175                expected_size,
1176                "Expected {} for be {} byte(s) but it was {} byte(s)",
1177                name,
1178                expected_size,
1179                ::core::mem::size_of::<T>(),
1180            );
1181        }
1182
1183        // Display and Position
1184        assert_type_size::<Display>(1);
1185        assert_type_size::<BoxSizing>(1);
1186        assert_type_size::<Position>(1);
1187        assert_type_size::<Overflow>(1);
1188
1189        // Dimensions and aggregations of Dimensions
1190        assert_type_size::<f32>(4);
1191        assert_type_size::<LengthPercentage>(8);
1192        assert_type_size::<LengthPercentageAuto>(8);
1193        assert_type_size::<Dimension>(8);
1194        assert_type_size::<Size<LengthPercentage>>(16);
1195        assert_type_size::<Size<LengthPercentageAuto>>(16);
1196        assert_type_size::<Size<Dimension>>(16);
1197        assert_type_size::<Rect<LengthPercentage>>(32);
1198        assert_type_size::<Rect<LengthPercentageAuto>>(32);
1199        assert_type_size::<Rect<Dimension>>(32);
1200
1201        // Alignment
1202        assert_type_size::<AlignContent>(1);
1203        assert_type_size::<AlignItems>(1);
1204        assert_type_size::<Option<AlignItems>>(1);
1205
1206        // Flexbox Container
1207        assert_type_size::<FlexDirection>(1);
1208        assert_type_size::<FlexWrap>(1);
1209
1210        // CSS Grid Container
1211        assert_type_size::<GridAutoFlow>(1);
1212        assert_type_size::<MinTrackSizingFunction>(8);
1213        assert_type_size::<MaxTrackSizingFunction>(8);
1214        assert_type_size::<TrackSizingFunction>(16);
1215        assert_type_size::<Vec<TrackSizingFunction>>(24);
1216        assert_type_size::<Vec<GridTemplateComponent<S>>>(24);
1217
1218        // String-type dependent (String)
1219        assert_type_size::<GridTemplateComponent<String>>(56);
1220        assert_type_size::<GridPlacement<String>>(32);
1221        assert_type_size::<Line<GridPlacement<String>>>(64);
1222        assert_type_size::<Style<String>>(536);
1223
1224        // String-type dependent (Arc<str>)
1225        assert_type_size::<GridTemplateComponent<Arc<str>>>(56);
1226        assert_type_size::<GridPlacement<Arc<str>>>(24);
1227        assert_type_size::<Line<GridPlacement<Arc<str>>>>(48);
1228        assert_type_size::<Style<Arc<str>>>(504);
1229    }
1230}