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