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