//! 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. mod alignment; mod available_space; mod compact_length; mod dimension; #[cfg(feature = "block_layout")] mod block; #[cfg(feature = "flexbox")] mod flex; #[cfg(feature = "float_layout")] mod float; #[cfg(feature = "grid")] mod grid; pub use self::alignment::{ AlignContent, AlignContentKeyword, AlignItems, AlignItemsKeyword, AlignSelf, AlignmentSafety, JustifyContent, JustifyItems, JustifySelf, }; pub use self::available_space::AvailableSpace; pub use self::compact_length::CompactLength; pub use self::dimension::{Dimension, LengthPercentage, LengthPercentageAuto}; use crate::sys::DefaultCheapStr; #[cfg(feature = "block_layout")] pub use self::block::{BlockContainerStyle, BlockItemStyle, TextAlign}; #[cfg(feature = "flexbox")] pub use self::flex::{FlexDirection, FlexWrap, FlexboxContainerStyle, FlexboxItemStyle}; #[cfg(feature = "float_layout")] pub use self::float::{Clear, Float, FloatDirection}; #[cfg(feature = "grid")] pub use self::grid::{ GenericGridPlacement, GenericGridTemplateComponent, GenericRepetition, GridAutoFlow, GridAutoTracks, GridContainerStyle, GridItemStyle, GridPlacement, GridTemplateComponent, GridTemplateRepetition, GridTemplateTracks, MaxTrackSizingFunction, MinTrackSizingFunction, RepetitionCount, TrackSizingFunction, }; #[cfg(feature = "grid")] pub(crate) use self::grid::{GridAreaAxis, GridAreaEnd}; #[cfg(feature = "grid")] pub use self::grid::{GridTemplateArea, NamedGridLine, TemplateLineNames}; #[cfg(feature = "grid")] pub(crate) use self::grid::{NonNamedGridPlacement, OriginZeroGridPlacement}; use crate::geometry::{Point, Rect, Size}; use crate::style_helpers::TaffyAuto as _; use core::fmt::Debug; #[cfg(feature = "grid")] use crate::geometry::Line; #[cfg(feature = "serde")] use crate::style_helpers; #[cfg(feature = "grid")] use crate::util::sys::GridTrackVec; use crate::sys::String; /// Trait that represents a cheaply clonable string. If you're unsure what to use here /// consider `Arc` or `string_cache::Atom`. #[cfg(any(feature = "alloc", feature = "std"))] pub trait CheapCloneStr: AsRef + for<'a> From<&'a str> + From + PartialEq + Eq + Clone + Default + Debug + 'static { } #[cfg(any(feature = "alloc", feature = "std"))] impl CheapCloneStr for T where T: AsRef + for<'a> From<&'a str> + From + PartialEq + Eq + Clone + Default + Debug + 'static { } /// Trait that represents a cheaply clonable string. If you're unsure what to use here /// consider `Arc` or `string_cache::Atom`. #[cfg(not(any(feature = "alloc", feature = "std")))] pub trait CheapCloneStr {} #[cfg(not(any(feature = "alloc", feature = "std")))] impl CheapCloneStr for T {} /// The core set of styles that are shared between all CSS layout nodes /// /// Note that all methods come with a default implementation which simply returns the default value for that style property /// but this is a just a convenience to save on boilerplate for styles that your implementation doesn't support. You will need /// to override the default implementation for each style property that your style type actually supports. pub trait CoreStyle { /// The type of custom identifiers used to identify named grid lines and areas type CustomIdent: CheapCloneStr; /// Which box generation mode should be used #[inline(always)] fn box_generation_mode(&self) -> BoxGenerationMode { BoxGenerationMode::DEFAULT } /// Is block layout? #[inline(always)] fn is_block(&self) -> bool { false } /// Is it a compressible replaced element? /// #[inline(always)] fn is_compressible_replaced(&self) -> bool { false } /// Which box do size styles apply to #[inline(always)] fn box_sizing(&self) -> BoxSizing { BoxSizing::BorderBox } /// The direction of text, table and grid columns, and horizontal overflow. #[inline(always)] fn direction(&self) -> Direction { Direction::Ltr } // Overflow properties /// How children overflowing their container should affect layout #[inline(always)] fn overflow(&self) -> Point { Style::::DEFAULT.overflow } /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes. #[inline(always)] fn scrollbar_width(&self) -> f32 { 0.0 } // Position properties /// What should the `position` value of this struct use as a base offset? #[inline(always)] fn position(&self) -> Position { Style::::DEFAULT.position } /// How should the position of this element be tweaked relative to the layout defined? #[inline(always)] fn inset(&self) -> Rect { Style::::DEFAULT.inset } // Size properies /// Sets the initial size of the item #[inline(always)] fn size(&self) -> Size { Style::::DEFAULT.size } /// Controls the minimum size of the item #[inline(always)] fn min_size(&self) -> Size { Style::::DEFAULT.min_size } /// Controls the maximum size of the item #[inline(always)] fn max_size(&self) -> Size { Style::::DEFAULT.max_size } /// Sets the preferred aspect ratio for the item /// The ratio is calculated as width divided by height. #[inline(always)] fn aspect_ratio(&self) -> Option { Style::::DEFAULT.aspect_ratio } // Spacing Properties /// How large should the margin be on each side? #[inline(always)] fn margin(&self) -> Rect { Style::::DEFAULT.margin } /// How large should the padding be on each side? #[inline(always)] fn padding(&self) -> Rect { Style::::DEFAULT.padding } /// How large should the border be on each side? #[inline(always)] fn border(&self) -> Rect { Style::::DEFAULT.border } } /// Sets the layout used for the children of this node /// /// The default values depends on on which feature flags are enabled. The order of precedence is: Flex, Grid, Block, None. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Display { /// The children will follow the block layout algorithm #[cfg(feature = "block_layout")] Block, /// The children will follow the block layout algorithm and establish a new block formatting context #[cfg(feature = "block_layout")] FlowRoot, /// The children will follow the flexbox layout algorithm #[cfg(feature = "flexbox")] Flex, /// The children will follow the CSS Grid layout algorithm #[cfg(feature = "grid")] Grid, /// The node is hidden, and it's children will also be hidden None, } impl Display { /// The default Display mode #[cfg(feature = "flexbox")] pub const DEFAULT: Display = Display::Flex; /// The default Display mode #[cfg(all(feature = "grid", not(feature = "flexbox")))] pub const DEFAULT: Display = Display::Grid; /// The default Display mode #[cfg(all(feature = "block_layout", not(feature = "flexbox"), not(feature = "grid")))] pub const DEFAULT: Display = Display::Block; /// The default Display mode #[cfg(all(not(feature = "flexbox"), not(feature = "grid"), not(feature = "block_layout")))] pub const DEFAULT: Display = Display::None; } impl Default for Display { fn default() -> Self { Self::DEFAULT } } #[cfg(feature = "parse")] crate::util::parse::impl_parse_for_keyword_enum!(Display, "none" => None, #[cfg(feature = "flexbox")] "flex" => Flex, #[cfg(feature = "grid")] "grid" => Grid, #[cfg(feature = "block_layout")] "block" => Block, #[cfg(feature = "block_layout")] "flow-root" => FlowRoot, ); impl core::fmt::Display for Display { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Display::None => write!(f, "NONE"), #[cfg(feature = "block_layout")] Display::Block => write!(f, "BLOCK"), #[cfg(feature = "block_layout")] Display::FlowRoot => write!(f, "FLOW-ROOT"), #[cfg(feature = "flexbox")] Display::Flex => write!(f, "FLEX"), #[cfg(feature = "grid")] Display::Grid => write!(f, "GRID"), } } } /// An abstracted version of the CSS `display` property where any value other than "none" is represented by "normal" /// See: #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum BoxGenerationMode { /// The node generates a box in the regular way Normal, /// The node and it's descendants generate no boxes (they are hidden) None, } impl BoxGenerationMode { /// The default of BoxGenerationMode pub const DEFAULT: BoxGenerationMode = BoxGenerationMode::Normal; } impl Default for BoxGenerationMode { fn default() -> Self { Self::DEFAULT } } /// The positioning strategy for this item. /// /// This controls both how the origin is determined for the [`Style::position`] field, /// and whether or not the item will be controlled by flexbox's layout algorithm. /// /// WARNING: this enum follows the behavior of [CSS's `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position), /// which can be unintuitive. /// /// [`Position::Relative`] is the default value, in contrast to the default behavior in CSS. #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Position { /// The offset is computed relative to the final position given by the layout algorithm. /// Offsets do not affect the position of any other items; they are effectively a correction factor applied at the end. #[default] Relative, /// The offset is computed relative to this item's closest positioned ancestor, if any. /// Otherwise, it is placed relative to the origin. /// No space is created for the item in the page layout, and its size will not be altered. /// /// WARNING: to opt-out of layouting entirely, you must use [`Display::None`] instead on your [`Style`] object. Absolute, } #[cfg(feature = "parse")] crate::util::parse::impl_parse_for_keyword_enum!(Position, "relative" => Relative, "absolute" => Absolute, ); /// Specifies whether size styles for this node are assigned to the node's "content box" or "border box" /// /// - The "content box" is the node's inner size excluding padding, border and margin /// - The "border box" is the node's outer size including padding and border (but still excluding margin) /// /// This property modifies the application of the following styles: /// /// - `size` /// - `min_size` /// - `max_size` /// - `flex_basis` /// /// See #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum BoxSizing { /// Size styles such size, min_size, max_size specify the box's "border box" (the size excluding margin but including padding/border) #[default] BorderBox, /// Size styles such size, min_size, max_size specify the box's "content box" (the size excluding padding/border/margin) ContentBox, } #[cfg(feature = "parse")] crate::util::parse::impl_parse_for_keyword_enum!(BoxSizing, "border-box" => BorderBox, "content-box" => ContentBox, ); /// How children overflowing their container should affect layout /// /// In CSS the primary effect of this property is to control whether contents of a parent container that overflow that container should /// be displayed anyway, be clipped, or trigger the container to become a scroll container. However it also has secondary effects on layout, /// the main ones being: /// /// - The automatic minimum size Flexbox/CSS Grid items with non-`Visible` overflow is `0` rather than being content based /// - `Overflow::Scroll` nodes have space in the layout reserved for a scrollbar (width controlled by the `scrollbar_width` property) /// /// In Taffy, we only implement the layout related secondary effects as we are not concerned with drawing/painting. The amount of space reserved for /// a scrollbar is controlled by the `scrollbar_width` property. If this is `0` then `Scroll` behaves identically to `Hidden`. /// /// #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Overflow { /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content. /// Content that overflows this node *should* contribute to the scroll region of its parent. #[default] Visible, /// The automatic minimum size of this node as a flexbox/grid item should be based on the size of its content. /// Content that overflows this node should *not* contribute to the scroll region of its parent. Clip, /// The automatic minimum size of this node as a flexbox/grid item should be `0`. /// Content that overflows this node should *not* contribute to the scroll region of its parent. Hidden, /// The automatic minimum size of this node as a flexbox/grid item should be `0`. Additionally, space should be reserved /// for a scrollbar. The amount of space reserved is controlled by the `scrollbar_width` property. /// Content that overflows this node should *not* contribute to the scroll region of its parent. Scroll, } impl Overflow { /// Returns true for overflow modes that contain their contents (`Overflow::Hidden`, `Overflow::Scroll`, `Overflow::Auto`) /// or else false for overflow modes that allow their contains to spill (`Overflow::Visible`). #[inline(always)] pub fn is_scroll_container(self) -> bool { match self { Self::Visible | Self::Clip => false, Self::Hidden | Self::Scroll => true, } } /// Returns `Some(0.0)` if the overflow mode would cause the automatic minimum size of a Flexbox or CSS Grid item /// to be `0`. Else returns None. #[inline(always)] pub(crate) fn maybe_into_automatic_min_size(self) -> Option { match self.is_scroll_container() { true => Some(0.0), false => None, } } } #[cfg(feature = "parse")] crate::util::parse::impl_parse_for_keyword_enum!(Overflow, "visible" => Visible, "hidden" => Hidden, "clip" => Clip, "scroll" => Scroll, ); /// Sets the direction of text, table and grid columns, and horizontal overflow. /// #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Direction { #[default] /// Left-to-right Ltr, /// Right-to-left Rtl, } impl Direction { /// Returns true if the direction is right-to-left #[inline] pub(crate) fn is_rtl(&self) -> bool { matches!(self, Direction::Rtl) } } #[cfg(feature = "parse")] crate::util::parse::impl_parse_for_keyword_enum!(Direction, "ltr" => Ltr, "rtl" => Rtl, ); /// A typed representation of the CSS style information for a single node. /// /// The most important idea in flexbox is the notion of a "main" and "cross" axis, which are always perpendicular to each other. /// The orientation of these axes are controlled via the [`FlexDirection`] field of this struct. /// /// This struct follows the [CSS equivalent](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) directly; /// information about the behavior on the web should transfer directly. /// /// Detailed information about the exact behavior of each of these fields /// can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS) by searching for the field name. /// The distinction between margin, padding and border is explained well in /// this [introduction to the box model](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model). /// /// If the behavior does not match the flexbox layout algorithm on the web, please file a bug! #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(default))] pub struct Style { /// This is a dummy field which is necessary to make Taffy compile with the `grid` feature disabled /// It should always be set to `core::marker::PhantomData`. pub dummy: core::marker::PhantomData, /// What layout strategy should be used? pub display: Display, /// Whether a child is display:table or not. This affects children of block layouts. /// This should really be part of `Display`, but it is currently seperate because table layout isn't implemented pub item_is_table: bool, /// Is it a replaced element like an image or form field? /// pub item_is_replaced: bool, /// Should size styles apply to the content box or the border box of the node pub box_sizing: BoxSizing, /// Sets the direction of text, table and grid columns, and horizontal overflow. pub direction: Direction, // Overflow properties /// How children overflowing their container should affect layout pub overflow: Point, /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes. pub scrollbar_width: f32, #[cfg(feature = "float_layout")] /// Should the box be floated pub float: Float, #[cfg(feature = "float_layout")] /// Should the box clear floats pub clear: Clear, // Position properties /// What should the `position` value of this struct use as a base offset? pub position: Position, /// How should the position of this element be tweaked relative to the layout defined? #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))] pub inset: Rect, // Size properties /// Sets the initial size of the item #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))] pub size: Size, /// Controls the minimum size of the item #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))] pub min_size: Size, /// Controls the maximum size of the item #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))] pub max_size: Size, /// Sets the preferred aspect ratio for the item /// /// The ratio is calculated as width divided by height. pub aspect_ratio: Option, // Spacing Properties /// How large should the margin be on each side? #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))] pub margin: Rect, /// How large should the padding be on each side? #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))] pub padding: Rect, /// How large should the border be on each side? #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))] pub border: Rect, // Alignment properties /// How this node's children aligned in the cross/block axis? #[cfg(any(feature = "flexbox", feature = "grid"))] pub align_items: Option, /// How this node should be aligned in the cross/block axis /// Falls back to the parents [`AlignItems`] if not set #[cfg(any(feature = "flexbox", feature = "grid"))] pub align_self: Option, /// How this node's children should be aligned in the inline axis #[cfg(feature = "grid")] pub justify_items: Option, /// How this node should be aligned in the inline axis /// Falls back to the parents [`JustifyItems`] if not set #[cfg(feature = "grid")] pub justify_self: Option, /// How should content contained within this item be aligned in the cross/block axis #[cfg(any(feature = "flexbox", feature = "grid", feature = "block_layout"))] pub align_content: Option, /// How should content contained within this item be aligned in the main/inline axis #[cfg(any(feature = "flexbox", feature = "grid"))] pub justify_content: Option, /// How large should the gaps between items in a grid or flex container be? #[cfg(any(feature = "flexbox", feature = "grid"))] #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))] pub gap: Size, // Block container properties /// How items elements should aligned in the inline axis #[cfg(feature = "block_layout")] pub text_align: TextAlign, // Flexbox container properties /// Which direction does the main axis flow in? #[cfg(feature = "flexbox")] pub flex_direction: FlexDirection, /// Should elements wrap, or stay in a single line? #[cfg(feature = "flexbox")] pub flex_wrap: FlexWrap, // Flexbox item properties /// Sets the initial main axis size of the item #[cfg(feature = "flexbox")] pub flex_basis: Dimension, /// The relative rate at which this item grows when it is expanding to fill space /// /// 0.0 is the default value, and this value must be positive. #[cfg(feature = "flexbox")] pub flex_grow: f32, /// The relative rate at which this item shrinks when it is contracting to fit into space /// /// 1.0 is the default value, and this value must be positive. #[cfg(feature = "flexbox")] pub flex_shrink: f32, // Grid container properies /// Defines the track sizing functions (heights) of the grid rows #[cfg(feature = "grid")] pub grid_template_rows: GridTrackVec>, /// Defines the track sizing functions (widths) of the grid columns #[cfg(feature = "grid")] pub grid_template_columns: GridTrackVec>, /// Defines the size of implicitly created rows #[cfg(feature = "grid")] pub grid_auto_rows: GridTrackVec, /// Defined the size of implicitly created columns #[cfg(feature = "grid")] pub grid_auto_columns: GridTrackVec, /// Controls how items get placed into the grid for auto-placed items #[cfg(feature = "grid")] pub grid_auto_flow: GridAutoFlow, // Grid container named properties /// Defines the rectangular grid areas #[cfg(feature = "grid")] pub grid_template_areas: GridTrackVec>, /// The named lines between the columns #[cfg(feature = "grid")] pub grid_template_column_names: GridTrackVec>, /// The named lines between the rows #[cfg(feature = "grid")] pub grid_template_row_names: GridTrackVec>, // Grid child properties /// Defines which row in the grid the item should start and end at #[cfg(feature = "grid")] pub grid_row: Line>, /// Defines which column in the grid the item should start and end at #[cfg(feature = "grid")] pub grid_column: Line>, } impl Style { /// The [`Default`] layout, in a form that can be used in const functions pub const DEFAULT: Style = Style { dummy: core::marker::PhantomData, display: Display::DEFAULT, item_is_table: false, item_is_replaced: false, box_sizing: BoxSizing::BorderBox, direction: Direction::Ltr, overflow: Point { x: Overflow::Visible, y: Overflow::Visible }, scrollbar_width: 0.0, #[cfg(feature = "float_layout")] float: Float::None, #[cfg(feature = "float_layout")] clear: Clear::None, position: Position::Relative, inset: Rect::auto(), margin: Rect::zero(), padding: Rect::zero(), border: Rect::zero(), size: Size::auto(), min_size: Size::auto(), max_size: Size::auto(), aspect_ratio: None, #[cfg(any(feature = "flexbox", feature = "grid"))] gap: Size::zero(), // Alignment #[cfg(any(feature = "flexbox", feature = "grid"))] align_items: None, #[cfg(any(feature = "flexbox", feature = "grid"))] align_self: None, #[cfg(feature = "grid")] justify_items: None, #[cfg(feature = "grid")] justify_self: None, #[cfg(any(feature = "flexbox", feature = "grid", feature = "block_layout"))] align_content: None, #[cfg(any(feature = "flexbox", feature = "grid"))] justify_content: None, // Block #[cfg(feature = "block_layout")] text_align: TextAlign::Auto, // Flexbox #[cfg(feature = "flexbox")] flex_direction: FlexDirection::Row, #[cfg(feature = "flexbox")] flex_wrap: FlexWrap::NoWrap, #[cfg(feature = "flexbox")] flex_grow: 0.0, #[cfg(feature = "flexbox")] flex_shrink: 1.0, #[cfg(feature = "flexbox")] flex_basis: Dimension::AUTO, // Grid #[cfg(feature = "grid")] grid_template_rows: GridTrackVec::new(), #[cfg(feature = "grid")] grid_template_columns: GridTrackVec::new(), #[cfg(feature = "grid")] grid_template_areas: GridTrackVec::new(), #[cfg(feature = "grid")] grid_template_column_names: GridTrackVec::new(), #[cfg(feature = "grid")] grid_template_row_names: GridTrackVec::new(), #[cfg(feature = "grid")] grid_auto_rows: GridTrackVec::new(), #[cfg(feature = "grid")] grid_auto_columns: GridTrackVec::new(), #[cfg(feature = "grid")] grid_auto_flow: GridAutoFlow::Row, #[cfg(feature = "grid")] grid_row: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, #[cfg(feature = "grid")] grid_column: Line { start: GridPlacement::::Auto, end: GridPlacement::::Auto }, }; } impl Default for Style { fn default() -> Self { Style::DEFAULT } } impl CoreStyle for Style { type CustomIdent = S; #[inline(always)] fn box_generation_mode(&self) -> BoxGenerationMode { match self.display { Display::None => BoxGenerationMode::None, _ => BoxGenerationMode::Normal, } } #[inline(always)] #[cfg(feature = "block_layout")] fn is_block(&self) -> bool { matches!(self.display, Display::Block) } #[inline(always)] fn is_compressible_replaced(&self) -> bool { self.item_is_replaced } #[inline(always)] fn box_sizing(&self) -> BoxSizing { self.box_sizing } #[inline(always)] fn direction(&self) -> Direction { self.direction } #[inline(always)] fn overflow(&self) -> Point { self.overflow } #[inline(always)] fn scrollbar_width(&self) -> f32 { self.scrollbar_width } #[inline(always)] fn position(&self) -> Position { self.position } #[inline(always)] fn inset(&self) -> Rect { self.inset } #[inline(always)] fn size(&self) -> Size { self.size } #[inline(always)] fn min_size(&self) -> Size { self.min_size } #[inline(always)] fn max_size(&self) -> Size { self.max_size } #[inline(always)] fn aspect_ratio(&self) -> Option { self.aspect_ratio } #[inline(always)] fn margin(&self) -> Rect { self.margin } #[inline(always)] fn padding(&self) -> Rect { self.padding } #[inline(always)] fn border(&self) -> Rect { self.border } } impl CoreStyle for &'_ T { type CustomIdent = T::CustomIdent; #[inline(always)] fn box_generation_mode(&self) -> BoxGenerationMode { (*self).box_generation_mode() } #[inline(always)] fn is_block(&self) -> bool { (*self).is_block() } #[inline(always)] fn is_compressible_replaced(&self) -> bool { (*self).is_compressible_replaced() } #[inline(always)] fn box_sizing(&self) -> BoxSizing { (*self).box_sizing() } #[inline(always)] fn direction(&self) -> Direction { (*self).direction() } #[inline(always)] fn overflow(&self) -> Point { (*self).overflow() } #[inline(always)] fn scrollbar_width(&self) -> f32 { (*self).scrollbar_width() } #[inline(always)] fn position(&self) -> Position { (*self).position() } #[inline(always)] fn inset(&self) -> Rect { (*self).inset() } #[inline(always)] fn size(&self) -> Size { (*self).size() } #[inline(always)] fn min_size(&self) -> Size { (*self).min_size() } #[inline(always)] fn max_size(&self) -> Size { (*self).max_size() } #[inline(always)] fn aspect_ratio(&self) -> Option { (*self).aspect_ratio() } #[inline(always)] fn margin(&self) -> Rect { (*self).margin() } #[inline(always)] fn padding(&self) -> Rect { (*self).padding() } #[inline(always)] fn border(&self) -> Rect { (*self).border() } } #[cfg(feature = "block_layout")] impl BlockContainerStyle for Style { #[inline(always)] fn text_align(&self) -> TextAlign { self.text_align } #[inline(always)] fn align_content(&self) -> Option { self.align_content } } #[cfg(feature = "block_layout")] impl BlockContainerStyle for &'_ T { #[inline(always)] fn text_align(&self) -> TextAlign { (*self).text_align() } #[inline(always)] fn align_content(&self) -> Option { (*self).align_content() } } #[cfg(feature = "block_layout")] impl BlockItemStyle for Style { #[inline(always)] fn is_table(&self) -> bool { self.item_is_table } #[cfg(feature = "float_layout")] #[inline(always)] fn float(&self) -> Float { self.float } #[cfg(feature = "float_layout")] #[inline(always)] fn clear(&self) -> Clear { self.clear } } #[cfg(feature = "block_layout")] impl BlockItemStyle for &'_ T { #[inline(always)] fn is_table(&self) -> bool { (*self).is_table() } #[cfg(feature = "float_layout")] #[inline(always)] fn float(&self) -> Float { (*self).float() } #[cfg(feature = "float_layout")] #[inline(always)] fn clear(&self) -> Clear { (*self).clear() } } #[cfg(feature = "flexbox")] impl FlexboxContainerStyle for Style { #[inline(always)] fn flex_direction(&self) -> FlexDirection { self.flex_direction } #[inline(always)] fn flex_wrap(&self) -> FlexWrap { self.flex_wrap } #[inline(always)] fn gap(&self) -> Size { self.gap } #[inline(always)] fn align_content(&self) -> Option { self.align_content } #[inline(always)] fn align_items(&self) -> Option { self.align_items } #[inline(always)] fn justify_content(&self) -> Option { self.justify_content } } #[cfg(feature = "flexbox")] impl FlexboxContainerStyle for &'_ T { #[inline(always)] fn flex_direction(&self) -> FlexDirection { (*self).flex_direction() } #[inline(always)] fn flex_wrap(&self) -> FlexWrap { (*self).flex_wrap() } #[inline(always)] fn gap(&self) -> Size { (*self).gap() } #[inline(always)] fn align_content(&self) -> Option { (*self).align_content() } #[inline(always)] fn align_items(&self) -> Option { (*self).align_items() } #[inline(always)] fn justify_content(&self) -> Option { (*self).justify_content() } } #[cfg(feature = "flexbox")] impl FlexboxItemStyle for Style { #[inline(always)] fn flex_basis(&self) -> Dimension { self.flex_basis } #[inline(always)] fn flex_grow(&self) -> f32 { self.flex_grow } #[inline(always)] fn flex_shrink(&self) -> f32 { self.flex_shrink } #[inline(always)] fn align_self(&self) -> Option { self.align_self } } #[cfg(feature = "flexbox")] impl FlexboxItemStyle for &'_ T { #[inline(always)] fn flex_basis(&self) -> Dimension { (*self).flex_basis() } #[inline(always)] fn flex_grow(&self) -> f32 { (*self).flex_grow() } #[inline(always)] fn flex_shrink(&self) -> f32 { (*self).flex_shrink() } #[inline(always)] fn align_self(&self) -> Option { (*self).align_self() } } #[cfg(feature = "grid")] impl GridContainerStyle for Style { type Repetition<'a> = &'a GridTemplateRepetition where Self: 'a; type TemplateTrackList<'a> = core::iter::Map< core::slice::Iter<'a, GridTemplateComponent>, fn(&'a GridTemplateComponent) -> GenericGridTemplateComponent>, > where Self: 'a; type AutoTrackList<'a> = core::iter::Copied> where Self: 'a; #[cfg(feature = "grid")] type TemplateLineNames<'a> = core::iter::Map>, fn(&GridTrackVec) -> core::slice::Iter<'_, S>> where Self: 'a; #[cfg(feature = "grid")] type GridTemplateAreas<'a> = core::iter::Cloned>> where Self: 'a; #[inline(always)] fn grid_template_rows(&self) -> Option> { Some(self.grid_template_rows.iter().map(|c| c.as_component_ref())) } #[inline(always)] fn grid_template_columns(&self) -> Option> { Some(self.grid_template_columns.iter().map(|c| c.as_component_ref())) } #[inline(always)] fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> { self.grid_auto_rows.iter().copied() } #[inline(always)] fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> { self.grid_auto_columns.iter().copied() } #[inline(always)] fn grid_auto_flow(&self) -> GridAutoFlow { self.grid_auto_flow } #[inline(always)] fn gap(&self) -> Size { self.gap } #[inline(always)] fn align_content(&self) -> Option { self.align_content } #[inline(always)] fn justify_content(&self) -> Option { self.justify_content } #[inline(always)] fn align_items(&self) -> Option { self.align_items } #[inline(always)] fn justify_items(&self) -> Option { self.justify_items } #[inline(always)] #[cfg(feature = "grid")] fn grid_template_areas(&self) -> Option> { Some(self.grid_template_areas.iter().cloned()) } #[inline(always)] #[cfg(feature = "grid")] fn grid_template_column_names(&self) -> Option> { Some(self.grid_template_column_names.iter().map(|names| names.iter())) } #[inline(always)] #[cfg(feature = "grid")] fn grid_template_row_names(&self) -> Option> { Some(self.grid_template_row_names.iter().map(|names| names.iter())) } } #[cfg(feature = "grid")] impl GridContainerStyle for &'_ T { type Repetition<'a> = T::Repetition<'a> where Self: 'a; type TemplateTrackList<'a> = T::TemplateTrackList<'a> where Self: 'a; type AutoTrackList<'a> = T::AutoTrackList<'a> where Self: 'a; /// The type returned by grid_template_row_names and grid_template_column_names #[cfg(feature = "grid")] type TemplateLineNames<'a> = T::TemplateLineNames<'a> where Self: 'a; #[cfg(feature = "grid")] type GridTemplateAreas<'a> = T::GridTemplateAreas<'a> where Self: 'a; #[inline(always)] fn grid_template_rows(&self) -> Option> { (*self).grid_template_rows() } #[inline(always)] fn grid_template_columns(&self) -> Option> { (*self).grid_template_columns() } #[inline(always)] fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> { (*self).grid_auto_rows() } #[inline(always)] fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> { (*self).grid_auto_columns() } #[cfg(feature = "grid")] #[inline(always)] fn grid_template_areas(&self) -> Option> { (*self).grid_template_areas() } #[cfg(feature = "grid")] #[inline(always)] fn grid_template_column_names(&self) -> Option> { (*self).grid_template_column_names() } #[cfg(feature = "grid")] #[inline(always)] fn grid_template_row_names(&self) -> Option> { (*self).grid_template_row_names() } #[inline(always)] fn grid_auto_flow(&self) -> GridAutoFlow { (*self).grid_auto_flow() } #[inline(always)] fn gap(&self) -> Size { (*self).gap() } #[inline(always)] fn align_content(&self) -> Option { (*self).align_content() } #[inline(always)] fn justify_content(&self) -> Option { (*self).justify_content() } #[inline(always)] fn align_items(&self) -> Option { (*self).align_items() } #[inline(always)] fn justify_items(&self) -> Option { (*self).justify_items() } } #[cfg(feature = "grid")] impl GridItemStyle for Style { #[inline(always)] fn grid_row(&self) -> Line> { // TODO: Investigate eliminating clone self.grid_row.clone() } #[inline(always)] fn grid_column(&self) -> Line> { // TODO: Investigate eliminating clone self.grid_column.clone() } #[inline(always)] fn align_self(&self) -> Option { self.align_self } #[inline(always)] fn justify_self(&self) -> Option { self.justify_self } } #[cfg(feature = "grid")] impl GridItemStyle for &'_ T { #[inline(always)] fn grid_row(&self) -> Line> { (*self).grid_row() } #[inline(always)] fn grid_column(&self) -> Line> { (*self).grid_column() } #[inline(always)] fn align_self(&self) -> Option { (*self).align_self() } #[inline(always)] fn justify_self(&self) -> Option { (*self).justify_self() } } #[cfg(test)] mod tests { use std::sync::Arc; use super::Style; use crate::sys::DefaultCheapStr; use crate::{geometry::*, style_helpers::TaffyAuto as _}; #[test] fn defaults_match() { #[cfg(feature = "grid")] use super::GridPlacement; let old_defaults: Style = Style { dummy: core::marker::PhantomData, display: Default::default(), item_is_table: false, item_is_replaced: false, box_sizing: Default::default(), #[cfg(feature = "float_layout")] float: Default::default(), #[cfg(feature = "float_layout")] clear: Default::default(), direction: Default::default(), overflow: Default::default(), scrollbar_width: 0.0, position: Default::default(), #[cfg(feature = "flexbox")] flex_direction: Default::default(), #[cfg(feature = "flexbox")] flex_wrap: Default::default(), #[cfg(any(feature = "flexbox", feature = "grid"))] align_items: Default::default(), #[cfg(any(feature = "flexbox", feature = "grid"))] align_self: Default::default(), #[cfg(feature = "grid")] justify_items: Default::default(), #[cfg(feature = "grid")] justify_self: Default::default(), #[cfg(any(feature = "flexbox", feature = "grid", feature = "block_layout"))] align_content: Default::default(), #[cfg(any(feature = "flexbox", feature = "grid"))] justify_content: Default::default(), inset: Rect::auto(), margin: Rect::zero(), padding: Rect::zero(), border: Rect::zero(), gap: Size::zero(), #[cfg(feature = "block_layout")] text_align: Default::default(), #[cfg(feature = "flexbox")] flex_grow: 0.0, #[cfg(feature = "flexbox")] flex_shrink: 1.0, #[cfg(feature = "flexbox")] flex_basis: super::Dimension::AUTO, size: Size::auto(), min_size: Size::auto(), max_size: Size::auto(), aspect_ratio: Default::default(), #[cfg(feature = "grid")] grid_template_rows: Default::default(), #[cfg(feature = "grid")] grid_template_columns: Default::default(), #[cfg(feature = "grid")] grid_template_row_names: Default::default(), #[cfg(feature = "grid")] grid_template_column_names: Default::default(), #[cfg(feature = "grid")] grid_template_areas: Default::default(), #[cfg(feature = "grid")] grid_auto_rows: Default::default(), #[cfg(feature = "grid")] grid_auto_columns: Default::default(), #[cfg(feature = "grid")] grid_auto_flow: Default::default(), #[cfg(feature = "grid")] grid_row: Line { start: GridPlacement::Auto, end: GridPlacement::Auto }, #[cfg(feature = "grid")] grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto }, }; assert_eq!(Style::DEFAULT, Style::::default()); assert_eq!(Style::DEFAULT, old_defaults); } // NOTE: Please feel free the update the sizes in this test as required. This test is here to prevent unintentional size changes // and to serve as accurate up-to-date documentation on the sizes. #[test] fn style_sizes() { use super::*; type S = crate::sys::DefaultCheapStr; fn assert_type_size(expected_size: usize) { let name = ::core::any::type_name::(); let name = name.replace("taffy::geometry::", ""); let name = name.replace("taffy::style::dimension::", ""); let name = name.replace("taffy::style::alignment::", ""); let name = name.replace("taffy::style::flex::", ""); let name = name.replace("taffy::style::grid::", ""); assert_eq!( ::core::mem::size_of::(), expected_size, "Expected {} for be {} byte(s) but it was {} byte(s)", name, expected_size, ::core::mem::size_of::(), ); } // Display and Position assert_type_size::(1); assert_type_size::(1); assert_type_size::(1); assert_type_size::(1); // Dimensions and aggregations of Dimensions assert_type_size::(4); assert_type_size::(8); assert_type_size::(8); assert_type_size::(8); assert_type_size::>(16); assert_type_size::>(16); assert_type_size::>(16); assert_type_size::>(32); assert_type_size::>(32); assert_type_size::>(32); // Alignment — `AlignContent` and `AlignItems` are structs of two `#[repr(u8)]` enums // (position keyword + safety modifier). Niche-packing in the safety byte (only 2 of // 256 values used) lets `Option<_>` stay the same size as the bare struct. assert_type_size::(1); assert_type_size::(1); assert_type_size::(1); assert_type_size::(2); assert_type_size::(2); assert_type_size::>(2); assert_type_size::>(2); // Flexbox Container assert_type_size::(1); assert_type_size::(1); // CSS Grid Container assert_type_size::(1); assert_type_size::(8); assert_type_size::(8); assert_type_size::(16); assert_type_size::>(24); assert_type_size::>>(24); // String-type dependent (String) assert_type_size::>(56); assert_type_size::>(32); assert_type_size::>>(64); assert_type_size::>(544); // String-type dependent (Arc) assert_type_size::>>(56); assert_type_size::>>(24); assert_type_size::>>>(48); assert_type_size::>>(512); } }