diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs index 94e543574..b5a4e0e7d 100644 --- a/src/compute/flexbox.rs +++ b/src/compute/flexbox.rs @@ -638,16 +638,15 @@ fn determine_flex_base_size( ) .with_cross(dir, cross_axis_available_space); - break 'flex_basis tree - .measure_child_size( - child.node, - child_known_dimensions, - child_parent_size, - child_available_space, - SizingMode::ContentSize, - Line::FALSE, - ) - .main(dir); + break 'flex_basis tree.measure_child_size( + child.node, + child_known_dimensions, + child_parent_size, + child_available_space, + SizingMode::ContentSize, + dir.main_axis(), + Line::FALSE, + ); }; // Floor flex-basis by the padding_border_sum (floors inner_flex_basis at zero) @@ -686,7 +685,7 @@ fn determine_flex_base_size( child.min_size.or(child.overflow.map(Overflow::maybe_into_automatic_min_size).into()).main(dir); child.resolved_minimum_main_size = style_min_main_size.unwrap_or({ - let min_content_size = { + let min_content_main_size = { let child_available_space = Size::MIN_CONTENT.with_cross(dir, cross_axis_available_space); tree.measure_child_size( @@ -695,14 +694,16 @@ fn determine_flex_base_size( child_parent_size, child_available_space, SizingMode::ContentSize, + dir.main_axis(), Line::FALSE, ) }; // 4.5. Automatic Minimum Size of Flex Items // https://www.w3.org/TR/css-flexbox-1/#min-size-auto - let clamped_min_content_size = min_content_size.maybe_min(child.size).maybe_min(child.max_size); - clamped_min_content_size.maybe_max(padding_border_axes_sums).main(dir) + let clamped_min_content_size = + min_content_main_size.maybe_min(child.size.main(dir)).maybe_min(child.max_size.main(dir)); + clamped_min_content_size.maybe_max(padding_border_axes_sums.main(dir)) }); } } @@ -899,17 +900,15 @@ fn determine_container_main_size( // Either the min- or max- content size depending on which constraint we are sizing under. // TODO: Optimise by using already computed values where available - let content_main_size = tree - .measure_child_size( - item.node, - Size::NONE, - constants.node_inner_size, - child_available_space, - SizingMode::InherentSize, - Line::FALSE, - ) - .main(constants.dir) - + item.margin.main_axis_sum(constants.dir); + let content_main_size = tree.measure_child_size( + item.node, + Size::NONE, + constants.node_inner_size, + child_available_space, + SizingMode::InherentSize, + dir.main_axis(), + Line::FALSE, + ) + item.margin.main_axis_sum(constants.dir); // This is somewhat bizarre in that it's asymetrical depending whether the flex container is a column or a row. // @@ -1231,9 +1230,9 @@ fn determine_hypothetical_cross_size( height: if constants.is_row { child_available_cross } else { child_known_main }, }, SizingMode::ContentSize, + constants.dir.cross_axis(), Line::FALSE, ) - .cross(constants.dir) .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir)) .max(padding_border_sum) }); diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs index e80cd4c87..86c4a1284 100644 --- a/src/compute/grid/types/grid_item.rs +++ b/src/compute/grid/types/grid_item.rs @@ -347,9 +347,9 @@ impl GridItem { None => AvailableSpace::MinContent, }), SizingMode::InherentSize, + axis.as_abs_naive(), Line::FALSE, ) - .get(axis) } /// Retrieve the item's min content contribution from the cache or compute it using the provided parameters @@ -386,9 +386,9 @@ impl GridItem { None => AvailableSpace::MaxContent, }), SizingMode::InherentSize, + axis.as_abs_naive(), Line::FALSE, ) - .get(axis) } /// Retrieve the item's max content contribution from the cache or compute it using the provided parameters diff --git a/src/geometry.rs b/src/geometry.rs index 006a21491..8f781443f 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -61,12 +61,23 @@ pub enum AbstractAxis { impl AbstractAxis { /// Returns the other variant of the enum + #[inline] pub fn other(&self) -> AbstractAxis { match *self { AbstractAxis::Inline => AbstractAxis::Block, AbstractAxis::Block => AbstractAxis::Inline, } } + + /// Convert an `AbstractAxis` into an `AbsoluteAxis` naively assuming that the Inline axis is Horizontal + /// This is currently always true, but will change if Taffy ever implements the `writing_mode` property + #[inline] + pub fn as_abs_naive(&self) -> AbsoluteAxis { + match self { + AbstractAxis::Inline => AbsoluteAxis::Horizontal, + AbstractAxis::Block => AbsoluteAxis::Vertical, + } + } } /// Container that holds an item in each absolute axis without specifying diff --git a/src/style/flex.rs b/src/style/flex.rs index 8cce6d051..c24f488d8 100644 --- a/src/style/flex.rs +++ b/src/style/flex.rs @@ -1,5 +1,7 @@ //! Style types for Flexbox layout +use crate::geometry::AbsoluteAxis; + /// Controls whether flex items are forced onto one line or can wrap onto multiple lines. /// /// Defaults to [`FlexWrap::NoWrap`] @@ -78,6 +80,24 @@ impl FlexDirection { pub(crate) fn is_reverse(self) -> bool { matches!(self, Self::RowReverse | Self::ColumnReverse) } + + #[inline] + /// The `AbsoluteAxis` that corresponds to the main axis + pub(crate) fn main_axis(self) -> AbsoluteAxis { + match self { + Self::Row | Self::RowReverse => AbsoluteAxis::Horizontal, + Self::Column | Self::ColumnReverse => AbsoluteAxis::Vertical, + } + } + + #[inline] + /// The `AbsoluteAxis` that corresponds to the cross axis + pub(crate) fn cross_axis(self) -> AbsoluteAxis { + match self { + Self::Row | Self::RowReverse => AbsoluteAxis::Vertical, + Self::Column | Self::ColumnReverse => AbsoluteAxis::Horizontal, + } + } } #[cfg(test)] diff --git a/src/tree/layout.rs b/src/tree/layout.rs index 27bd43571..2c43128f4 100644 --- a/src/tree/layout.rs +++ b/src/tree/layout.rs @@ -1,5 +1,5 @@ //! Final data structures that represent the high-level UI layout -use crate::geometry::{Line, Point, Size}; +use crate::geometry::{AbsoluteAxis, Line, Point, Size}; use crate::prelude::TaffyMaxContent; use crate::style::AvailableSpace; use crate::util::sys::{f32_max, f32_min}; @@ -71,9 +71,46 @@ impl CollapsibleMarginSet { } } +/// An axis that layout algorithms can be requested to compute a size for +#[derive(Debug, Copy, Clone)] +pub enum RequestedAxis { + /// The horizontal axis + Horizontal, + /// The vertical axis + Vertical, + /// Both axes + Both, +} + +impl From for RequestedAxis { + fn from(value: AbsoluteAxis) -> Self { + match value { + AbsoluteAxis::Horizontal => RequestedAxis::Horizontal, + AbsoluteAxis::Vertical => RequestedAxis::Vertical, + } + } +} +impl TryFrom for AbsoluteAxis { + type Error = (); + fn try_from(value: RequestedAxis) -> Result { + match value { + RequestedAxis::Horizontal => Ok(AbsoluteAxis::Horizontal), + RequestedAxis::Vertical => Ok(AbsoluteAxis::Vertical), + RequestedAxis::Both => Err(()), + } + } +} + /// A struct containing the inputs constraints/hints for laying out a node, which are passed in by the parent #[derive(Debug, Copy, Clone)] pub struct LayoutInput { + /// Whether we only need to know the Node's size, or whe + pub run_mode: RunMode, + /// Whether a Node's style sizes should be taken into account or ignored + pub sizing_mode: SizingMode, + /// Which axis we need the size of + pub axis: RequestedAxis, + /// Known dimensions represent dimensions (width/height) which should be taken as fixed when performing layout. /// For example, if known_dimensions.width is set to Some(WIDTH) then this means something like: /// @@ -89,10 +126,6 @@ pub struct LayoutInput { /// Available space represents an amount of space to layout into, and is used as a soft constraint /// for the purpose of wrapping. pub available_space: Size, - /// Whether a Node's style sizes should be taken into account or ignored - pub sizing_mode: SizingMode, - /// Whether we only need to know the Node's size, or whe - pub run_mode: RunMode, /// Specific to CSS Block layout. Used for correctly computing margin collapsing. You probably want to set this to `Line::FALSE`. pub vertical_margins_are_collapsible: Line, } @@ -107,6 +140,7 @@ impl LayoutInput { parent_size: Size::NONE, available_space: Size::MAX_CONTENT, sizing_mode: SizingMode::InherentSize, + axis: RequestedAxis::Both, vertical_margins_are_collapsible: Line::FALSE, }; } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index fb9fee7c5..d89ab1a23 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1,6 +1,6 @@ //! Contains both [a high-level interface to Taffy](crate::Taffy) using a ready-made node tree, and [a trait for defining a custom node trees](crate::tree::LayoutTree) / utility types to help with that. -use crate::geometry::{Line, Size}; +use crate::geometry::{AbsoluteAxis, Line, Size}; use crate::style::{AvailableSpace, Style}; // Submodules @@ -15,7 +15,7 @@ mod taffy_tree; #[cfg(feature = "taffy_tree")] pub use taffy_tree::{Taffy, TaffyError, TaffyResult}; mod layout; -pub use layout::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RunMode, SizingMode}; +pub use layout::{CollapsibleMarginSet, Layout, LayoutInput, LayoutOutput, RequestedAxis, RunMode, SizingMode}; /// This if the core abstraction in Taffy. Any type that *correctly* implements `PartialLayoutTree` can be laid out using Taffy's algorithms. /// @@ -64,6 +64,7 @@ pub trait LayoutTree: PartialLayoutTree { pub(crate) trait PartialLayoutTreeExt: PartialLayoutTree { /// Compute the size of the node given the specified constraints #[inline(always)] + #[allow(clippy::too_many_arguments)] fn measure_child_size( &mut self, node_id: NodeId, @@ -71,8 +72,9 @@ pub(crate) trait PartialLayoutTreeExt: PartialLayoutTree { parent_size: Size>, available_space: Size, sizing_mode: SizingMode, + axis: AbsoluteAxis, vertical_margins_are_collapsible: Line, - ) -> Size { + ) -> f32 { self.compute_child_layout( node_id, LayoutInput { @@ -80,11 +82,13 @@ pub(crate) trait PartialLayoutTreeExt: PartialLayoutTree { parent_size, available_space, sizing_mode, + axis: axis.into(), run_mode: RunMode::ComputeSize, vertical_margins_are_collapsible, }, ) .size + .get_abs(axis) } /// Perform a full layout on the node given the specified constraints @@ -105,6 +109,7 @@ pub(crate) trait PartialLayoutTreeExt: PartialLayoutTree { parent_size, available_space, sizing_mode, + axis: RequestedAxis::Both, run_mode: RunMode::PerformLayout, vertical_margins_are_collapsible, },