gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 499HTML 254C 19JavaScript 81365 Definiciones

⎇ 22a79ba0ee895068d1c4b0598cbec5f479561b17 src/style/mod.rs Rust · 1241 líneas · 42.7 KB Historia Quién tocó qué crudo

Float layout WIP 22a79ba0e · Nico Burns ·

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