From 03a6200d3e8d92af551253a4a82d09f71a43905b Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sun, 22 Oct 2023 19:22:20 +0100 Subject: [PATCH 01/13] Create style traits --- src/style/flex.rs | 66 +++++++ src/style/grid.rs | 90 ++++++++- src/style/mod.rs | 479 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 620 insertions(+), 15 deletions(-) diff --git a/src/style/flex.rs b/src/style/flex.rs index c24f488d8..f04f3a454 100644 --- a/src/style/flex.rs +++ b/src/style/flex.rs @@ -1,4 +1,70 @@ //! Style types for Flexbox layout +use super::{AlignContent, AlignItems, AlignSelf, CoreStyle, Dimension, JustifyContent, LengthPercentage, Style}; +use crate::geometry::Size; + +/// The set of styles required for a Flexbox container +pub trait FlexboxContainerStyle: CoreStyle { + /// Which direction does the main axis flow in? + #[inline(always)] + fn flex_direction(&self) -> FlexDirection { + Style::DEFAULT.flex_direction + } + /// Should elements wrap, or stay in a single line? + #[inline(always)] + fn flex_wrap(&self) -> FlexWrap { + Style::DEFAULT.flex_wrap + } + + /// How large should the gaps between items in a grid or flex container be? + #[inline(always)] + fn gap(&self) -> Size { + Style::DEFAULT.gap + } + + // Alignment properties + + /// How should content contained within this item be aligned in the cross/block axis + #[inline(always)] + fn align_content(&self) -> Option { + Style::DEFAULT.align_content + } + /// How this node's children aligned in the cross/block axis? + #[inline(always)] + fn align_items(&self) -> Option { + Style::DEFAULT.align_items + } + /// How this node's children should be aligned in the inline axis + #[inline(always)] + fn justify_content(&self) -> Option { + Style::DEFAULT.justify_content + } +} + +/// The set of styles required for a Flexbox item (child of a Flexbox container) +pub trait FlexboxItemStyle: CoreStyle { + /// Sets the initial main axis size of the item + #[inline(always)] + fn flex_basis(&self) -> Dimension { + Style::DEFAULT.flex_basis + } + /// The relative rate at which this item grows when it is expanding to fill space + #[inline(always)] + fn flex_grow(&self) -> f32 { + Style::DEFAULT.flex_grow + } + /// The relative rate at which this item shrinks when it is contracting to fit into space + #[inline(always)] + fn flex_shrink(&self) -> f32 { + Style::DEFAULT.flex_shrink + } + + /// How this node should be aligned in the cross/block axis + /// Falls back to the parents [`AlignItems`] if not set + #[inline(always)] + fn align_self(&self) -> Option { + Style::DEFAULT.align_self + } +} use crate::geometry::AbsoluteAxis; diff --git a/src/style/grid.rs b/src/style/grid.rs index b2d2b04b4..0394b763d 100644 --- a/src/style/grid.rs +++ b/src/style/grid.rs @@ -1,13 +1,97 @@ //! Style types for CSS Grid layout -use super::{AlignContent, LengthPercentage, Style}; +use super::{AlignContent, AlignItems, AlignSelf, CoreStyle, JustifyContent, LengthPercentage, Style}; use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine}; -use crate::geometry::{AbsoluteAxis, AbstractAxis}; -use crate::geometry::{Line, MinMax}; +use crate::geometry::{AbsoluteAxis, AbstractAxis, Line, MinMax, Size}; use crate::style_helpers::*; use crate::util::sys::GridTrackVec; use core::cmp::{max, min}; use core::convert::Infallible; +/// The set of styles required for a CSS Grid container +pub trait GridContainerStyle: CoreStyle { + /// Defines the track sizing functions (heights) of the grid rows + #[inline(always)] + fn grid_template_rows(&self) -> &[TrackSizingFunction] { + &[] + } + /// Defines the track sizing functions (widths) of the grid columns + #[inline(always)] + fn grid_template_columns(&self) -> &[TrackSizingFunction] { + &[] + } + /// Defines the size of implicitly created rows + #[inline(always)] + fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] { + &[] + } + /// Defined the size of implicitly created columns + #[inline(always)] + fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] { + &[] + } + /// Controls how items get placed into the grid for auto-placed items + #[inline(always)] + fn grid_auto_flow(&self) -> GridAutoFlow { + Style::DEFAULT.grid_auto_flow + } + + /// How large should the gaps between items in a grid or flex container be? + #[inline(always)] + fn gap(&self) -> Size { + Style::DEFAULT.gap + } + + // Alignment properties + + /// How should content contained within this item be aligned in the cross/block axis + #[inline(always)] + fn align_content(&self) -> Option { + Style::DEFAULT.align_content + } + /// How should contained within this item be aligned in the main/inline axis + #[inline(always)] + fn justify_content(&self) -> Option { + Style::DEFAULT.justify_content + } + /// How this node's children aligned in the cross/block axis? + #[inline(always)] + fn align_items(&self) -> Option { + Style::DEFAULT.align_items + } + /// How this node's children should be aligned in the inline axis + #[inline(always)] + fn justify_items(&self) -> Option { + Style::DEFAULT.justify_items + } +} + +/// The set of styles required for a CSS Grid item (child of a CSS Grid container) +pub trait GridItemStyle: CoreStyle { + /// Defines which row in the grid the item should start and end at + #[inline(always)] + fn grid_row(&self) -> Line { + Style::DEFAULT.grid_row + } + /// Defines which column in the grid the item should start and end at + #[inline(always)] + fn grid_column(&self) -> Line { + Style::DEFAULT.grid_column + } + + /// How this node should be aligned in the cross/block axis + /// Falls back to the parents [`AlignItems`] if not set + #[inline(always)] + fn align_self(&self) -> Option { + Style::DEFAULT.align_self + } + /// How this node should be aligned in the inline axis + /// Falls back to the parents [`super::JustifyItems`] if not set + #[inline(always)] + fn justify_self(&self) -> Option { + Style::DEFAULT.justify_self + } +} + /// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used. /// /// The "dense" packing algorithm attempts to fill in holes earlier in the grid, if smaller items come up later. This may cause items to appear out-of-order, when doing so would fill in holes left by larger items. diff --git a/src/style/mod.rs b/src/style/mod.rs index 31f4419b0..681a3c5bd 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -9,7 +9,7 @@ pub use self::alignment::{AlignContent, AlignItems, AlignSelf, JustifyContent, J pub use self::dimension::{AvailableSpace, Dimension, LengthPercentage, LengthPercentageAuto}; #[cfg(feature = "flexbox")] -pub use self::flex::{FlexDirection, FlexWrap}; +pub use self::flex::{FlexDirection, FlexWrap, FlexboxContainerStyle, FlexboxItemStyle}; #[cfg(feature = "grid")] mod grid; @@ -17,8 +17,8 @@ mod grid; pub(crate) use self::grid::{GenericGridPlacement, OriginZeroGridPlacement}; #[cfg(feature = "grid")] pub use self::grid::{ - GridAutoFlow, GridPlacement, GridTrackRepetition, MaxTrackSizingFunction, MinTrackSizingFunction, - NonRepeatedTrackSizingFunction, TrackSizingFunction, + GridAutoFlow, GridContainerStyle, GridItemStyle, GridPlacement, GridTrackRepetition, MaxTrackSizingFunction, + MinTrackSizingFunction, NonRepeatedTrackSizingFunction, TrackSizingFunction, }; use crate::geometry::{Point, Rect, Size}; @@ -29,6 +29,93 @@ 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 { + 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. @@ -44,28 +131,34 @@ pub enum Display { /// The children will follow the CSS Grid layout algorithm #[cfg(feature = "grid")] Grid, - /// The children will not be laid out, and will follow absolute positioning + /// The node is hidden, and it's children will also be hidden None, } impl Display { - /// The default of Display. + /// The default Display mode #[cfg(feature = "flexbox")] pub const DEFAULT: Display = Display::Flex; - /// The default of Display. + /// The default Display mode #[cfg(all(feature = "grid", not(feature = "flexbox")))] pub const DEFAULT: Display = Display::Grid; - /// The default of Display. + /// The default Display mode #[cfg(all(feature = "block_layout", not(feature = "flexbox"), not(feature = "grid")))] pub const DEFAULT: Display = Display::Block; - /// The default of Display. + /// 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 { @@ -80,7 +173,23 @@ impl core::fmt::Display for Display { } } -impl Default for Display { +/// 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 } @@ -306,11 +415,11 @@ pub struct Style { #[cfg(feature = "flexbox")] pub flex_shrink: f32, - // Grid container properties - /// Defines the track sizing functions (widths) of the grid rows + // 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 (heights) of the grid columns + /// 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 @@ -398,6 +507,352 @@ impl Default for Style { } } +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 { + 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 { + #[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 { + (*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 = "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 { + #[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 { + 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 GridContainerStyle for &'_ T { + #[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 { + (*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 { + 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(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 super::Style; From 6a7b122d47c1f1421ce2cf3a84e359537d5e169c Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sun, 22 Oct 2023 20:40:04 +0100 Subject: [PATCH 02/13] Add algorithm-specific PartialLayoutTree traits --- src/tree/mod.rs | 5 ++- src/tree/taffy_tree.rs | 6 ++-- src/tree/traits.rs | 72 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 6 deletions(-) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 7a8961f3a..481ede8fa 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -13,7 +13,10 @@ pub use cache::Cache; pub use layout::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RequestedAxis, RunMode, SizingMode}; pub use node::NodeId; pub(crate) use traits::LayoutPartialTreeExt; -pub use traits::{LayoutPartialTree, PrintTree, RoundTree, TraversePartialTree, TraverseTree}; +pub use traits::{ + LayoutBlockContainer, LayoutFlexboxContainer, LayoutGridContainer, LayoutPartialTree, PrintTree, RoundTree, + TraversePartialTree, TraverseTree, +}; #[cfg(feature = "taffy_tree")] mod taffy_tree; diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs index 7ec8deea5..2e2d1d969 100644 --- a/src/tree/taffy_tree.rs +++ b/src/tree/taffy_tree.rs @@ -271,9 +271,11 @@ where MeasureFunction: FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, { + type CoreContainerStyle<'a> = &'a Style where Self : 'a; + #[inline(always)] - fn get_style(&self, node: NodeId) -> &Style { - &self.taffy.nodes[node.into()].style + fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { + &self.taffy.nodes[node_id.into()].style } #[inline(always)] diff --git a/src/tree/traits.rs b/src/tree/traits.rs index ce6688294..02324dbf9 100644 --- a/src/tree/traits.rs +++ b/src/tree/traits.rs @@ -128,7 +128,11 @@ //! use super::{Cache, Layout, LayoutInput, LayoutOutput, NodeId, RequestedAxis, RunMode, SizingMode}; use crate::geometry::{AbsoluteAxis, Line, Size}; -use crate::style::{AvailableSpace, Style}; +use crate::style::{AvailableSpace, CoreStyle}; +#[cfg(feature = "flexbox")] +use crate::style::{FlexboxContainerStyle, FlexboxItemStyle}; +#[cfg(feature = "grid")] +use crate::style::{GridContainerStyle, GridItemStyle}; /// This trait is Taffy's abstraction for downward tree traversal. /// However, this trait does *not* require access to any node's other than a single container node's immediate children unless you also intend to implement `TraverseTree`. @@ -157,8 +161,14 @@ pub trait TraverseTree: TraversePartialTree {} /// Note that this trait extends [`TraversePartialTree`] (not [`TraverseTree`]). Taffy's algorithm implementations have been designed such that they can be used for a laying out a single /// node that only has access to it's immediate children. pub trait LayoutPartialTree: TraversePartialTree { - /// Get a reference to the [`Style`] for this node. - fn get_style(&self, node_id: NodeId) -> &Style; + /// The style type representing the core container styles that all containers should have + /// Used when laying out the root node of a tree + type CoreContainerStyle<'a>: CoreStyle + where + Self: 'a; + + /// Get core style + fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>; /// Set the node's unrounded layout fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout); @@ -191,6 +201,62 @@ pub trait PrintTree: TraverseTree { fn get_final_layout(&self, node_id: NodeId) -> &Layout; } +#[cfg(feature = "flexbox")] +/// Extends [`LayoutPartialTree`] with getters for the styles required for Flexbox layout +pub trait LayoutFlexboxContainer: LayoutPartialTree { + /// The style type representing the Flexbox container's styles + type ContainerStyle<'a>: FlexboxContainerStyle + where + Self: 'a; + /// The style type representing each Flexbox item's styles + type ItemStyle<'a>: FlexboxItemStyle + where + Self: 'a; + + /// Get the container's styles + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>; + + /// Get the child's styles + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>; +} + +#[cfg(feature = "grid")] +/// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout +pub trait LayoutGridContainer: LayoutPartialTree { + /// The style type representing the CSS Grid container's styles + type ContainerStyle: GridContainerStyle + Clone; + + /// The style type representing each CSS Grid item's styles + type ItemStyle<'a>: GridItemStyle + where + Self: 'a; + + /// Get the container's styles + fn get_grid_container_style(&self, node_id: NodeId) -> &Self::ContainerStyle; + + /// Get the child's styles + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>; +} + +#[cfg(feature = "block_layout")] +/// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Block layout +pub trait LayoutBlockContainer: LayoutPartialTree { + /// The style type representing the CSS Block container's styles + type ContainerStyle<'a>: CoreStyle + where + Self: 'a; + /// The style type representing each CSS Block item's styles + type ItemStyle<'a>: CoreStyle + where + Self: 'a; + + /// Get the container's styles + fn get_block_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>; + + /// Get the child's styles + fn get_block_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>; +} + // --- PRIVATE TRAITS /// A private trait which allows us to add extra convenience methods to types which implement From 87405bdaef346eecdbe383ec332dc4b4356d3034 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 16 Jul 2024 14:58:42 +1200 Subject: [PATCH 03/13] Taffy tree changes --- src/tree/taffy_tree.rs | 60 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs index 2e2d1d969..48ccc2605 100644 --- a/src/tree/taffy_tree.rs +++ b/src/tree/taffy_tree.rs @@ -23,6 +23,7 @@ use crate::compute::compute_grid_layout; use crate::compute::{ compute_cached_layout, compute_hidden_layout, compute_leaf_layout, compute_root_layout, round_layout, }; +use crate::{LayoutBlockContainer, LayoutFlexboxContainer, LayoutGridContainer}; /// The error Taffy generates on invalid operations pub type TaffyResult = Result; @@ -303,7 +304,7 @@ where // // If there was no cache match and a new result needs to be computed then that result will be added to the cache compute_cached_layout(self, node, inputs, |tree, node, inputs| { - let display_mode = tree.get_style(node).display; + let display_mode = tree.taffy.nodes[node.into()].style.display; let has_children = tree.child_count(node) > 0; debug_log!(display_mode); @@ -339,6 +340,63 @@ where } } +impl<'t, NodeContext, MeasureFunction> LayoutBlockContainer for TaffyView<'t, NodeContext, MeasureFunction> +where + MeasureFunction: + FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, +{ + type ContainerStyle<'a> = &'a Style where Self: 'a; + type ItemStyle<'a> = &'a Style where Self: 'a; + + #[inline(always)] + fn get_block_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + self.get_core_container_style(node_id) + } + + #[inline(always)] + fn get_block_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + self.get_core_container_style(child_node_id) + } +} + +impl<'t, NodeContext, MeasureFunction> LayoutFlexboxContainer for TaffyView<'t, NodeContext, MeasureFunction> +where + MeasureFunction: + FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, +{ + type ContainerStyle<'a> = &'a Style where Self: 'a; + type ItemStyle<'a> = &'a Style where Self: 'a; + + #[inline(always)] + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + &self.taffy.nodes[node_id.into()].style + } + + #[inline(always)] + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + &self.taffy.nodes[child_node_id.into()].style + } +} + +impl<'t, NodeContext, MeasureFunction> LayoutGridContainer for TaffyView<'t, NodeContext, MeasureFunction> +where + MeasureFunction: + FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, +{ + type ContainerStyle = Style; + type ItemStyle<'a> = &'a Style where Self: 'a; + + #[inline(always)] + fn get_grid_container_style(&self, node_id: NodeId) -> &Self::ContainerStyle { + &self.taffy.nodes[node_id.into()].style + } + + #[inline(always)] + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + &self.taffy.nodes[child_node_id.into()].style + } +} + // RoundTree impl for TaffyView impl<'t, NodeContext, MeasureFunction> RoundTree for TaffyView<'t, NodeContext, MeasureFunction> where From 5790da1867bd11d0181b0adbba46ea4c2bb80993 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 16 Jul 2024 14:59:05 +1200 Subject: [PATCH 04/13] Convert algorithms to traitified styles --- src/compute/block.rs | 148 ++++++++++--------- src/compute/flexbox.rs | 221 +++++++++++++++------------- src/compute/grid/alignment.rs | 44 +++--- src/compute/grid/explicit_grid.rs | 13 +- src/compute/grid/implicit_grid.rs | 17 ++- src/compute/grid/mod.rs | 80 +++++----- src/compute/grid/placement.rs | 22 +-- src/compute/grid/types/grid_item.rs | 30 ++-- src/compute/leaf.rs | 39 +++-- src/compute/mod.rs | 37 ++--- src/style/grid.rs | 54 +++---- 11 files changed, 374 insertions(+), 331 deletions(-) diff --git a/src/compute/block.rs b/src/compute/block.rs index 8070dab04..8771b4ef3 100644 --- a/src/compute/block.rs +++ b/src/compute/block.rs @@ -1,6 +1,6 @@ //! Computes the CSS block layout algorithm in the case that the block container being laid out contains only block-level boxes use crate::geometry::{Line, Point, Rect, Size}; -use crate::style::{AvailableSpace, Display, LengthPercentageAuto, Overflow, Position}; +use crate::style::{AvailableSpace, CoreStyle, LengthPercentageAuto, Overflow, Position}; use crate::style_helpers::TaffyMaxContent; use crate::tree::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RunMode, SizingMode}; use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId}; @@ -9,7 +9,7 @@ use crate::util::sys::f32_max; use crate::util::sys::Vec; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; -use crate::BoxSizing; +use crate::{BoxGenerationMode, BoxSizing, LayoutBlockContainer}; #[cfg(feature = "content_size")] use super::common::content_size::compute_content_size_contribution; @@ -58,31 +58,35 @@ struct BlockItem { } /// Computes the layout of [`LayoutPartialTree`] according to the block layout algorithm -pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput { +pub fn compute_block_layout( + tree: &mut impl LayoutBlockContainer, + node_id: NodeId, + inputs: LayoutInput, +) -> LayoutOutput { let LayoutInput { known_dimensions, parent_size, run_mode, .. } = inputs; - let style = tree.get_style(node_id); + let style = tree.get_block_container_style(node_id); // Pull these out earlier to avoid borrowing issues - let aspect_ratio = style.aspect_ratio; - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); + let aspect_ratio = style.aspect_ratio(); + let padding = style.padding().resolve_or_zero(parent_size.width); + let border = style.border().resolve_or_zero(parent_size.width); let padding_border_size = (padding + border).sum_axes(); let box_sizing_adjustment = - if style.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; + if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; let min_size = style - .min_size + .min_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let max_size = style - .max_size + .max_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let clamped_style_size = if inputs.sizing_mode == SizingMode::InherentSize { style - .size + .size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment) @@ -91,6 +95,8 @@ pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId, Size::NONE }; + drop(style); + // If both min and max in a given axis are set and max <= min then this determines the size in that axis let min_max_definite_size = min_size.zip_map(max_size, |min, max| match (min, max) { (Some(min), Some(max)) if max <= min => Some(min), @@ -112,26 +118,26 @@ pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId, compute_inner(tree, node_id, LayoutInput { known_dimensions: styled_based_known_dimensions, ..inputs }) } -/// Computes the layout of [`LayoutPartialTree`] according to the block layout algorithm -fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput { +/// Computes the layout of [`LayoutBlockContainer`] according to the block layout algorithm +fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput { let LayoutInput { known_dimensions, parent_size, available_space, run_mode, vertical_margins_are_collapsible, .. } = inputs; - let style = tree.get_style(node_id); - let raw_padding = style.padding; - let raw_border = style.border; - let raw_margin = style.margin; - let aspect_ratio = style.aspect_ratio; - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); + let style = tree.get_block_container_style(node_id); + let raw_padding = style.padding(); + let raw_border = style.border(); + let raw_margin = style.margin(); + let aspect_ratio = style.aspect_ratio(); + let padding = raw_padding.resolve_or_zero(parent_size.width); + let border = raw_border.resolve_or_zero(parent_size.width); // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`. // However, the axis are switched (transposed) because a node that scrolls vertically needs // *horizontal* space to be reserved for a scrollbar let scrollbar_gutter = { - let offsets = style.overflow.transpose().map(|overflow| match overflow { - Overflow::Scroll => style.scrollbar_width, + let offsets = style.overflow().transpose().map(|overflow| match overflow { + Overflow::Scroll => style.scrollbar_width(), _ => 0.0, }); // TODO: make side configurable based on the `direction` property @@ -143,16 +149,16 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay let container_content_box_size = known_dimensions.maybe_sub(content_box_inset.sum_axes()); let box_sizing_adjustment = - if style.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; + if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; let size = - style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_add(box_sizing_adjustment); + style.size().maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_add(box_sizing_adjustment); let min_size = style - .min_size + .min_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let max_size = style - .max_size + .max_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); @@ -160,28 +166,30 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay // Determine margin collapsing behaviour let own_margins_collapse_with_children = Line { start: vertical_margins_are_collapsible.start - && !style.overflow.x.is_scroll_container() - && !style.overflow.y.is_scroll_container() - && style.position == Position::Relative + && !style.overflow().x.is_scroll_container() + && !style.overflow().y.is_scroll_container() + && style.position() == Position::Relative && padding.top == 0.0 && border.top == 0.0, end: vertical_margins_are_collapsible.end - && !style.overflow.x.is_scroll_container() - && !style.overflow.y.is_scroll_container() - && style.position == Position::Relative + && !style.overflow().x.is_scroll_container() + && !style.overflow().y.is_scroll_container() + && style.position() == Position::Relative && padding.bottom == 0.0 && border.bottom == 0.0 && size.height.is_none(), }; - let has_styles_preventing_being_collapsed_through = style.display != Display::Block - || style.overflow.x.is_scroll_container() - || style.overflow.y.is_scroll_container() - || style.position == Position::Absolute + let has_styles_preventing_being_collapsed_through = false//style.display != Display::Block + || style.overflow().x.is_scroll_container() + || style.overflow().y.is_scroll_container() + || style.position() == Position::Absolute || padding.top > 0.0 || padding.bottom > 0.0 || border.top > 0.0 || border.bottom > 0.0; + drop(style); + // 1. Generate items let mut items = generate_item_list(tree, node_id, container_content_box_size); @@ -233,7 +241,7 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay let len = tree.child_count(node_id); for order in 0..len { let child = tree.get_child_id(node_id, order); - if tree.get_style(child).display == Display::None { + if tree.get_block_child_style(child).box_generation_mode() == BoxGenerationMode::None { tree.set_unrounded_layout(child, &Layout::with_order(order as u32)); tree.perform_child_layout( child, @@ -279,48 +287,47 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay /// Create a `Vec` of `BlockItem` structs where each item in the `Vec` represents a child of the current node #[inline] fn generate_item_list( - tree: &impl LayoutPartialTree, + tree: &impl LayoutBlockContainer, node: NodeId, node_inner_size: Size>, ) -> Vec { tree.child_ids(node) - .map(|child_node_id| (child_node_id, tree.get_style(child_node_id))) - .filter(|(_, style)| style.display != Display::None) + .map(|child_node_id| (child_node_id, tree.get_block_child_style(child_node_id))) + .filter(|(_, style)| style.box_generation_mode() != BoxGenerationMode::None) .enumerate() .map(|(order, (child_node_id, child_style))| { - let aspect_ratio = child_style.aspect_ratio; - let padding = child_style.padding.resolve_or_zero(node_inner_size); - let border = child_style.border.resolve_or_zero(node_inner_size); + let aspect_ratio = child_style.aspect_ratio(); + let padding = child_style.padding().resolve_or_zero(node_inner_size); + let border = child_style.border().resolve_or_zero(node_inner_size); let pb_sum = (padding + border).sum_axes(); let box_sizing_adjustment = - if child_style.box_sizing == BoxSizing::ContentBox { pb_sum } else { Size::ZERO }; + if child_style.box_sizing() == BoxSizing::ContentBox { pb_sum } else { Size::ZERO }; BlockItem { node_id: child_node_id, order: order as u32, - size: child_style - .size + .size() .maybe_resolve(node_inner_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), min_size: child_style - .min_size + .min_size() .maybe_resolve(node_inner_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), max_size: child_style - .max_size + .max_size() .maybe_resolve(node_inner_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), - overflow: child_style.overflow, - scrollbar_width: child_style.scrollbar_width, - position: child_style.position, - inset: child_style.inset, - margin: child_style.margin, + overflow: child_style.overflow(), + scrollbar_width: child_style.scrollbar_width(), + position: child_style.position(), + inset: child_style.inset(), + margin: child_style.margin(), padding, border, - padding_border_sum: (padding + border).sum_axes(), + padding_border_sum: pb_sum, // Fields to be computed later (for now we initialise with dummy values) computed_size: Size::zero(), @@ -531,7 +538,7 @@ fn perform_final_layout_on_in_flow_children( /// Perform absolute layout on all absolutely positioned children. #[inline] fn perform_absolute_layout_on_absolute_children( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutBlockContainer, items: &[BlockItem], area_size: Size, area_offset: Point, @@ -543,47 +550,50 @@ fn perform_absolute_layout_on_absolute_children( let mut absolute_content_size = Size::ZERO; for item in items.iter().filter(|item| item.position == Position::Absolute) { - let child_style = tree.get_style(item.node_id); + let child_style = tree.get_block_child_style(item.node_id); // Skip items that are display:none or are not position:absolute - if child_style.display == Display::None || child_style.position != Position::Absolute { + if child_style.box_generation_mode() == BoxGenerationMode::None || child_style.position() != Position::Absolute + { continue; } - let aspect_ratio = child_style.aspect_ratio; - let margin = child_style.margin.map(|margin| margin.resolve_to_option(area_width)); - let padding = child_style.padding.resolve_or_zero(Some(area_width)); - let border = child_style.border.resolve_or_zero(Some(area_width)); + let aspect_ratio = child_style.aspect_ratio(); + let margin = child_style.margin().map(|margin| margin.resolve_to_option(area_width)); + let padding = child_style.padding().resolve_or_zero(Some(area_width)); + let border = child_style.border().resolve_or_zero(Some(area_width)); let padding_border_sum = (padding + border).sum_axes(); let box_sizing_adjustment = - if child_style.box_sizing == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; + if child_style.box_sizing() == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; // Resolve inset - let left = child_style.inset.left.maybe_resolve(area_width); - let right = child_style.inset.right.maybe_resolve(area_width); - let top = child_style.inset.top.maybe_resolve(area_height); - let bottom = child_style.inset.bottom.maybe_resolve(area_height); + let left = child_style.inset().left.maybe_resolve(area_width); + let right = child_style.inset().right.maybe_resolve(area_width); + let top = child_style.inset().top.maybe_resolve(area_height); + let bottom = child_style.inset().bottom.maybe_resolve(area_height); // Compute known dimensions from min/max/inherent size styles let style_size = child_style - .size + .size() .maybe_resolve(area_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let min_size = child_style - .min_size + .min_size() .maybe_resolve(area_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment) .or(padding_border_sum.map(Some)) .maybe_max(padding_border_sum); let max_size = child_style - .max_size + .max_size() .maybe_resolve(area_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let mut known_dimensions = style_size.maybe_clamp(min_size, max_size); + drop(child_style); + // Fill in width from left/right and reapply aspect ratio if: // - Width is not already known // - Item has both left and right inset properties set diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs index c814711f9..6eaf74178 100644 --- a/src/compute/flexbox.rs +++ b/src/compute/flexbox.rs @@ -2,18 +2,18 @@ use crate::compute::common::alignment::compute_alignment_offset; use crate::geometry::{Line, Point, Rect, Size}; use crate::style::{ - AlignContent, AlignItems, AlignSelf, AvailableSpace, Dimension, Display, FlexWrap, JustifyContent, - LengthPercentageAuto, Overflow, Position, + AlignContent, AlignItems, AlignSelf, AvailableSpace, Dimension, FlexWrap, JustifyContent, LengthPercentageAuto, + Overflow, Position, }; -use crate::style::{FlexDirection, Style}; +use crate::style::{CoreStyle, FlexDirection, FlexboxContainerStyle, FlexboxItemStyle}; use crate::style_helpers::{TaffyMaxContent, TaffyMinContent}; use crate::tree::{Layout, LayoutInput, LayoutOutput, RunMode, SizingMode}; -use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId}; +use crate::tree::{LayoutFlexboxContainer, LayoutPartialTreeExt, NodeId}; use crate::util::debug::debug_log; use crate::util::sys::{f32_max, new_vec_with_capacity, Vec}; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; -use crate::BoxSizing; +use crate::{BoxGenerationMode, BoxSizing}; use super::common::alignment::apply_alignment_fallback; #[cfg(feature = "content_size")] @@ -154,30 +154,35 @@ struct AlgoConstants { } /// Computes the layout of [`LayoutPartialTree`] according to the flexbox algorithm -pub fn compute_flexbox_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput { +pub fn compute_flexbox_layout( + tree: &mut impl LayoutFlexboxContainer, + node: NodeId, + inputs: LayoutInput, +) -> LayoutOutput { let LayoutInput { known_dimensions, parent_size, run_mode, .. } = inputs; - let style = tree.get_style(node); + let style = tree.get_flexbox_container_style(node); // Pull these out earlier to avoid borrowing issues - let aspect_ratio = style.aspect_ratio; - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); + let aspect_ratio = style.aspect_ratio(); + let padding = style.padding().resolve_or_zero(parent_size.width); + let border = style.border().resolve_or_zero(parent_size.width); let padding_border_sum = padding.sum_axes() + border.sum_axes(); - let box_sizing_adjustment = if style.box_sizing == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; + let box_sizing_adjustment = + if style.box_sizing() == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; let min_size = style - .min_size + .min_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let max_size = style - .max_size + .max_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let clamped_style_size = if inputs.sizing_mode == SizingMode::InherentSize { style - .size + .size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment) @@ -204,16 +209,18 @@ pub fn compute_flexbox_layout(tree: &mut impl LayoutPartialTree, node: NodeId, i } } - debug_log!("FLEX:", dbg:style.flex_direction); + debug_log!("FLEX:", dbg:style.flex_direction()); + drop(style); + compute_preliminary(tree, node, LayoutInput { known_dimensions: styled_based_known_dimensions, ..inputs }) } /// Compute a preliminary size for an item -fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput { +fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inputs: LayoutInput) -> LayoutOutput { let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs; // Define some general constants we will need for the remainder of the algorithm. - let mut constants = compute_constants(tree.get_style(node), known_dimensions, parent_size); + let mut constants = compute_constants(tree.get_flexbox_container_style(node), known_dimensions, parent_size); // 9. Flex Layout Algorithm @@ -269,9 +276,9 @@ fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: debug_log!("constants.node_inner_size", dbg:constants.node_inner_size); // Re-resolve percentage gaps - let style = tree.get_style(node); + let style = tree.get_flexbox_container_style(node); let inner_container_size = constants.inner_container_size.main(constants.dir); - let new_gap = style.gap.main(constants.dir).maybe_resolve(inner_container_size).unwrap_or(0.0); + let new_gap = style.gap().main(constants.dir).maybe_resolve(inner_container_size).unwrap_or(0.0); constants.gap.set_main(constants.dir, new_gap); } @@ -359,7 +366,7 @@ fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: let len = tree.child_count(node); for order in 0..len { let child = tree.get_child_id(node, order); - if tree.get_style(child).display == Display::None { + if tree.get_flexbox_child_style(child).box_generation_mode() == BoxGenerationMode::None { tree.set_unrounded_layout(child, &Layout::with_order(order as u32)); tree.perform_child_layout( child, @@ -398,32 +405,33 @@ fn compute_preliminary(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: /// Compute constants that can be reused during the flexbox algorithm. #[inline] fn compute_constants( - style: &Style, + style: impl FlexboxContainerStyle, known_dimensions: Size>, parent_size: Size>, ) -> AlgoConstants { - let dir = style.flex_direction; + let dir = style.flex_direction(); let is_row = dir.is_row(); let is_column = dir.is_column(); - let is_wrap = matches!(style.flex_wrap, FlexWrap::Wrap | FlexWrap::WrapReverse); - let is_wrap_reverse = style.flex_wrap == FlexWrap::WrapReverse; + let is_wrap = matches!(style.flex_wrap(), FlexWrap::Wrap | FlexWrap::WrapReverse); + let is_wrap_reverse = style.flex_wrap() == FlexWrap::WrapReverse; - let aspect_ratio = style.aspect_ratio; - let margin = style.margin.resolve_or_zero(parent_size.width); - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); + let aspect_ratio = style.aspect_ratio(); + let margin = style.margin().resolve_or_zero(parent_size.width); + let padding = style.padding().resolve_or_zero(parent_size.width); + let border = style.border().resolve_or_zero(parent_size.width); let padding_border_sum = padding.sum_axes() + border.sum_axes(); - let box_sizing_adjustment = if style.box_sizing == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; + let box_sizing_adjustment = + if style.box_sizing() == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; - let align_items = style.align_items.unwrap_or(AlignItems::Stretch); - let align_content = style.align_content.unwrap_or(AlignContent::Stretch); - let justify_content = style.justify_content; + let align_items = style.align_items().unwrap_or(AlignItems::Stretch); + let align_content = style.align_content().unwrap_or(AlignContent::Stretch); + let justify_content = style.justify_content(); // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`. // However, the axis are switched (transposed) because a node that scrolls vertically needs // *horizontal* space to be reserved for a scrollbar - let scrollbar_gutter = style.overflow.transpose().map(|overflow| match overflow { - Overflow::Scroll => style.scrollbar_width, + let scrollbar_gutter = style.overflow().transpose().map(|overflow| match overflow { + Overflow::Scroll => style.scrollbar_width(), _ => 0.0, }); // TODO: make side configurable based on the `direction` property @@ -433,7 +441,7 @@ fn compute_constants( let node_outer_size = known_dimensions; let node_inner_size = node_outer_size.maybe_sub(content_box_inset.sum_axes()); - let gap = style.gap.resolve_or_zero(node_inner_size.or(Size::zero())); + let gap = style.gap().resolve_or_zero(node_inner_size.or(Size::zero())); let container_size = Size::zero(); let inner_container_size = Size::zero(); @@ -445,12 +453,12 @@ fn compute_constants( is_wrap, is_wrap_reverse, min_size: style - .min_size + .min_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), max_size: style - .max_size + .max_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), @@ -476,51 +484,51 @@ fn compute_constants( /// - [**Generate anonymous flex items**](https://www.w3.org/TR/css-flexbox-1/#algo-anon-box) as described in [§4 Flex Items](https://www.w3.org/TR/css-flexbox-1/#flex-items). #[inline] fn generate_anonymous_flex_items( - tree: &impl LayoutPartialTree, + tree: &impl LayoutFlexboxContainer, node: NodeId, constants: &AlgoConstants, ) -> Vec { tree.child_ids(node) .enumerate() - .map(|(index, child)| (index, child, tree.get_style(child))) - .filter(|(_, _, style)| style.position != Position::Absolute) - .filter(|(_, _, style)| style.display != Display::None) + .map(|(index, child)| (index, child, tree.get_flexbox_child_style(child))) + .filter(|(_, _, style)| style.position() != Position::Absolute) + .filter(|(_, _, style)| style.box_generation_mode() != BoxGenerationMode::None) .map(|(index, child, child_style)| { - let aspect_ratio = child_style.aspect_ratio; - let padding = child_style.padding.resolve_or_zero(constants.node_inner_size.width); - let border = child_style.border.resolve_or_zero(constants.node_inner_size.width); + let aspect_ratio = child_style.aspect_ratio(); + let padding = child_style.padding().resolve_or_zero(constants.node_inner_size.width); + let border = child_style.border().resolve_or_zero(constants.node_inner_size.width); let pb_sum = (padding + border).sum_axes(); let box_sizing_adjustment = - if child_style.box_sizing == BoxSizing::ContentBox { pb_sum } else { Size::ZERO }; + if child_style.box_sizing() == BoxSizing::ContentBox { pb_sum } else { Size::ZERO }; FlexItem { node: child, order: index as u32, size: child_style - .size + .size() .maybe_resolve(constants.node_inner_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), min_size: child_style - .min_size + .min_size() .maybe_resolve(constants.node_inner_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), max_size: child_style - .max_size + .max_size() .maybe_resolve(constants.node_inner_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment), - inset: child_style.inset.zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s)), - margin: child_style.margin.resolve_or_zero(constants.node_inner_size.width), - margin_is_auto: child_style.margin.map(|m| m == LengthPercentageAuto::Auto), - padding: child_style.padding.resolve_or_zero(constants.node_inner_size.width), - border: child_style.border.resolve_or_zero(constants.node_inner_size.width), - align_self: child_style.align_self.unwrap_or(constants.align_items), - overflow: child_style.overflow, - scrollbar_width: child_style.scrollbar_width, - flex_grow: child_style.flex_grow, - flex_shrink: child_style.flex_shrink, + inset: child_style.inset().zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s)), + margin: child_style.margin().resolve_or_zero(constants.node_inner_size.width), + margin_is_auto: child_style.margin().map(|m| m == LengthPercentageAuto::Auto), + padding: child_style.padding().resolve_or_zero(constants.node_inner_size.width), + border: child_style.border().resolve_or_zero(constants.node_inner_size.width), + align_self: child_style.align_self().unwrap_or(constants.align_items), + overflow: child_style.overflow(), + scrollbar_width: child_style.scrollbar_width(), + flex_grow: child_style.flex_grow(), + flex_shrink: child_style.flex_shrink(), flex_basis: 0.0, inner_flex_basis: 0.0, violation: 0.0, @@ -608,7 +616,7 @@ fn determine_available_space( /// (For example, an item with a specified size of zero, positive padding, and box-sizing: border-box will have an outer flex base size of zero—and hence a negative inner flex base size.) #[inline] fn determine_flex_base_size( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutFlexboxContainer, constants: &AlgoConstants, available_space: Size, flex_items: &mut [FlexItem], @@ -616,7 +624,8 @@ fn determine_flex_base_size( let dir = constants.dir; for child in flex_items.iter_mut() { - let child_style = tree.get_style(child.node); + let child_style = tree.get_flexbox_child_style(child.node); + let flex_basis = child_style.flex_basis().maybe_resolve(constants.node_inner_size.main(dir)); // Parent size for child sizing let cross_axis_parent_size = constants.node_inner_size.cross(dir); @@ -643,6 +652,8 @@ fn determine_flex_base_size( ckd }; + drop(child_style); + child.flex_basis = 'flex_basis: { // A. If the item has a definite used flex basis, that’s the flex base size. @@ -655,15 +666,15 @@ fn determine_flex_base_size( // So B will just work here by using main_size without special handling for aspect_ratio let container_width = constants.node_inner_size.main(dir); - let box_sizing_adjustment = if child_style.box_sizing == BoxSizing::ContentBox { - let padding = child_style.padding.resolve_or_zero(container_width); - let border = child_style.border.resolve_or_zero(container_width); + let box_sizing_adjustment = if child_style.box_sizing() == BoxSizing::ContentBox { + let padding = child_style.padding().resolve_or_zero(container_width); + let border = child_style.border().resolve_or_zero(container_width); (padding + border).sum_axes() } else { Size::ZERO } .main(dir); - let flex_basis = child_style.flex_basis.maybe_resolve(container_width).maybe_add(box_sizing_adjustment); + let flex_basis = child_style.flex_basis().maybe_resolve(container_width).maybe_add(box_sizing_adjustment); let main_size = child.size.main(dir); if let Some(flex_basis) = flex_basis.or(main_size) { break 'flex_basis flex_basis; @@ -859,7 +870,7 @@ fn collect_flex_lines<'a>( /// Determine the container's main size (if not already known) fn determine_container_main_size( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutFlexboxContainer, available_space: Size, lines: &mut [FlexLine<'_>], constants: &mut AlgoConstants, @@ -1280,7 +1291,7 @@ fn resolve_flexible_lengths(line: &mut FlexLine, constants: &AlgoConstants, orig /// by performing layout with the used main size and the available space, treating auto as fit-content. #[inline] fn determine_hypothetical_cross_size( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutFlexboxContainer, line: &mut FlexLine, constants: &AlgoConstants, available_space: Size, @@ -1330,7 +1341,7 @@ fn determine_hypothetical_cross_size( /// Calculate the base lines of the children. #[inline] fn calculate_children_base_lines( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutFlexboxContainer, node_size: Size>, available_space: Size, flex_lines: &mut [FlexLine], @@ -1525,31 +1536,36 @@ fn handle_align_content_stretch(flex_lines: &mut [FlexLine], node_size: Size, @@ -1939,7 +1955,7 @@ fn calculate_layout_line( /// Do a final layout pass and collect the resulting layouts. #[inline] fn final_layout_pass( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutFlexboxContainer, flex_lines: &mut [FlexLine], constants: &AlgoConstants, ) -> Size { @@ -1984,7 +2000,7 @@ fn final_layout_pass( /// Perform absolute layout on all absolutely positioned children. #[inline] fn perform_absolute_layout_on_absolute_children( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutFlexboxContainer, node: NodeId, constants: &AlgoConstants, ) -> Size { @@ -1998,58 +2014,59 @@ fn perform_absolute_layout_on_absolute_children( for order in 0..tree.child_count(node) { let child = tree.get_child_id(node, order); - let child_style = tree.get_style(child); + let child_style = tree.get_flexbox_child_style(child); // Skip items that are display:none or are not position:absolute - if child_style.display == Display::None || child_style.position != Position::Absolute { + if child_style.box_generation_mode() == BoxGenerationMode::None || child_style.position() != Position::Absolute + { continue; } - let overflow = child_style.overflow; - let scrollbar_width = child_style.scrollbar_width; - let aspect_ratio = child_style.aspect_ratio; - let align_self = child_style.align_self.unwrap_or(constants.align_items); - let margin = child_style.margin.map(|margin| margin.resolve_to_option(container_width)); - let padding = child_style.padding.resolve_or_zero(Some(container_width)); - let border = child_style.border.resolve_or_zero(Some(container_width)); + let overflow = child_style.overflow(); + let scrollbar_width = child_style.scrollbar_width(); + let aspect_ratio = child_style.aspect_ratio(); + let align_self = child_style.align_self().unwrap_or(constants.align_items); + let margin = child_style.margin().map(|margin| margin.resolve_to_option(inset_relative_size.width)); + let padding = child_style.padding().resolve_or_zero(Some(inset_relative_size.width)); + let border = child_style.border().resolve_or_zero(Some(inset_relative_size.width)); let padding_border_sum = (padding + border).sum_axes(); let box_sizing_adjustment = if child_style.box_sizing == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; // Resolve inset // Insets are resolved against the container size minus border - let left = child_style.inset.left.maybe_resolve(inset_relative_size.width); - let right = - child_style.inset.right.maybe_resolve(inset_relative_size.width).maybe_add(constants.scrollbar_gutter.x); - let top = child_style.inset.top.maybe_resolve(inset_relative_size.height); - let bottom = - child_style.inset.bottom.maybe_resolve(inset_relative_size.height).maybe_add(constants.scrollbar_gutter.y); + let left = child_style.inset().left.maybe_resolve(inset_relative_size.width); + let right = child_style.inset().right.maybe_resolve(inset_relative_size.width); + let top = child_style.inset().top.maybe_resolve(inset_relative_size.height); + let bottom = child_style.inset().bottom.maybe_resolve(inset_relative_size.height); // Compute known dimensions from min/max/inherent size styles let style_size = child_style - .size + .size() .maybe_resolve(inset_relative_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let min_size = child_style - .min_size + .min_size() .maybe_resolve(inset_relative_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment) .or(padding_border_sum.map(Some)) .maybe_max(padding_border_sum); let max_size = child_style - .max_size + .max_size() .maybe_resolve(inset_relative_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let mut known_dimensions = style_size.maybe_clamp(min_size, max_size); + drop(child_style); + // Fill in width from left/right and reapply aspect ratio if: // - Width is not already known // - Item has both left and right inset properties set if let (None, Some(left), Some(right)) = (known_dimensions.width, left, right) { - let new_width_raw = container_width.maybe_sub(margin.left).maybe_sub(margin.right) - left - right; + let new_width_raw = inset_relative_size.width.maybe_sub(margin.left).maybe_sub(margin.right) - left - right; known_dimensions.width = Some(f32_max(new_width_raw, 0.0)); known_dimensions = known_dimensions.maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size); } @@ -2058,11 +2075,11 @@ fn perform_absolute_layout_on_absolute_children( // - Height is not already known // - Item has both top and bottom inset properties set if let (None, Some(top), Some(bottom)) = (known_dimensions.height, top, bottom) { - let new_height_raw = container_height.maybe_sub(margin.top).maybe_sub(margin.bottom) - top - bottom; + let new_height_raw = + inset_relative_size.height.maybe_sub(margin.top).maybe_sub(margin.bottom) - top - bottom; known_dimensions.height = Some(f32_max(new_height_raw, 0.0)); known_dimensions = known_dimensions.maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size); } - let layout_output = tree.perform_child_layout( child, known_dimensions, @@ -2125,6 +2142,7 @@ fn perform_absolute_layout_on_absolute_children( } else if let Some(end) = end_main { constants.container_size.main(constants.dir) - constants.border.main_end(constants.dir) + - constants.scrollbar_gutter.main(constants.dir) - final_size.main(constants.dir) - end - resolved_margin.main_end(constants.dir) @@ -2167,6 +2185,7 @@ fn perform_absolute_layout_on_absolute_children( } else if let Some(end) = end_cross { constants.container_size.cross(constants.dir) - constants.border.cross_end(constants.dir) + - constants.scrollbar_gutter.cross(constants.dir) - final_size.cross(constants.dir) - end - resolved_margin.cross_end(constants.dir) diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs index 3cec376d6..aeeed4424 100644 --- a/src/compute/grid/alignment.rs +++ b/src/compute/grid/alignment.rs @@ -2,14 +2,14 @@ use super::types::GridTrack; use crate::compute::common::alignment::{apply_alignment_fallback, compute_alignment_offset}; use crate::geometry::{InBothAbsAxis, Line, Point, Rect, Size}; -use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Overflow, Position}; -use crate::tree::{Layout, LayoutPartialTree, LayoutPartialTreeExt, NodeId, SizingMode}; +use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, CoreStyle, GridItemStyle, Overflow, Position}; +use crate::tree::{Layout, LayoutPartialTreeExt, NodeId, SizingMode}; use crate::util::sys::f32_max; use crate::util::{MaybeMath, MaybeResolve, ResolveOrZero}; #[cfg(feature = "content_size")] use crate::compute::common::content_size::compute_content_size_contribution; -use crate::BoxSizing; +use crate::{BoxSizing, LayoutGridContainer}; /// Align the grid tracks within the grid according to the align-content (rows) or /// justify-content (columns) property. This only does anything if the size of the @@ -57,7 +57,7 @@ pub(super) fn align_tracks( /// Align and size a grid item into it's final position pub(super) fn align_and_position_item( - tree: &mut impl LayoutPartialTree, + tree: &mut impl LayoutGridContainer, node: NodeId, order: u32, grid_area: Rect, @@ -66,36 +66,39 @@ pub(super) fn align_and_position_item( ) -> (Size, f32, f32) { let grid_area_size = Size { width: grid_area.right - grid_area.left, height: grid_area.bottom - grid_area.top }; - let style = tree.get_style(node); + let style = tree.get_grid_child_style(node); - let overflow = style.overflow; - let scrollbar_width = style.scrollbar_width; - let aspect_ratio = style.aspect_ratio; - let justify_self = style.justify_self; - let align_self = style.align_self; + let overflow = style.overflow(); + let scrollbar_width = style.scrollbar_width(); + let aspect_ratio = style.aspect_ratio(); + let justify_self = style.justify_self(); + let align_self = style.align_self(); - let position = style.position; - let inset_horizontal = style.inset.horizontal_components().map(|size| size.resolve_to_option(grid_area_size.width)); - let inset_vertical = style.inset.vertical_components().map(|size| size.resolve_to_option(grid_area_size.height)); - let padding = style.padding.map(|p| p.resolve_or_zero(Some(grid_area_size.width))); - let border = style.border.map(|p| p.resolve_or_zero(Some(grid_area_size.width))); + let position = style.position(); + let inset_horizontal = + style.inset().horizontal_components().map(|size| size.resolve_to_option(grid_area_size.width)); + let inset_vertical = style.inset().vertical_components().map(|size| size.resolve_to_option(grid_area_size.height)); + let padding = style.padding().map(|p| p.resolve_or_zero(Some(grid_area_size.width))); + let border = style.border().map(|p| p.resolve_or_zero(Some(grid_area_size.width))); let padding_border_size = (padding + border).sum_axes(); + let box_sizing_adjustment = - if style.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; + if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; + let inherent_size = style - .size + .size() .maybe_resolve(grid_area_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let min_size = style - .min_size + .min_size() .maybe_resolve(grid_area_size) .maybe_add(box_sizing_adjustment) .or(padding_border_size.map(Some)) .maybe_max(padding_border_size) .maybe_apply_aspect_ratio(aspect_ratio); let max_size = style - .max_size + .max_size() .maybe_resolve(grid_area_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); @@ -123,7 +126,7 @@ pub(super) fn align_and_position_item( // Note: This is not a bug. It is part of the CSS spec that both horizontal and vertical margins // resolve against the WIDTH of the grid area. - let margin = style.margin.map(|margin| margin.resolve_to_option(grid_area_size.width)); + let margin = style.margin().map(|margin| margin.resolve_to_option(grid_area_size.width)); let grid_area_minus_item_margins_size = Size { width: grid_area_size.width.maybe_sub(margin.left).maybe_sub(margin.right), @@ -187,6 +190,7 @@ pub(super) fn align_and_position_item( let Size { width, height } = Size { width, height }.maybe_clamp(min_size, max_size); // Layout node + drop(style); let layout_output = tree.perform_child_layout( node, Size { width, height }, diff --git a/src/compute/grid/explicit_grid.rs b/src/compute/grid/explicit_grid.rs index dbc450627..793aa2477 100644 --- a/src/compute/grid/explicit_grid.rs +++ b/src/compute/grid/explicit_grid.rs @@ -2,18 +2,19 @@ //! This mainly consists of evaluating GridAutoTracks use super::types::{GridTrack, TrackCounts}; use crate::geometry::{AbsoluteAxis, Size}; -use crate::style::{GridTrackRepetition, LengthPercentage, NonRepeatedTrackSizingFunction, Style, TrackSizingFunction}; +use crate::style::{GridTrackRepetition, LengthPercentage, NonRepeatedTrackSizingFunction, TrackSizingFunction}; use crate::style_helpers::TaffyAuto; -use crate::util::sys::{GridTrackVec, Vec}; +use crate::util::sys::Vec; use crate::util::MaybeMath; use crate::util::ResolveOrZero; +use crate::GridContainerStyle; #[cfg(not(feature = "std"))] use num_traits::float::FloatCore; /// Compute the number of rows and columns in the explicit grid pub(crate) fn compute_explicit_grid_size_in_axis( - style: &Style, + style: &impl GridContainerStyle, inner_container_size: Size>, axis: AbsoluteAxis, ) -> u16 { @@ -93,7 +94,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis( // - then the number of repetitions is the smallest possible positive integer that fulfills that minimum requirement // Otherwise, the specified track list repeats only once. let size_is_maximum = - style.size.get_abs(axis).into_option().is_some() || style.max_size.get_abs(axis).into_option().is_some(); + style.size().get_abs(axis).into_option().is_some() || style.max_size().get_abs(axis).into_option().is_some(); // Determine the number of repetitions let num_repetitions: u16 = match inner_container_size.get_abs(axis) { @@ -128,7 +129,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis( } }) .sum(); - let gap_size = style.gap.get_abs(axis).resolve_or_zero(Some(inner_container_size)); + let gap_size = style.gap().get_abs(axis).resolve_or_zero(Some(inner_container_size)); // Compute the amount of space that a single repetition of the repeated track list takes let per_repetition_track_used_space: f32 = repetition_definition @@ -176,7 +177,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis( pub(super) fn initialize_grid_tracks( tracks: &mut Vec, counts: TrackCounts, - track_template: &GridTrackVec, + track_template: &[TrackSizingFunction], auto_tracks: &[NonRepeatedTrackSizingFunction], gap: LengthPercentage, track_has_items: impl Fn(usize) -> bool, diff --git a/src/compute/grid/implicit_grid.rs b/src/compute/grid/implicit_grid.rs index 1836cbb5b..d1651218b 100644 --- a/src/compute/grid/implicit_grid.rs +++ b/src/compute/grid/implicit_grid.rs @@ -1,7 +1,8 @@ //! This module is not required for spec compliance, but is used as a performance optimisation //! to reduce the number of allocations required when creating a grid. use crate::geometry::Line; -use crate::style::{GenericGridPlacement, GridPlacement, Style}; +use crate::style::{GenericGridPlacement, GridPlacement}; +use crate::GridItemStyle; use core::cmp::{max, min}; use super::types::TrackCounts; @@ -15,10 +16,10 @@ use super::OriginZeroLine; /// in ways which are impossible to predict until the auto-placement algorithm is run. /// /// Note that this function internally mixes use of grid track numbers and grid line numbers -pub(crate) fn compute_grid_size_estimate<'a>( +pub(crate) fn compute_grid_size_estimate<'a, S: GridItemStyle + 'a>( explicit_col_count: u16, explicit_row_count: u16, - child_styles_iter: impl Iterator, + child_styles_iter: impl Iterator, ) -> (TrackCounts, TrackCounts) { // Iterate over children, producing an estimate of the min and max grid lines (in origin-zero coordinates where) // along with the span of each item @@ -60,20 +61,20 @@ pub(crate) fn compute_grid_size_estimate<'a>( /// /// Min and max grid lines are returned in origin-zero coordinates) /// The span is measured in tracks spanned -fn get_known_child_positions<'a>( - children_iter: impl Iterator, +fn get_known_child_positions<'a, S: GridItemStyle + 'a>( + children_iter: impl Iterator, explicit_col_count: u16, explicit_row_count: u16, ) -> (OriginZeroLine, OriginZeroLine, u16, OriginZeroLine, OriginZeroLine, u16) { let (mut col_min, mut col_max, mut col_max_span) = (OriginZeroLine(0), OriginZeroLine(0), 0); let (mut row_min, mut row_max, mut row_max_span) = (OriginZeroLine(0), OriginZeroLine(0), 0); - children_iter.for_each(|child_style: &Style| { + children_iter.for_each(|child_style| { // Note: that the children reference the lines in between (and around) the tracks not tracks themselves, // and thus we must subtract 1 to get an accurate estimate of the number of tracks let (child_col_min, child_col_max, child_col_span) = - child_min_line_max_line_span(child_style.grid_column, explicit_col_count); + child_min_line_max_line_span(child_style.grid_column(), explicit_col_count); let (child_row_min, child_row_max, child_row_span) = - child_min_line_max_line_span(child_style.grid_row, explicit_row_count); + child_min_line_max_line_span(child_style.grid_row(), explicit_row_count); col_min = min(col_min, child_col_min); col_max = max(col_max, child_col_max); col_max_span = max(col_max_span, child_col_span); diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs index 2fc02e5bf..f5a979576 100644 --- a/src/compute/grid/mod.rs +++ b/src/compute/grid/mod.rs @@ -2,14 +2,15 @@ //! use crate::geometry::{AbsoluteAxis, AbstractAxis, InBothAbsAxis}; use crate::geometry::{Line, Point, Rect, Size}; -use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Display, Overflow, Position}; -use crate::tree::{Layout, LayoutInput, LayoutOutput, RunMode, SizingMode}; -use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId}; +use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Overflow, Position}; +use crate::tree::{Layout, LayoutInput, LayoutOutput, LayoutPartialTreeExt, NodeId, RunMode, SizingMode}; use crate::util::debug::debug_log; use crate::util::sys::{f32_max, GridTrackVec, Vec}; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; -use crate::{style_helpers::*, BoxSizing}; +use crate::{ + style_helpers::*, BoxGenerationMode, BoxSizing, CoreStyle, GridContainerStyle, GridItemStyle, LayoutGridContainer, +}; use alignment::{align_and_position_item, align_tracks}; use explicit_grid::{compute_explicit_grid_size_in_axis, initialize_grid_tracks}; use implicit_grid::compute_grid_size_estimate; @@ -35,36 +36,36 @@ mod util; /// - Placing items (which also resolves the implicit grid) /// - Track (row/column) sizing /// - Alignment & Final item placement -pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inputs: LayoutInput) -> LayoutOutput { +pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, inputs: LayoutInput) -> LayoutOutput { let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs; - let style = tree.get_style(node).clone(); + let style = tree.get_grid_container_style(node).clone(); // 1. Compute "available grid space" // https://www.w3.org/TR/css-grid-1/#available-grid-space - let aspect_ratio = style.aspect_ratio; - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); + let aspect_ratio = style.aspect_ratio(); + let padding = style.padding().resolve_or_zero(parent_size.width); + let border = style.border().resolve_or_zero(parent_size.width); let padding_border = padding + border; let padding_border_size = padding_border.sum_axes(); let box_sizing_adjustment = - if style.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; + if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; let min_size = style - .min_size + .min_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let max_size = style - .max_size + .max_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let preferred_size = if inputs.sizing_mode == SizingMode::InherentSize { style - .size + .size() .maybe_resolve(parent_size) - .maybe_apply_aspect_ratio(style.aspect_ratio) + .maybe_apply_aspect_ratio(style.aspect_ratio()) .maybe_add(box_sizing_adjustment) } else { Size::NONE @@ -73,8 +74,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`. // However, the axis are switched (transposed) because a node that scrolls vertically needs // *horizontal* space to be reserved for a scrollbar - let scrollbar_gutter = style.overflow.transpose().map(|overflow| match overflow { - Overflow::Scroll => style.scrollbar_width, + let scrollbar_gutter = style.overflow().transpose().map(|overflow| match overflow { + Overflow::Scroll => style.scrollbar_width(), _ => 0.0, }); // TODO: make side configurable based on the `direction` property @@ -114,7 +115,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu return LayoutOutput::from_outer_size(Size { width, height }); } - let get_child_styles_iter = |node| tree.child_ids(node).map(|child_node: NodeId| tree.get_style(child_node)); + let get_child_styles_iter = + |node| tree.child_ids(node).map(|child_node: NodeId| tree.get_grid_child_style(child_node)); let child_styles_iter = get_child_styles_iter(node); // 2. Resolve the explicit grid @@ -147,16 +149,18 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu let in_flow_children_iter = || { tree.child_ids(node) .enumerate() - .map(|(index, child_node)| (index, child_node, tree.get_style(child_node))) - .filter(|(_, _, style)| style.display != Display::None && style.position != Position::Absolute) + .map(|(index, child_node)| (index, child_node, tree.get_grid_child_style(child_node))) + .filter(|(_, _, style)| { + style.box_generation_mode() != BoxGenerationMode::None && style.position() != Position::Absolute + }) }; place_grid_items( &mut cell_occupancy_matrix, &mut items, in_flow_children_iter, - style.grid_auto_flow, - style.align_items.unwrap_or(AlignItems::Stretch), - style.justify_items.unwrap_or(AlignItems::Stretch), + style.grid_auto_flow(), + style.align_items().unwrap_or(AlignItems::Stretch), + style.justify_items().unwrap_or(AlignItems::Stretch), ); // Extract track counts from previous step (auto-placement can expand the number of tracks) @@ -171,17 +175,17 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu initialize_grid_tracks( &mut columns, final_col_counts, - &style.grid_template_columns, - &style.grid_auto_columns, - style.gap.width, + style.grid_template_columns(), + style.grid_auto_columns(), + style.gap().width, |column_index| cell_occupancy_matrix.column_is_occupied(column_index), ); initialize_grid_tracks( &mut rows, final_row_counts, - &style.grid_template_rows, - &style.grid_auto_rows, - style.gap.height, + style.grid_template_rows(), + style.grid_auto_rows(), + style.gap().height, |row_index| cell_occupancy_matrix.row_is_occupied(row_index), ); @@ -420,7 +424,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu Line { start: padding.left, end: padding.right }, Line { start: border.left, end: border.right }, &mut columns, - style.justify_content.unwrap_or(AlignContent::Stretch), + style.justify_content().unwrap_or(AlignContent::Stretch), ); // Align rows align_tracks( @@ -428,7 +432,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu Line { start: padding.top, end: padding.bottom }, Line { start: border.top, end: border.bottom }, &mut rows, - style.align_content.unwrap_or(AlignContent::Stretch), + style.align_content().unwrap_or(AlignContent::Stretch), ); // 9. Size, Align, and Position Grid Items @@ -439,7 +443,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu // Sort items back into original order to allow them to be matched up with styles items.sort_by_key(|item| item.source_order); - let container_alignment_styles = InBothAbsAxis { horizontal: style.justify_items, vertical: style.align_items }; + let container_alignment_styles = InBothAbsAxis { horizontal: style.justify_items(), vertical: style.align_items() }; + drop(style); // Position in-flow children (stored in items vector) for (index, item) in items.iter_mut().enumerate() { @@ -471,10 +476,11 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu let mut order = items.len() as u32; (0..tree.child_count(node)).for_each(|index| { let child = tree.get_child_id(node, index); - let child_style = tree.get_style(child); + let child_style = tree.get_grid_child_style(child); // Position hidden child - if child_style.display == Display::None { + if child_style.box_generation_mode() == BoxGenerationMode::None { + drop(child_style); tree.set_unrounded_layout(child, &Layout::with_order(order)); tree.perform_child_layout( child, @@ -489,11 +495,11 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu } // Position absolutely positioned child - if child_style.position == Position::Absolute { + if child_style.position() == Position::Absolute { // Convert grid-col-{start/end} into Option's of indexes into the columns vector // The Option is None if the style property is Auto and an unresolvable Span let maybe_col_indexes = child_style - .grid_column + .grid_column() .into_origin_zero(final_col_counts.explicit) .resolve_absolutely_positioned_grid_tracks() .map(|maybe_grid_line| { @@ -502,7 +508,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu // Convert grid-row-{start/end} into Option's of indexes into the row vector // The Option is None if the style property is Auto and an unresolvable Span let maybe_row_indexes = child_style - .grid_row + .grid_row() .into_origin_zero(final_row_counts.explicit) .resolve_absolutely_positioned_grid_tracks() .map(|maybe_grid_line| { @@ -521,6 +527,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu .map(|index| columns[index].offset) .unwrap_or(container_border_box.width - border.right - scrollbar_gutter.x), }; + drop(child_style); + // TODO: Baseline alignment support for absolutely positioned items (should check if is actuallty specified) #[cfg_attr(not(feature = "content_size"), allow(unused_variables))] let (content_size_contribution, _, _) = diff --git a/src/compute/grid/placement.rs b/src/compute/grid/placement.rs index bd760accb..695ac0291 100644 --- a/src/compute/grid/placement.rs +++ b/src/compute/grid/placement.rs @@ -4,15 +4,16 @@ use super::types::{CellOccupancyMatrix, CellOccupancyState, GridItem}; use super::OriginZeroLine; use crate::geometry::Line; use crate::geometry::{AbsoluteAxis, InBothAbsAxis}; -use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement, Style}; +use crate::style::{AlignItems, GridAutoFlow, OriginZeroGridPlacement}; use crate::tree::NodeId; use crate::util::sys::Vec; +use crate::GridItemStyle; /// 8.5. Grid Item Placement Algorithm /// Place items into the grid, generating new rows/column into the implicit grid as required /// /// [Specification](https://www.w3.org/TR/css-grid-2/#auto-placement-algo) -pub(super) fn place_grid_items<'a, ChildIter>( +pub(super) fn place_grid_items<'a, S, ChildIter>( cell_occupancy_matrix: &mut CellOccupancyMatrix, items: &mut Vec, children_iter: impl Fn() -> ChildIter, @@ -20,7 +21,8 @@ pub(super) fn place_grid_items<'a, ChildIter>( align_items: AlignItems, justify_items: AlignItems, ) where - ChildIter: Iterator, + S: GridItemStyle + 'a, + ChildIter: Iterator, { let primary_axis = grid_auto_flow.primary_axis(); let secondary_axis = primary_axis.other_axis(); @@ -28,10 +30,12 @@ pub(super) fn place_grid_items<'a, ChildIter>( let map_child_style_to_origin_zero_placement = { let explicit_col_count = cell_occupancy_matrix.track_counts(AbsoluteAxis::Horizontal).explicit; let explicit_row_count = cell_occupancy_matrix.track_counts(AbsoluteAxis::Vertical).explicit; - move |(index, node, style): (usize, NodeId, &'a Style)| -> (_, _, _, &'a Style) { + move |(index, node, style): (usize, NodeId, S)| -> (_, _, _, S) { let origin_zero_placement = InBothAbsAxis { - horizontal: style.grid_column.map(|placement| placement.into_origin_zero_placement(explicit_col_count)), - vertical: style.grid_row.map(|placement| placement.into_origin_zero_placement(explicit_row_count)), + horizontal: style + .grid_column() + .map(|placement| placement.into_origin_zero_placement(explicit_col_count)), + vertical: style.grid_row().map(|placement| placement.into_origin_zero_placement(explicit_row_count)), }; (index, node, origin_zero_placement, style) } @@ -40,7 +44,7 @@ pub(super) fn place_grid_items<'a, ChildIter>( // 1. Place children with definite positions let mut idx = 0; children_iter() - .filter(|(_, _, child_style)| child_style.grid_row.is_definite() && child_style.grid_column.is_definite()) + .filter(|(_, _, child_style)| child_style.grid_row().is_definite() && child_style.grid_column().is_definite()) .map(map_child_style_to_origin_zero_placement) .for_each(|(index, child_node, child_placement, style)| { idx += 1; @@ -296,12 +300,12 @@ fn place_indefinitely_positioned_item( /// Record the grid item in both CellOccupancyMatric and the GridItems list /// once a definite placement has been determined #[allow(clippy::too_many_arguments)] -fn record_grid_placement( +fn record_grid_placement( cell_occupancy_matrix: &mut CellOccupancyMatrix, items: &mut Vec, node: NodeId, index: usize, - style: &Style, + style: S, parent_align_items: AlignItems, parent_justify_items: AlignItems, primary_axis: AbsoluteAxis, diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs index b77f7de02..3df863d82 100644 --- a/src/compute/grid/types/grid_item.rs +++ b/src/compute/grid/types/grid_item.rs @@ -5,11 +5,11 @@ use crate::geometry::AbstractAxis; use crate::geometry::{Line, Point, Rect, Size}; use crate::style::{ AlignItems, AlignSelf, AvailableSpace, Dimension, LengthPercentageAuto, MaxTrackSizingFunction, - MinTrackSizingFunction, Overflow, Style, + MinTrackSizingFunction, Overflow, }; use crate::tree::{LayoutPartialTree, LayoutPartialTreeExt, NodeId, SizingMode}; use crate::util::{MaybeMath, MaybeResolve, ResolveOrZero}; -use crate::{BoxSizing, LengthPercentage}; +use crate::{BoxSizing, GridItemStyle, LengthPercentage}; use core::ops::Range; /// Represents a single grid item @@ -93,11 +93,11 @@ pub(in super::super) struct GridItem { impl GridItem { /// Create a new item given a concrete placement in both axes - pub fn new_with_placement_style_and_order( + pub fn new_with_placement_style_and_order( node: NodeId, col_span: Line, row_span: Line, - style: &Style, + style: S, parent_align_items: AlignItems, parent_justify_items: AlignItems, source_order: u16, @@ -107,17 +107,17 @@ impl GridItem { source_order, row: row_span, column: col_span, - overflow: style.overflow, - box_sizing: style.box_sizing, - size: style.size, - min_size: style.min_size, - max_size: style.max_size, - aspect_ratio: style.aspect_ratio, - padding: style.padding, - border: style.border, - margin: style.margin, - align_self: style.align_self.unwrap_or(parent_align_items), - justify_self: style.justify_self.unwrap_or(parent_justify_items), + overflow: style.overflow(), + box_sizing: style.box_sizing(), + size: style.size(), + min_size: style.min_size(), + max_size: style.max_size(), + aspect_ratio: style.aspect_ratio(), + padding: style.padding(), + border: style.border(), + margin: style.margin(), + align_self: style.align_self().unwrap_or(parent_align_items), + justify_self: style.justify_self().unwrap_or(parent_justify_items), baseline: None, baseline_shim: 0.0, row_indexes: Line { start: 0, end: 0 }, // Properly initialised later diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs index 117d4284f..0c3f5a0af 100644 --- a/src/compute/leaf.rs +++ b/src/compute/leaf.rs @@ -1,20 +1,20 @@ //! Computes size using styles and measure functions use crate::geometry::{Point, Size}; -use crate::style::{AvailableSpace, Display, Overflow, Position, Style}; +use crate::style::{AvailableSpace, Overflow, Position}; use crate::tree::{CollapsibleMarginSet, RunMode}; use crate::tree::{LayoutInput, LayoutOutput, SizingMode}; use crate::util::debug::debug_log; use crate::util::sys::f32_max; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; -use crate::BoxSizing; +use crate::{BoxSizing, CoreStyle}; use core::unreachable; /// Compute the size of a leaf node (node with no children) pub fn compute_leaf_layout( inputs: LayoutInput, - style: &Style, + style: &impl CoreStyle, measure_function: MeasureFunction, ) -> LayoutOutput where @@ -24,12 +24,12 @@ where // Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width). // This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values) - let margin = style.margin.resolve_or_zero(parent_size.width); - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); + let margin = style.margin().resolve_or_zero(parent_size.width); + let padding = style.padding().resolve_or_zero(parent_size.width); + let border = style.border().resolve_or_zero(parent_size.width); let padding_border = padding + border; let pb_sum = padding_border.sum_axes(); - let box_sizing_adjustment = if style.box_sizing == BoxSizing::ContentBox { pb_sum } else { Size::ZERO }; + let box_sizing_adjustment = if style.box_sizing() == BoxSizing::ContentBox { pb_sum } else { Size::ZERO }; // Resolve node's preferred/min/max sizes (width/heights) against the available space (percentages resolve to pixel values) // For ContentSize mode, we pretend that the node has no size styles as these should be ignored. @@ -41,18 +41,18 @@ where (node_size, node_min_size, node_max_size, None) } SizingMode::InherentSize => { - let aspect_ratio = style.aspect_ratio; + let aspect_ratio = style.aspect_ratio(); let style_size = style - .size + .size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let style_min_size = style - .min_size + .min_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); - let style_max_size = style.max_size.maybe_resolve(parent_size).maybe_add(box_sizing_adjustment); + let style_max_size = style.max_size().maybe_resolve(parent_size).maybe_add(box_sizing_adjustment); let node_size = known_dimensions.or(style_size); (node_size, style_min_size, style_max_size, aspect_ratio) @@ -62,8 +62,8 @@ where // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`. // However, the axis are switched (transposed) because a node that scrolls vertically needs // *horizontal* space to be reserved for a scrollbar - let scrollbar_gutter = style.overflow.transpose().map(|overflow| match overflow { - Overflow::Scroll => style.scrollbar_width, + let scrollbar_gutter = style.overflow().transpose().map(|overflow| match overflow { + Overflow::Scroll => style.scrollbar_width(), _ => 0.0, }); // TODO: make side configurable based on the `direction` property @@ -71,15 +71,10 @@ where content_box_inset.right += scrollbar_gutter.x; content_box_inset.bottom += scrollbar_gutter.y; - #[cfg(feature = "block_layout")] - let is_block = style.display == Display::Block; - #[cfg(not(feature = "block_layout"))] - let is_block = false; - - let has_styles_preventing_being_collapsed_through = !is_block - || style.overflow.x.is_scroll_container() - || style.overflow.y.is_scroll_container() - || style.position == Position::Absolute + let has_styles_preventing_being_collapsed_through = !style.is_block() + || style.overflow().x.is_scroll_container() + || style.overflow().y.is_scroll_container() + || style.position() == Position::Absolute || padding.top > 0.0 || padding.bottom > 0.0 || border.top > 0.0 diff --git a/src/compute/mod.rs b/src/compute/mod.rs index 00d4a8cb9..8a23c051e 100644 --- a/src/compute/mod.rs +++ b/src/compute/mod.rs @@ -45,14 +45,14 @@ pub use self::flexbox::compute_flexbox_layout; pub use self::grid::compute_grid_layout; use crate::geometry::{Line, Point, Size}; -use crate::style::{AvailableSpace, Overflow}; +use crate::style::{AvailableSpace, CoreStyle, Overflow}; use crate::tree::{ Layout, LayoutInput, LayoutOutput, LayoutPartialTree, LayoutPartialTreeExt, NodeId, RoundTree, SizingMode, }; use crate::util::debug::{debug_log, debug_log_node, debug_pop_node, debug_push_node}; use crate::util::sys::round; use crate::util::ResolveOrZero; -use crate::{BoxSizing, Display, MaybeMath, MaybeResolve}; +use crate::{BoxSizing, MaybeMath, MaybeResolve}; /// Compute layout for the root node in the tree pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, available_space: Size) { @@ -61,30 +61,30 @@ pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, avai #[cfg(feature = "block_layout")] { let parent_size = available_space.into_options(); - let style = tree.get_style(root); + let style = tree.get_core_container_style(root); - if style.display == Display::Block { + if style.is_block() { // Pull these out earlier to avoid borrowing issues - let aspect_ratio = style.aspect_ratio; - let margin = style.margin.resolve_or_zero(parent_size.width); - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); + let aspect_ratio = style.aspect_ratio(); + let margin = style.margin().resolve_or_zero(parent_size.width); + let padding = style.padding().resolve_or_zero(parent_size.width); + let border = style.border().resolve_or_zero(parent_size.width); let padding_border_size = (padding + border).sum_axes(); let box_sizing_adjustment = - if style.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; + if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO }; let min_size = style - .min_size + .min_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let max_size = style - .max_size + .max_size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment); let clamped_style_size = style - .size + .size() .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) .maybe_add(box_sizing_adjustment) @@ -122,14 +122,15 @@ pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, avai Line::FALSE, ); - let style = tree.get_style(root); - let padding = style.padding.resolve_or_zero(available_space.width.into_option()); - let border = style.border.resolve_or_zero(available_space.width.into_option()); - let margin = style.margin.resolve_or_zero(available_space.width.into_option()); + let style = tree.get_core_container_style(root); + let padding = style.padding().resolve_or_zero(available_space.width.into_option()); + let border = style.border().resolve_or_zero(available_space.width.into_option()); + let margin = style.margin().resolve_or_zero(available_space.width.into_option()); let scrollbar_size = Size { - width: if style.overflow.y == Overflow::Scroll { style.scrollbar_width } else { 0.0 }, - height: if style.overflow.x == Overflow::Scroll { style.scrollbar_width } else { 0.0 }, + width: if style.overflow().y == Overflow::Scroll { style.scrollbar_width() } else { 0.0 }, + height: if style.overflow().x == Overflow::Scroll { style.scrollbar_width() } else { 0.0 }, }; + drop(style); tree.set_unrounded_layout( root, diff --git a/src/style/grid.rs b/src/style/grid.rs index 0394b763d..d2597e69c 100644 --- a/src/style/grid.rs +++ b/src/style/grid.rs @@ -63,6 +63,24 @@ pub trait GridContainerStyle: CoreStyle { fn justify_items(&self) -> Option { Style::DEFAULT.justify_items } + + /// Get a grid item's row or column placement depending on the axis passed + #[inline(always)] + fn grid_template_tracks(&self, axis: AbsoluteAxis) -> &[TrackSizingFunction] { + match axis { + AbsoluteAxis::Horizontal => self.grid_template_columns(), + AbsoluteAxis::Vertical => self.grid_template_rows(), + } + } + + /// Get a grid container's align-content or justify-content alignment depending on the axis passed + #[inline(always)] + fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent { + match axis { + AbstractAxis::Inline => self.justify_content().unwrap_or(AlignContent::Stretch), + AbstractAxis::Block => self.align_content().unwrap_or(AlignContent::Stretch), + } + } } /// The set of styles required for a CSS Grid item (child of a CSS Grid container) @@ -90,6 +108,15 @@ pub trait GridItemStyle: CoreStyle { fn justify_self(&self) -> Option { Style::DEFAULT.justify_self } + + /// Get a grid item's row or column placement depending on the axis passed + #[inline(always)] + fn grid_placement(&self, axis: AbsoluteAxis) -> Line { + match axis { + AbsoluteAxis::Horizontal => self.grid_column(), + AbsoluteAxis::Vertical => self.grid_row(), + } + } } /// Controls whether grid items are placed row-wise or column-wise. And whether the sparse or dense packing algorithm is used. @@ -684,30 +711,3 @@ impl From> for TrackSizin Self::Single(input) } } - -// Grid extensions to the Style struct -impl Style { - /// Get a grid item's row or column placement depending on the axis passed - pub(crate) fn grid_template_tracks(&self, axis: AbsoluteAxis) -> &GridTrackVec { - match axis { - AbsoluteAxis::Horizontal => &self.grid_template_columns, - AbsoluteAxis::Vertical => &self.grid_template_rows, - } - } - - /// Get a grid item's row or column placement depending on the axis passed - pub(crate) fn grid_placement(&self, axis: AbsoluteAxis) -> Line { - match axis { - AbsoluteAxis::Horizontal => self.grid_column, - AbsoluteAxis::Vertical => self.grid_row, - } - } - - /// Get a grid container's align-content or justify-content alignment depending on the axis passed - pub(crate) fn grid_align_content(&self, axis: AbstractAxis) -> AlignContent { - match axis { - AbstractAxis::Inline => self.justify_content.unwrap_or(AlignContent::Stretch), - AbstractAxis::Block => self.align_content.unwrap_or(AlignContent::Stretch), - } - } -} From 3f40ec47e0c0be44bfd89ebe3720d369c60b3966 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Wed, 17 Apr 2024 12:54:03 +1200 Subject: [PATCH 05/13] Remove style clone in grid algorithm --- src/compute/grid/mod.rs | 33 ++++++++++++++++++++------------- src/tree/taffy_tree.rs | 4 ++-- src/tree/traits.rs | 6 ++++-- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs index f5a979576..fa314de3a 100644 --- a/src/compute/grid/mod.rs +++ b/src/compute/grid/mod.rs @@ -2,14 +2,15 @@ //! use crate::geometry::{AbsoluteAxis, AbstractAxis, InBothAbsAxis}; use crate::geometry::{Line, Point, Rect, Size}; -use crate::style::{AlignContent, AlignItems, AlignSelf, AvailableSpace, Overflow, Position}; +use crate::style::{AlignItems, AlignSelf, AvailableSpace, Overflow, Position}; use crate::tree::{Layout, LayoutInput, LayoutOutput, LayoutPartialTreeExt, NodeId, RunMode, SizingMode}; use crate::util::debug::debug_log; use crate::util::sys::{f32_max, GridTrackVec, Vec}; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; use crate::{ - style_helpers::*, BoxGenerationMode, BoxSizing, CoreStyle, GridContainerStyle, GridItemStyle, LayoutGridContainer, + style_helpers::*, AlignContent, BoxGenerationMode, BoxSizing, CoreStyle, GridContainerStyle, GridItemStyle, + JustifyContent, LayoutGridContainer, }; use alignment::{align_and_position_item, align_tracks}; use explicit_grid::{compute_explicit_grid_size_in_axis, initialize_grid_tracks}; @@ -39,7 +40,7 @@ mod util; pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, inputs: LayoutInput) -> LayoutOutput { let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs; - let style = tree.get_grid_container_style(node).clone(); + let style = tree.get_grid_container_style(node); // 1. Compute "available grid space" // https://www.w3.org/TR/css-grid-1/#available-grid-space @@ -83,6 +84,13 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in content_box_inset.right += scrollbar_gutter.x; content_box_inset.bottom += scrollbar_gutter.y; + let align_content = style.align_content().unwrap_or(AlignContent::Stretch); + let justify_content = style.justify_content().unwrap_or(JustifyContent::Stretch); + let align_items = style.align_items(); + let justify_items = style.justify_items(); + + drop(style); + let constrained_available_space = known_dimensions .or(preferred_size) .map(|size| size.map(AvailableSpace::Definite)) @@ -159,8 +167,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in &mut items, in_flow_children_iter, style.grid_auto_flow(), - style.align_items().unwrap_or(AlignItems::Stretch), - style.justify_items().unwrap_or(AlignItems::Stretch), + align_items.unwrap_or(AlignItems::Stretch), + justify_items.unwrap_or(AlignItems::Stretch), ); // Extract track counts from previous step (auto-placement can expand the number of tracks) @@ -209,7 +217,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in AbstractAxis::Inline, min_size.get(AbstractAxis::Inline), max_size.get(AbstractAxis::Inline), - style.grid_align_content(AbstractAxis::Block), + align_content, available_grid_space, inner_node_size, &mut columns, @@ -229,7 +237,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in AbstractAxis::Block, min_size.get(AbstractAxis::Block), max_size.get(AbstractAxis::Block), - style.grid_align_content(AbstractAxis::Inline), + justify_content, available_grid_space, inner_node_size, &mut rows, @@ -342,7 +350,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in AbstractAxis::Inline, min_size.get(AbstractAxis::Inline), max_size.get(AbstractAxis::Inline), - style.grid_align_content(AbstractAxis::Block), + align_content, available_grid_space, inner_node_size, &mut columns, @@ -404,7 +412,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in AbstractAxis::Block, min_size.get(AbstractAxis::Block), max_size.get(AbstractAxis::Block), - style.grid_align_content(AbstractAxis::Inline), + justify_content, available_grid_space, inner_node_size, &mut rows, @@ -424,7 +432,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in Line { start: padding.left, end: padding.right }, Line { start: border.left, end: border.right }, &mut columns, - style.justify_content().unwrap_or(AlignContent::Stretch), + justify_content, ); // Align rows align_tracks( @@ -432,7 +440,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in Line { start: padding.top, end: padding.bottom }, Line { start: border.top, end: border.bottom }, &mut rows, - style.align_content().unwrap_or(AlignContent::Stretch), + align_content, ); // 9. Size, Align, and Position Grid Items @@ -443,8 +451,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in // Sort items back into original order to allow them to be matched up with styles items.sort_by_key(|item| item.source_order); - let container_alignment_styles = InBothAbsAxis { horizontal: style.justify_items(), vertical: style.align_items() }; - drop(style); + let container_alignment_styles = InBothAbsAxis { horizontal: justify_items, vertical: align_items }; // Position in-flow children (stored in items vector) for (index, item) in items.iter_mut().enumerate() { diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs index 48ccc2605..9f8f94e74 100644 --- a/src/tree/taffy_tree.rs +++ b/src/tree/taffy_tree.rs @@ -383,11 +383,11 @@ where MeasureFunction: FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, { - type ContainerStyle = Style; + type ContainerStyle<'a> = &'a Style where Self: 'a; type ItemStyle<'a> = &'a Style where Self: 'a; #[inline(always)] - fn get_grid_container_style(&self, node_id: NodeId) -> &Self::ContainerStyle { + fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { &self.taffy.nodes[node_id.into()].style } diff --git a/src/tree/traits.rs b/src/tree/traits.rs index 02324dbf9..f3e2be7ee 100644 --- a/src/tree/traits.rs +++ b/src/tree/traits.rs @@ -224,7 +224,9 @@ pub trait LayoutFlexboxContainer: LayoutPartialTree { /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout pub trait LayoutGridContainer: LayoutPartialTree { /// The style type representing the CSS Grid container's styles - type ContainerStyle: GridContainerStyle + Clone; + type ContainerStyle<'a>: GridContainerStyle + where + Self: 'a; /// The style type representing each CSS Grid item's styles type ItemStyle<'a>: GridItemStyle @@ -232,7 +234,7 @@ pub trait LayoutGridContainer: LayoutPartialTree { Self: 'a; /// Get the container's styles - fn get_grid_container_style(&self, node_id: NodeId) -> &Self::ContainerStyle; + fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>; /// Get the child's styles fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>; From 7fd3e48c1548de7ce23032678b18665c4cd461bc Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Mon, 8 Jul 2024 10:12:12 +1200 Subject: [PATCH 06/13] Fixup convert --- src/compute/flexbox.rs | 25 ++++++++++++------------- src/compute/grid/mod.rs | 4 ++-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs index 6eaf74178..358c76bf7 100644 --- a/src/compute/flexbox.rs +++ b/src/compute/flexbox.rs @@ -625,7 +625,6 @@ fn determine_flex_base_size( for child in flex_items.iter_mut() { let child_style = tree.get_flexbox_child_style(child.node); - let flex_basis = child_style.flex_basis().maybe_resolve(constants.node_inner_size.main(dir)); // Parent size for child sizing let cross_axis_parent_size = constants.node_inner_size.cross(dir); @@ -652,6 +651,17 @@ fn determine_flex_base_size( ckd }; + let container_width = constants.node_inner_size.main(dir); + let box_sizing_adjustment = if child_style.box_sizing() == BoxSizing::ContentBox { + let padding = child_style.padding().resolve_or_zero(container_width); + let border = child_style.border().resolve_or_zero(container_width); + (padding + border).sum_axes() + } else { + Size::ZERO + } + .main(dir); + let flex_basis = child_style.flex_basis().maybe_resolve(container_width).maybe_add(box_sizing_adjustment); + drop(child_style); child.flex_basis = 'flex_basis: { @@ -664,17 +674,6 @@ fn determine_flex_base_size( // Note: `child.size` has already been resolved against aspect_ratio in generate_anonymous_flex_items // So B will just work here by using main_size without special handling for aspect_ratio - - let container_width = constants.node_inner_size.main(dir); - let box_sizing_adjustment = if child_style.box_sizing() == BoxSizing::ContentBox { - let padding = child_style.padding().resolve_or_zero(container_width); - let border = child_style.border().resolve_or_zero(container_width); - (padding + border).sum_axes() - } else { - Size::ZERO - } - .main(dir); - let flex_basis = child_style.flex_basis().maybe_resolve(container_width).maybe_add(box_sizing_adjustment); let main_size = child.size.main(dir); if let Some(flex_basis) = flex_basis.or(main_size) { break 'flex_basis flex_basis; @@ -2031,7 +2030,7 @@ fn perform_absolute_layout_on_absolute_children( let border = child_style.border().resolve_or_zero(Some(inset_relative_size.width)); let padding_border_sum = (padding + border).sum_axes(); let box_sizing_adjustment = - if child_style.box_sizing == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; + if child_style.box_sizing() == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO }; // Resolve inset // Insets are resolved against the container size minus border diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs index fa314de3a..c15c98e7b 100644 --- a/src/compute/grid/mod.rs +++ b/src/compute/grid/mod.rs @@ -89,8 +89,6 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in let align_items = style.align_items(); let justify_items = style.justify_items(); - drop(style); - let constrained_available_space = known_dimensions .or(preferred_size) .map(|size| size.map(AvailableSpace::Definite)) @@ -197,6 +195,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in |row_index| cell_occupancy_matrix.row_is_occupied(row_index), ); + drop(style); + // 6. Track Sizing // Convert grid placements in origin-zero coordinates to indexes into the GridTrack (rows and columns) vectors From dd3007ce5b79645b8913e413b96ee4265b8f23f5 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 25 Jun 2024 13:53:19 +1200 Subject: [PATCH 07/13] Make CacheMut an associated type --- src/tree/taffy_tree.rs | 1 + src/tree/traits.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs index 9f8f94e74..c2a4e293a 100644 --- a/src/tree/taffy_tree.rs +++ b/src/tree/taffy_tree.rs @@ -273,6 +273,7 @@ where FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, { type CoreContainerStyle<'a> = &'a Style where Self : 'a; + type CacheMut<'b> = &'b mut Cache where Self : 'b; #[inline(always)] fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { diff --git a/src/tree/traits.rs b/src/tree/traits.rs index f3e2be7ee..984a6965d 100644 --- a/src/tree/traits.rs +++ b/src/tree/traits.rs @@ -133,6 +133,7 @@ use crate::style::{AvailableSpace, CoreStyle}; use crate::style::{FlexboxContainerStyle, FlexboxItemStyle}; #[cfg(feature = "grid")] use crate::style::{GridContainerStyle, GridItemStyle}; +use core::ops::{Deref, DerefMut}; /// This trait is Taffy's abstraction for downward tree traversal. /// However, this trait does *not* require access to any node's other than a single container node's immediate children unless you also intend to implement `TraverseTree`. @@ -167,6 +168,12 @@ pub trait LayoutPartialTree: TraversePartialTree { where Self: 'a; + /// A mutable reference to the cache. This is an associated type to allow for different + /// types of mutable reference such as mutex or refcell guards + type CacheMut<'b>: Deref + DerefMut + where + Self: 'b; + /// Get core style fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>; @@ -174,7 +181,7 @@ pub trait LayoutPartialTree: TraversePartialTree { fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout); /// Get a mutable reference to the [`Cache`] for this node. - fn get_cache_mut(&mut self, node_id: NodeId) -> &mut Cache; + fn get_cache_mut(&mut self, node_id: NodeId) -> Self::CacheMut<'_>; /// Compute the specified node's size or full layout given the specified constraints fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput; From 824a3fd742f3dcf6a97c84a360efbd1b7de6f884 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Fri, 12 Jul 2024 11:14:21 +1200 Subject: [PATCH 08/13] Update examples to use new traits --- examples/custom_tree_owned_partial.rs | 39 ++++++++++++++++++++++++++- examples/custom_tree_owned_unsafe.rs | 39 ++++++++++++++++++++++++++- examples/custom_tree_vec.rs | 39 ++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/examples/custom_tree_owned_partial.rs b/examples/custom_tree_owned_partial.rs index 79f693296..a94cd5faf 100644 --- a/examples/custom_tree_owned_partial.rs +++ b/examples/custom_tree_owned_partial.rs @@ -126,7 +126,12 @@ impl taffy::TraversePartialTree for Node { } impl taffy::LayoutPartialTree for Node { - fn get_style(&self, node_id: NodeId) -> &Style { + type CoreContainerStyle<'a> = &'a Style where + Self: 'a; + + type CacheMut<'b> = &'b mut Cache where Self: 'b; + + fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { &self.node_from_id(node_id).style } @@ -162,6 +167,38 @@ impl taffy::LayoutPartialTree for Node { } } +impl taffy::LayoutFlexboxContainer for Node { + type ContainerStyle<'a> = &'a Style where + Self: 'a; + + type ItemStyle<'a> = &'a Style where + Self: 'a; + + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + &self.node_from_id(node_id).style + } + + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + &self.node_from_id(child_node_id).style + } +} + +impl taffy::LayoutGridContainer for Node { + type ContainerStyle<'a> = &'a Style where + Self: 'a; + + type ItemStyle<'a> = &'a Style where + Self: 'a; + + fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + &self.node_from_id(node_id).style + } + + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + &self.node_from_id(child_node_id).style + } +} + fn main() -> Result<(), taffy::TaffyError> { let mut root = Node::new_column(Style::DEFAULT); diff --git a/examples/custom_tree_owned_unsafe.rs b/examples/custom_tree_owned_unsafe.rs index 96f31527f..15a748bd1 100644 --- a/examples/custom_tree_owned_unsafe.rs +++ b/examples/custom_tree_owned_unsafe.rs @@ -130,7 +130,12 @@ impl TraversePartialTree for StatelessLayoutTree { impl TraverseTree for StatelessLayoutTree {} impl LayoutPartialTree for StatelessLayoutTree { - fn get_style(&self, node_id: NodeId) -> &Style { + type CoreContainerStyle<'a> = &'a Style where + Self: 'a; + + type CacheMut<'b> = &'b mut Cache where Self: 'b; + + fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { unsafe { &node_from_id(node_id).style } } @@ -166,6 +171,38 @@ impl LayoutPartialTree for StatelessLayoutTree { } } +impl taffy::LayoutFlexboxContainer for StatelessLayoutTree { + type ContainerStyle<'a> = &'a Style where + Self: 'a; + + type ItemStyle<'a> = &'a Style where + Self: 'a; + + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + unsafe { &node_from_id(node_id).style } + } + + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + unsafe { &node_from_id(child_node_id).style } + } +} + +impl taffy::LayoutGridContainer for StatelessLayoutTree { + type ContainerStyle<'a> = &'a Style where + Self: 'a; + + type ItemStyle<'a> = &'a Style where + Self: 'a; + + fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + unsafe { &node_from_id(node_id).style } + } + + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + unsafe { &node_from_id(child_node_id).style } + } +} + impl RoundTree for StatelessLayoutTree { fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout { unsafe { &node_from_id_mut(node_id).unrounded_layout } diff --git a/examples/custom_tree_vec.rs b/examples/custom_tree_vec.rs index f3e86568a..0525295d5 100644 --- a/examples/custom_tree_vec.rs +++ b/examples/custom_tree_vec.rs @@ -139,7 +139,12 @@ impl taffy::TraversePartialTree for Tree { impl taffy::TraverseTree for Tree {} impl taffy::LayoutPartialTree for Tree { - fn get_style(&self, node_id: NodeId) -> &Style { + type CoreContainerStyle<'a> = &'a Style where + Self: 'a; + + type CacheMut<'b> = &'b mut Cache where Self: 'b; + + fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> { &self.node_from_id(node_id).style } @@ -175,6 +180,38 @@ impl taffy::LayoutPartialTree for Tree { } } +impl taffy::LayoutFlexboxContainer for Tree { + type ContainerStyle<'a> = &'a Style where + Self: 'a; + + type ItemStyle<'a> = &'a Style where + Self: 'a; + + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + &self.node_from_id(node_id).style + } + + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + &self.node_from_id(child_node_id).style + } +} + +impl taffy::LayoutGridContainer for Tree { + type ContainerStyle<'a> = &'a Style where + Self: 'a; + + type ItemStyle<'a> = &'a Style where + Self: 'a; + + fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + &self.node_from_id(node_id).style + } + + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + &self.node_from_id(child_node_id).style + } +} + impl taffy::RoundTree for Tree { fn get_unrounded_layout(&self, node_id: NodeId) -> &Layout { &self.node_from_id(node_id).unrounded_layout From 1bf8a0481480c55fc17f8d54e4b61a8e5e6b7ba6 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 16 Jul 2024 15:10:17 +1200 Subject: [PATCH 09/13] Fix --no-default-features --- src/tree/mod.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 481ede8fa..ccb5b625e 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -13,10 +13,16 @@ pub use cache::Cache; pub use layout::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RequestedAxis, RunMode, SizingMode}; pub use node::NodeId; pub(crate) use traits::LayoutPartialTreeExt; -pub use traits::{ - LayoutBlockContainer, LayoutFlexboxContainer, LayoutGridContainer, LayoutPartialTree, PrintTree, RoundTree, - TraversePartialTree, TraverseTree, -}; +pub use traits::{LayoutPartialTree, PrintTree, RoundTree, TraversePartialTree, TraverseTree}; + +#[cfg(feature = "flexbox")] +pub use traits::LayoutFlexboxContainer; + +#[cfg(feature = "grid")] +pub use traits::LayoutGridContainer; + +#[cfg(feature = "block_layout")] +pub use traits::LayoutBlockContainer; #[cfg(feature = "taffy_tree")] mod taffy_tree; From 7b5f60dca612a171f6b794aa0021c979786c9f92 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 16 Jul 2024 15:12:02 +1200 Subject: [PATCH 10/13] Fixup is_block --- src/compute/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compute/block.rs b/src/compute/block.rs index 8771b4ef3..7e0bc1aa5 100644 --- a/src/compute/block.rs +++ b/src/compute/block.rs @@ -179,7 +179,7 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs: && border.bottom == 0.0 && size.height.is_none(), }; - let has_styles_preventing_being_collapsed_through = false//style.display != Display::Block + let has_styles_preventing_being_collapsed_through = !style.is_block() || style.overflow().x.is_scroll_container() || style.overflow().y.is_scroll_container() || style.position() == Position::Absolute From a2f0f7b53311d23c36c3d71113fe90808958bd62 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 16 Jul 2024 15:12:41 +1200 Subject: [PATCH 11/13] Fix clippy lints --- src/style/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/style/mod.rs b/src/style/mod.rs index 681a3c5bd..d32924879 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -773,19 +773,19 @@ impl GridContainerStyle for Style { impl GridContainerStyle for &'_ T { #[inline(always)] fn grid_template_rows(&self) -> &[TrackSizingFunction] { - &(*self).grid_template_rows() + (*self).grid_template_rows() } #[inline(always)] fn grid_template_columns(&self) -> &[TrackSizingFunction] { - &(*self).grid_template_columns() + (*self).grid_template_columns() } #[inline(always)] fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] { - &(*self).grid_auto_rows() + (*self).grid_auto_rows() } #[inline(always)] fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] { - &(*self).grid_auto_columns() + (*self).grid_auto_columns() } #[inline(always)] fn grid_auto_flow(&self) -> GridAutoFlow { From 122c36af1512cdc18b3cc5429b474988f319f013 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 16 Jul 2024 15:22:21 +1200 Subject: [PATCH 12/13] Fix --no-default-features taffy_tree --- src/tree/taffy_tree.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs index c2a4e293a..975852401 100644 --- a/src/tree/taffy_tree.rs +++ b/src/tree/taffy_tree.rs @@ -14,16 +14,15 @@ use crate::tree::{ use crate::util::debug::{debug_log, debug_log_node}; use crate::util::sys::{new_vec_with_capacity, ChildrenVec, Vec}; -#[cfg(feature = "block_layout")] -use crate::compute::compute_block_layout; -#[cfg(feature = "flexbox")] -use crate::compute::compute_flexbox_layout; -#[cfg(feature = "grid")] -use crate::compute::compute_grid_layout; use crate::compute::{ compute_cached_layout, compute_hidden_layout, compute_leaf_layout, compute_root_layout, round_layout, }; -use crate::{LayoutBlockContainer, LayoutFlexboxContainer, LayoutGridContainer}; +#[cfg(feature = "block_layout")] +use crate::{compute::compute_block_layout, LayoutBlockContainer}; +#[cfg(feature = "flexbox")] +use crate::{compute::compute_flexbox_layout, LayoutFlexboxContainer}; +#[cfg(feature = "grid")] +use crate::{compute::compute_grid_layout, LayoutGridContainer}; /// The error Taffy generates on invalid operations pub type TaffyResult = Result; @@ -341,6 +340,7 @@ where } } +#[cfg(feature = "block_layout")] impl<'t, NodeContext, MeasureFunction> LayoutBlockContainer for TaffyView<'t, NodeContext, MeasureFunction> where MeasureFunction: @@ -360,6 +360,7 @@ where } } +#[cfg(feature = "flexbox")] impl<'t, NodeContext, MeasureFunction> LayoutFlexboxContainer for TaffyView<'t, NodeContext, MeasureFunction> where MeasureFunction: @@ -379,6 +380,7 @@ where } } +#[cfg(feature = "grid")] impl<'t, NodeContext, MeasureFunction> LayoutGridContainer for TaffyView<'t, NodeContext, MeasureFunction> where MeasureFunction: From b818fb85be71543f70cc3a6b9560155076d87971 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 16 Jul 2024 15:25:16 +1200 Subject: [PATCH 13/13] Give style trait associated types unique names --- examples/custom_tree_owned_partial.rs | 16 ++++++++-------- examples/custom_tree_owned_unsafe.rs | 16 ++++++++-------- examples/custom_tree_vec.rs | 16 ++++++++-------- src/tree/taffy_tree.rs | 24 ++++++++++++------------ src/tree/traits.rs | 24 ++++++++++++------------ 5 files changed, 48 insertions(+), 48 deletions(-) diff --git a/examples/custom_tree_owned_partial.rs b/examples/custom_tree_owned_partial.rs index a94cd5faf..f9fb37897 100644 --- a/examples/custom_tree_owned_partial.rs +++ b/examples/custom_tree_owned_partial.rs @@ -168,33 +168,33 @@ impl taffy::LayoutPartialTree for Node { } impl taffy::LayoutFlexboxContainer for Node { - type ContainerStyle<'a> = &'a Style where + type FlexboxContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where + type FlexboxItemStyle<'a> = &'a Style where Self: 'a; - fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> { &self.node_from_id(node_id).style } - fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> { &self.node_from_id(child_node_id).style } } impl taffy::LayoutGridContainer for Node { - type ContainerStyle<'a> = &'a Style where + type GridContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where + type GridItemStyle<'a> = &'a Style where Self: 'a; - fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> { &self.node_from_id(node_id).style } - fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> { &self.node_from_id(child_node_id).style } } diff --git a/examples/custom_tree_owned_unsafe.rs b/examples/custom_tree_owned_unsafe.rs index 15a748bd1..c6bf0d24e 100644 --- a/examples/custom_tree_owned_unsafe.rs +++ b/examples/custom_tree_owned_unsafe.rs @@ -172,33 +172,33 @@ impl LayoutPartialTree for StatelessLayoutTree { } impl taffy::LayoutFlexboxContainer for StatelessLayoutTree { - type ContainerStyle<'a> = &'a Style where + type FlexboxContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where + type FlexboxItemStyle<'a> = &'a Style where Self: 'a; - fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> { unsafe { &node_from_id(node_id).style } } - fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> { unsafe { &node_from_id(child_node_id).style } } } impl taffy::LayoutGridContainer for StatelessLayoutTree { - type ContainerStyle<'a> = &'a Style where + type GridContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where + type GridItemStyle<'a> = &'a Style where Self: 'a; - fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> { unsafe { &node_from_id(node_id).style } } - fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> { unsafe { &node_from_id(child_node_id).style } } } diff --git a/examples/custom_tree_vec.rs b/examples/custom_tree_vec.rs index 0525295d5..98ef83f7c 100644 --- a/examples/custom_tree_vec.rs +++ b/examples/custom_tree_vec.rs @@ -181,33 +181,33 @@ impl taffy::LayoutPartialTree for Tree { } impl taffy::LayoutFlexboxContainer for Tree { - type ContainerStyle<'a> = &'a Style where + type FlexboxContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where + type FlexboxItemStyle<'a> = &'a Style where Self: 'a; - fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> { &self.node_from_id(node_id).style } - fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> { &self.node_from_id(child_node_id).style } } impl taffy::LayoutGridContainer for Tree { - type ContainerStyle<'a> = &'a Style where + type GridContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where + type GridItemStyle<'a> = &'a Style where Self: 'a; - fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> { &self.node_from_id(node_id).style } - fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> { &self.node_from_id(child_node_id).style } } diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs index 975852401..788941fdf 100644 --- a/src/tree/taffy_tree.rs +++ b/src/tree/taffy_tree.rs @@ -346,16 +346,16 @@ where MeasureFunction: FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, { - type ContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where Self: 'a; + type BlockContainerStyle<'a> = &'a Style where Self: 'a; + type BlockItemStyle<'a> = &'a Style where Self: 'a; #[inline(always)] - fn get_block_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_> { self.get_core_container_style(node_id) } #[inline(always)] - fn get_block_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_> { self.get_core_container_style(child_node_id) } } @@ -366,16 +366,16 @@ where MeasureFunction: FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, { - type ContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where Self: 'a; + type FlexboxContainerStyle<'a> = &'a Style where Self: 'a; + type FlexboxItemStyle<'a> = &'a Style where Self: 'a; #[inline(always)] - fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> { &self.taffy.nodes[node_id.into()].style } #[inline(always)] - fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> { &self.taffy.nodes[child_node_id.into()].style } } @@ -386,16 +386,16 @@ where MeasureFunction: FnMut(Size>, Size, NodeId, Option<&mut NodeContext>, &Style) -> Size, { - type ContainerStyle<'a> = &'a Style where Self: 'a; - type ItemStyle<'a> = &'a Style where Self: 'a; + type GridContainerStyle<'a> = &'a Style where Self: 'a; + type GridItemStyle<'a> = &'a Style where Self: 'a; #[inline(always)] - fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_> { + fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> { &self.taffy.nodes[node_id.into()].style } #[inline(always)] - fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_> { + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> { &self.taffy.nodes[child_node_id.into()].style } } diff --git a/src/tree/traits.rs b/src/tree/traits.rs index 984a6965d..a549232ea 100644 --- a/src/tree/traits.rs +++ b/src/tree/traits.rs @@ -212,58 +212,58 @@ pub trait PrintTree: TraverseTree { /// Extends [`LayoutPartialTree`] with getters for the styles required for Flexbox layout pub trait LayoutFlexboxContainer: LayoutPartialTree { /// The style type representing the Flexbox container's styles - type ContainerStyle<'a>: FlexboxContainerStyle + type FlexboxContainerStyle<'a>: FlexboxContainerStyle where Self: 'a; /// The style type representing each Flexbox item's styles - type ItemStyle<'a>: FlexboxItemStyle + type FlexboxItemStyle<'a>: FlexboxItemStyle where Self: 'a; /// Get the container's styles - fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>; + fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_>; /// Get the child's styles - fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>; + fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_>; } #[cfg(feature = "grid")] /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Grid layout pub trait LayoutGridContainer: LayoutPartialTree { /// The style type representing the CSS Grid container's styles - type ContainerStyle<'a>: GridContainerStyle + type GridContainerStyle<'a>: GridContainerStyle where Self: 'a; /// The style type representing each CSS Grid item's styles - type ItemStyle<'a>: GridItemStyle + type GridItemStyle<'a>: GridItemStyle where Self: 'a; /// Get the container's styles - fn get_grid_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>; + fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_>; /// Get the child's styles - fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>; + fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_>; } #[cfg(feature = "block_layout")] /// Extends [`LayoutPartialTree`] with getters for the styles required for CSS Block layout pub trait LayoutBlockContainer: LayoutPartialTree { /// The style type representing the CSS Block container's styles - type ContainerStyle<'a>: CoreStyle + type BlockContainerStyle<'a>: CoreStyle where Self: 'a; /// The style type representing each CSS Block item's styles - type ItemStyle<'a>: CoreStyle + type BlockItemStyle<'a>: CoreStyle where Self: 'a; /// Get the container's styles - fn get_block_container_style(&self, node_id: NodeId) -> Self::ContainerStyle<'_>; + fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_>; /// Get the child's styles - fn get_block_child_style(&self, child_node_id: NodeId) -> Self::ItemStyle<'_>; + fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_>; } // --- PRIVATE TRAITS