Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass axis information when measuring a child's size #575

Merged
merged 1 commit into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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