Skip to content

Commit

Permalink
Pass axis information when measuring a child's size (#575)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoburns authored Nov 2, 2023
1 parent 278f5e3 commit 6d7f3cf
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 35 deletions.
49 changes: 24 additions & 25 deletions src/compute/flexbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand All @@ -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))
});
}
}
Expand Down Expand Up @@ -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.
//
Expand Down Expand Up @@ -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)
});
Expand Down
4 changes: 2 additions & 2 deletions src/compute/grid/types/grid_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions src/style/flex.rs
Original file line number Diff line number Diff line change
@@ -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`]
Expand Down Expand Up @@ -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)]
Expand Down
44 changes: 39 additions & 5 deletions src/tree/layout.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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<AbsoluteAxis> for RequestedAxis {
fn from(value: AbsoluteAxis) -> Self {
match value {
AbsoluteAxis::Horizontal => RequestedAxis::Horizontal,
AbsoluteAxis::Vertical => RequestedAxis::Vertical,
}
}
}
impl TryFrom<RequestedAxis> for AbsoluteAxis {
type Error = ();
fn try_from(value: RequestedAxis) -> Result<Self, Self::Error> {
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:
///
Expand All @@ -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<AvailableSpace>,
/// 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<bool>,
}
Expand All @@ -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,
};
}
Expand Down
11 changes: 8 additions & 3 deletions src/tree/mod.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.
///
Expand Down Expand Up @@ -64,27 +64,31 @@ 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,
known_dimensions: Size<Option<f32>>,
parent_size: Size<Option<f32>>,
available_space: Size<AvailableSpace>,
sizing_mode: SizingMode,
axis: AbsoluteAxis,
vertical_margins_are_collapsible: Line<bool>,
) -> Size<f32> {
) -> f32 {
self.compute_child_layout(
node_id,
LayoutInput {
known_dimensions,
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
Expand All @@ -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,
},
Expand Down

0 comments on commit 6d7f3cf

Please sign in to comment.