| //! 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 dimension; |
| |
| #[cfg(feature = "block_layout")] |
| mod block; |
| #[cfg(feature = "flexbox")] |
| mod flex; |
| #[cfg(feature = "grid")] |
| mod grid; |
| |
| pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, JustifyItems, JustifySelf}; |
| pub use self::dimension::{AvailableSpace, Dimension, LengthPercentage, LengthPercentageAuto}; |
| |
| #[cfg(feature = "block_layout")] |
| pub use self::block::{BlockContainerStyle, BlockItemStyle, TextAlign}; |
| #[cfg(feature = "flexbox")] |
| pub use self::flex::{FlexDirection, FlexWrap, FlexboxContainerStyle, FlexboxItemStyle}; |
| #[cfg(feature = "grid")] |
| pub(crate) use self::grid::{GenericGridPlacement, OriginZeroGridPlacement}; |
| #[cfg(feature = "grid")] |
| pub use self::grid::{ |
| GridAutoFlow, GridContainerStyle, GridItemStyle, GridPlacement, GridTrackRepetition, MaxTrackSizingFunction, |
| MinTrackSizingFunction, NonRepeatedTrackSizingFunction, TrackSizingFunction, |
| }; |
| |
| use crate::geometry::{Point, Rect, Size}; |
| |
| #[cfg(feature = "grid")] |
| use crate::geometry::Line; |
| #[cfg(feature = "serde")] |
| use crate::style_helpers; |
| #[cfg(feature = "grid")] |
| use crate::util::sys::GridTrackVec; |
| |
| /// 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 { |
| /// 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 |
| } |
| /// Which box do size styles apply to |
| #[inline(always)] |
| fn box_sizing(&self) -> BoxSizing { |
| BoxSizing::BorderBox |
| } |
| |
| // Overflow properties |
| /// How children overflowing their container should affect layout |
| #[inline(always)] |
| fn overflow(&self) -> Point<Overflow> { |
| 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<LengthPercentageAuto> { |
| Style::DEFAULT.inset |
| } |
| |
| // Size properies |
| /// Sets the initial size of the item |
| #[inline(always)] |
| fn size(&self) -> Size<Dimension> { |
| Style::DEFAULT.size |
| } |
| /// Controls the minimum size of the item |
| #[inline(always)] |
| fn min_size(&self) -> Size<Dimension> { |
| Style::DEFAULT.min_size |
| } |
| /// Controls the maximum size of the item |
| #[inline(always)] |
| fn max_size(&self) -> Size<Dimension> { |
| 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<f32> { |
| Style::DEFAULT.aspect_ratio |
| } |
| |
| // Spacing Properties |
| /// How large should the margin be on each side? |
| #[inline(always)] |
| fn margin(&self) -> Rect<LengthPercentageAuto> { |
| Style::DEFAULT.margin |
| } |
| /// How large should the padding be on each side? |
| #[inline(always)] |
| fn padding(&self) -> Rect<LengthPercentage> { |
| Style::DEFAULT.padding |
| } |
| /// How large should the border be on each side? |
| #[inline(always)] |
| fn border(&self) -> Rect<LengthPercentage> { |
| 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 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 |
| } |
| } |
| |
| 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 = "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: <https://www.w3.org/TR/css-display-3/#box-generation> |
| #[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)] |
| #[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. |
| 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, |
| } |
| |
| impl Default for Position { |
| fn default() -> Self { |
| Self::Relative |
| } |
| } |
| |
| /// 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 h<ttps://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing> |
| #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
| #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| pub enum BoxSizing { |
| /// Size styles such size, min_size, max_size specify the box's "content box" (the size excluding padding/border/margin) |
| BorderBox, |
| /// Size styles such size, min_size, max_size specify the box's "border box" (the size excluding margin but including padding/border) |
| ContentBox, |
| } |
| |
| impl Default for BoxSizing { |
| fn default() -> Self { |
| Self::BorderBox |
| } |
| } |
| |
| /// 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`. |
| /// |
| /// <https://developer.mozilla.org/en-US/docs/Web/CSS/overflow> |
| #[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(crate) 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<f32> { |
| match self.is_scroll_container() { |
| true => Some(0.0), |
| false => None, |
| } |
| } |
| } |
| |
| /// 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 { |
| /// 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, |
| /// Should size styles apply to the content box or the border box of the node |
| pub box_sizing: BoxSizing, |
| |
| // Overflow properties |
| /// How children overflowing their container should affect layout |
| pub overflow: Point<Overflow>, |
| /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes. |
| pub scrollbar_width: f32, |
| |
| // 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<LengthPercentageAuto>, |
| |
| // Size properties |
| /// Sets the initial size of the item |
| #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))] |
| pub size: Size<Dimension>, |
| /// Controls the minimum size of the item |
| #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))] |
| pub min_size: Size<Dimension>, |
| /// Controls the maximum size of the item |
| #[cfg_attr(feature = "serde", serde(default = "style_helpers::auto"))] |
| pub max_size: Size<Dimension>, |
| /// Sets the preferred aspect ratio for the item |
| /// |
| /// The ratio is calculated as width divided by height. |
| pub aspect_ratio: Option<f32>, |
| |
| // Spacing Properties |
| /// How large should the margin be on each side? |
| #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))] |
| pub margin: Rect<LengthPercentageAuto>, |
| /// How large should the padding be on each side? |
| #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))] |
| pub padding: Rect<LengthPercentage>, |
| /// How large should the border be on each side? |
| #[cfg_attr(feature = "serde", serde(default = "style_helpers::zero"))] |
| pub border: Rect<LengthPercentage>, |
| |
| // Alignment properties |
| /// How this node's children aligned in the cross/block axis? |
| #[cfg(any(feature = "flexbox", feature = "grid"))] |
| pub align_items: Option<AlignItems>, |
| /// 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<AlignSelf>, |
| /// How this node's children should be aligned in the inline axis |
| #[cfg(feature = "grid")] |
| pub justify_items: Option<AlignItems>, |
| /// 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<AlignSelf>, |
| /// How should content contained within this item be aligned in the cross/block axis |
| #[cfg(any(feature = "flexbox", feature = "grid"))] |
| pub align_content: Option<AlignContent>, |
| /// How should content contained within this item be aligned in the main/inline axis |
| #[cfg(any(feature = "flexbox", feature = "grid"))] |
| pub justify_content: Option<JustifyContent>, |
| /// 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<LengthPercentage>, |
| |
| // 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<TrackSizingFunction>, |
| /// Defines the track sizing functions (widths) of the grid columns |
| #[cfg(feature = "grid")] |
| pub grid_template_columns: GridTrackVec<TrackSizingFunction>, |
| /// Defines the size of implicitly created rows |
| #[cfg(feature = "grid")] |
| pub grid_auto_rows: GridTrackVec<NonRepeatedTrackSizingFunction>, |
| /// Defined the size of implicitly created columns |
| #[cfg(feature = "grid")] |
| pub grid_auto_columns: GridTrackVec<NonRepeatedTrackSizingFunction>, |
| /// Controls how items get placed into the grid for auto-placed items |
| #[cfg(feature = "grid")] |
| pub grid_auto_flow: GridAutoFlow, |
| |
| // Grid child properties |
| /// Defines which row in the grid the item should start and end at |
| #[cfg(feature = "grid")] |
| pub grid_row: Line<GridPlacement>, |
| /// Defines which column in the grid the item should start and end at |
| #[cfg(feature = "grid")] |
| pub grid_column: Line<GridPlacement>, |
| } |
| |
| impl Style { |
| /// The [`Default`] layout, in a form that can be used in const functions |
| pub const DEFAULT: Style = Style { |
| display: Display::DEFAULT, |
| item_is_table: false, |
| box_sizing: BoxSizing::BorderBox, |
| overflow: Point { x: Overflow::Visible, y: Overflow::Visible }, |
| scrollbar_width: 0.0, |
| 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"))] |
| 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_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 { |
| #[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 box_sizing(&self) -> BoxSizing { |
| self.box_sizing |
| } |
| #[inline(always)] |
| fn overflow(&self) -> Point<Overflow> { |
| 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<LengthPercentageAuto> { |
| self.inset |
| } |
| #[inline(always)] |
| fn size(&self) -> Size<Dimension> { |
| self.size |
| } |
| #[inline(always)] |
| fn min_size(&self) -> Size<Dimension> { |
| self.min_size |
| } |
| #[inline(always)] |
| fn max_size(&self) -> Size<Dimension> { |
| self.max_size |
| } |
| #[inline(always)] |
| fn aspect_ratio(&self) -> Option<f32> { |
| self.aspect_ratio |
| } |
| #[inline(always)] |
| fn margin(&self) -> Rect<LengthPercentageAuto> { |
| self.margin |
| } |
| #[inline(always)] |
| fn padding(&self) -> Rect<LengthPercentage> { |
| self.padding |
| } |
| #[inline(always)] |
| fn border(&self) -> Rect<LengthPercentage> { |
| self.border |
| } |
| } |
| |
| impl<T: CoreStyle> CoreStyle for &'_ T { |
| #[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 box_sizing(&self) -> BoxSizing { |
| (*self).box_sizing() |
| } |
| #[inline(always)] |
| fn overflow(&self) -> Point<Overflow> { |
| (*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<LengthPercentageAuto> { |
| (*self).inset() |
| } |
| #[inline(always)] |
| fn size(&self) -> Size<Dimension> { |
| (*self).size() |
| } |
| #[inline(always)] |
| fn min_size(&self) -> Size<Dimension> { |
| (*self).min_size() |
| } |
| #[inline(always)] |
| fn max_size(&self) -> Size<Dimension> { |
| (*self).max_size() |
| } |
| #[inline(always)] |
| fn aspect_ratio(&self) -> Option<f32> { |
| (*self).aspect_ratio() |
| } |
| #[inline(always)] |
| fn margin(&self) -> Rect<LengthPercentageAuto> { |
| (*self).margin() |
| } |
| #[inline(always)] |
| fn padding(&self) -> Rect<LengthPercentage> { |
| (*self).padding() |
| } |
| #[inline(always)] |
| fn border(&self) -> Rect<LengthPercentage> { |
| (*self).border() |
| } |
| } |
| |
| #[cfg(feature = "block_layout")] |
| impl BlockContainerStyle for &Style { |
| #[inline(always)] |
| fn text_align(&self) -> TextAlign { |
| self.text_align |
| } |
| } |
| |
| #[cfg(feature = "block_layout")] |
| impl<T: BlockContainerStyle> BlockContainerStyle for &'_ T { |
| #[inline(always)] |
| fn text_align(&self) -> TextAlign { |
| (*self).text_align() |
| } |
| } |
| |
| #[cfg(feature = "block_layout")] |
| impl BlockItemStyle for Style { |
| #[inline(always)] |
| fn is_table(&self) -> bool { |
| self.item_is_table |
| } |
| } |
| |
| #[cfg(feature = "block_layout")] |
| impl<T: BlockItemStyle> BlockItemStyle for &'_ T { |
| #[inline(always)] |
| fn is_table(&self) -> bool { |
| (*self).is_table() |
| } |
| } |
| |
| #[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<LengthPercentage> { |
| self.gap |
| } |
| #[inline(always)] |
| fn align_content(&self) -> Option<AlignContent> { |
| self.align_content |
| } |
| #[inline(always)] |
| fn align_items(&self) -> Option<AlignItems> { |
| self.align_items |
| } |
| #[inline(always)] |
| fn justify_content(&self) -> Option<JustifyContent> { |
| self.justify_content |
| } |
| } |
| |
| #[cfg(feature = "flexbox")] |
| impl<T: FlexboxContainerStyle> 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<LengthPercentage> { |
| (*self).gap() |
| } |
| #[inline(always)] |
| fn align_content(&self) -> Option<AlignContent> { |
| (*self).align_content() |
| } |
| #[inline(always)] |
| fn align_items(&self) -> Option<AlignItems> { |
| (*self).align_items() |
| } |
| #[inline(always)] |
| fn justify_content(&self) -> Option<JustifyContent> { |
| (*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<AlignSelf> { |
| self.align_self |
| } |
| } |
| |
| #[cfg(feature = "flexbox")] |
| impl<T: FlexboxItemStyle> 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<AlignSelf> { |
| (*self).align_self() |
| } |
| } |
| |
| #[cfg(feature = "grid")] |
| impl GridContainerStyle for Style { |
| type TemplateTrackList<'a> |
| = &'a [TrackSizingFunction] |
| where |
| Self: 'a; |
| type AutoTrackList<'a> |
| = &'a [NonRepeatedTrackSizingFunction] |
| where |
| Self: 'a; |
| |
| #[inline(always)] |
| fn grid_template_rows(&self) -> &[TrackSizingFunction] { |
| &self.grid_template_rows |
| } |
| #[inline(always)] |
| fn grid_template_columns(&self) -> &[TrackSizingFunction] { |
| &self.grid_template_columns |
| } |
| #[inline(always)] |
| fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] { |
| &self.grid_auto_rows |
| } |
| #[inline(always)] |
| fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] { |
| &self.grid_auto_columns |
| } |
| #[inline(always)] |
| fn grid_auto_flow(&self) -> GridAutoFlow { |
| self.grid_auto_flow |
| } |
| #[inline(always)] |
| fn gap(&self) -> Size<LengthPercentage> { |
| self.gap |
| } |
| #[inline(always)] |
| fn align_content(&self) -> Option<AlignContent> { |
| self.align_content |
| } |
| #[inline(always)] |
| fn justify_content(&self) -> Option<JustifyContent> { |
| self.justify_content |
| } |
| #[inline(always)] |
| fn align_items(&self) -> Option<AlignItems> { |
| self.align_items |
| } |
| #[inline(always)] |
| fn justify_items(&self) -> Option<AlignItems> { |
| self.justify_items |
| } |
| } |
| |
| #[cfg(feature = "grid")] |
| impl<T: GridContainerStyle> GridContainerStyle for &'_ T { |
| type TemplateTrackList<'a> |
| = T::TemplateTrackList<'a> |
| where |
| Self: 'a; |
| type AutoTrackList<'a> |
| = T::AutoTrackList<'a> |
| where |
| Self: 'a; |
| |
| #[inline(always)] |
| fn grid_template_rows(&self) -> Self::TemplateTrackList<'_> { |
| (*self).grid_template_rows() |
| } |
| #[inline(always)] |
| fn grid_template_columns(&self) -> Self::TemplateTrackList<'_> { |
| (*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() |
| } |
| #[inline(always)] |
| fn grid_auto_flow(&self) -> GridAutoFlow { |
| (*self).grid_auto_flow() |
| } |
| #[inline(always)] |
| fn gap(&self) -> Size<LengthPercentage> { |
| (*self).gap() |
| } |
| #[inline(always)] |
| fn align_content(&self) -> Option<AlignContent> { |
| (*self).align_content() |
| } |
| #[inline(always)] |
| fn justify_content(&self) -> Option<JustifyContent> { |
| (*self).justify_content() |
| } |
| #[inline(always)] |
| fn align_items(&self) -> Option<AlignItems> { |
| (*self).align_items() |
| } |
| #[inline(always)] |
| fn justify_items(&self) -> Option<AlignItems> { |
| (*self).justify_items() |
| } |
| } |
| |
| #[cfg(feature = "grid")] |
| impl GridItemStyle for &'_ Style { |
| #[inline(always)] |
| fn grid_row(&self) -> Line<GridPlacement> { |
| self.grid_row |
| } |
| #[inline(always)] |
| fn grid_column(&self) -> Line<GridPlacement> { |
| self.grid_column |
| } |
| #[inline(always)] |
| fn align_self(&self) -> Option<AlignSelf> { |
| self.align_self |
| } |
| #[inline(always)] |
| fn justify_self(&self) -> Option<AlignSelf> { |
| self.justify_self |
| } |
| } |
| |
| #[cfg(feature = "grid")] |
| impl<T: GridItemStyle> GridItemStyle for &'_ T { |
| #[inline(always)] |
| fn grid_row(&self) -> Line<GridPlacement> { |
| (*self).grid_row() |
| } |
| #[inline(always)] |
| fn grid_column(&self) -> Line<GridPlacement> { |
| (*self).grid_column() |
| } |
| #[inline(always)] |
| fn align_self(&self) -> Option<AlignSelf> { |
| (*self).align_self() |
| } |
| #[inline(always)] |
| fn justify_self(&self) -> Option<AlignSelf> { |
| (*self).justify_self() |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::Style; |
| use crate::geometry::*; |
| |
| #[test] |
| fn defaults_match() { |
| #[cfg(feature = "grid")] |
| use super::GridPlacement; |
| |
| let old_defaults = Style { |
| display: Default::default(), |
| item_is_table: false, |
| box_sizing: 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"))] |
| 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_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::*; |
| |
| fn assert_type_size<T>(expected_size: usize) { |
| let name = ::core::any::type_name::<T>(); |
| 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::<T>(), |
| expected_size, |
| "Expected {} for be {} byte(s) but it was {} byte(s)", |
| name, |
| expected_size, |
| ::core::mem::size_of::<T>(), |
| ); |
| } |
| |
| // Display and Position |
| assert_type_size::<Display>(1); |
| assert_type_size::<BoxSizing>(1); |
| assert_type_size::<Position>(1); |
| assert_type_size::<Overflow>(1); |
| |
| // Dimensions and aggregations of Dimensions |
| assert_type_size::<f32>(4); |
| assert_type_size::<LengthPercentage>(8); |
| assert_type_size::<LengthPercentageAuto>(8); |
| assert_type_size::<Dimension>(8); |
| assert_type_size::<Size<LengthPercentage>>(16); |
| assert_type_size::<Size<LengthPercentageAuto>>(16); |
| assert_type_size::<Size<Dimension>>(16); |
| assert_type_size::<Rect<LengthPercentage>>(32); |
| assert_type_size::<Rect<LengthPercentageAuto>>(32); |
| assert_type_size::<Rect<Dimension>>(32); |
| |
| // Alignment |
| assert_type_size::<AlignContent>(1); |
| assert_type_size::<AlignItems>(1); |
| assert_type_size::<Option<AlignItems>>(1); |
| |
| // Flexbox Container |
| assert_type_size::<FlexDirection>(1); |
| assert_type_size::<FlexWrap>(1); |
| |
| // CSS Grid Container |
| assert_type_size::<GridAutoFlow>(1); |
| assert_type_size::<MinTrackSizingFunction>(8); |
| assert_type_size::<MaxTrackSizingFunction>(12); |
| assert_type_size::<NonRepeatedTrackSizingFunction>(20); |
| assert_type_size::<TrackSizingFunction>(32); |
| assert_type_size::<Vec<NonRepeatedTrackSizingFunction>>(24); |
| assert_type_size::<Vec<TrackSizingFunction>>(24); |
| |
| // CSS Grid Item |
| assert_type_size::<GridPlacement>(4); |
| assert_type_size::<Line<GridPlacement>>(8); |
| |
| // Overall |
| assert_type_size::<Style>(352); |
| } |
| } |