"Traitify" the `Style` struct (#568)
* Create style traits
* Add algorithm-specific PartialLayoutTree traits
* Taffy tree changes
* Convert algorithms to traitified styles
* Remove style clone in grid algorithm
* Fixup convert
* Make CacheMut an associated type
* Update examples to use new traits
* Fix --no-default-features
* Fixup is_block
* Fix clippy lints
* Fix --no-default-features taffy_tree
* Give style trait associated types unique names
f953fcbebbb7a0a3c158e538190ea88b252354fe · por Nico Burns · (hace 2 años) · padre 6fb38bfe0 · ver el árbol en este commit
Delta semántico · 210
examples/custom_tree_owned_partial.rs
examples/custom_tree_owned_unsafe.rs
examples/custom_tree_vec.rs
src/compute/grid/alignment.rs
src/compute/grid/explicit_grid.rs
src/compute/grid/implicit_grid.rs
src/compute/grid/placement.rs
src/compute/grid/types/grid_item.rs
diff --git a/examples/custom_tree_owned_partial.rs b/examples/custom_tree_owned_partial.rs
index 79f693296..f9fb37897 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 FlexboxContainerStyle<'a> = &'a Style where
+ Self: 'a;
+
+ type FlexboxItemStyle<'a> = &'a Style where
+ Self: 'a;
+
+ 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::FlexboxItemStyle<'_> {
+ &self.node_from_id(child_node_id).style
+ }
+}
+
+impl taffy::LayoutGridContainer for Node {
+ type GridContainerStyle<'a> = &'a Style where
+ Self: 'a;
+
+ type GridItemStyle<'a> = &'a Style where
+ Self: 'a;
+
+ 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::GridItemStyle<'_> {
+ &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..c6bf0d24e 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 FlexboxContainerStyle<'a> = &'a Style where
+ Self: 'a;
+
+ type FlexboxItemStyle<'a> = &'a Style where
+ Self: 'a;
+
+ 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::FlexboxItemStyle<'_> {
+ unsafe { &node_from_id(child_node_id).style }
+ }
+}
+
+impl taffy::LayoutGridContainer for StatelessLayoutTree {
+ type GridContainerStyle<'a> = &'a Style where
+ Self: 'a;
+
+ type GridItemStyle<'a> = &'a Style where
+ Self: 'a;
+
+ 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::GridItemStyle<'_> {
+ 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..98ef83f7c 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 FlexboxContainerStyle<'a> = &'a Style where
+ Self: 'a;
+
+ type FlexboxItemStyle<'a> = &'a Style where
+ Self: 'a;
+
+ 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::FlexboxItemStyle<'_> {
+ &self.node_from_id(child_node_id).style
+ }
+}
+
+impl taffy::LayoutGridContainer for Tree {
+ type GridContainerStyle<'a> = &'a Style where
+ Self: 'a;
+
+ type GridItemStyle<'a> = &'a Style where
+ Self: 'a;
+
+ 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::GridItemStyle<'_> {
+ &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
diff --git a/src/compute/block.rs b/src/compute/block.rs
index 8070dab04..7e0bc1aa5 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 = !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
|| 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<Option<f32>>,
) -> Vec<BlockItem> {
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<f32>,
area_offset: Point<f32>,
@@ -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..358c76bf7 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<Option<f32>>,
parent_size: Size<Option<f32>>,
) -> 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<FlexItem> {
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<AvailableSpace>,
flex_items: &mut [FlexItem],
@@ -616,7 +624,7 @@ 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);
// Parent size for child sizing
let cross_axis_parent_size = constants.node_inner_size.cross(dir);
@@ -643,6 +651,19 @@ 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: {
// A. If the item has a definite used flex basis, that’s the flex base size.
@@ -653,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;
@@ -859,7 +869,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<AvailableSpace>,
lines: &mut [FlexLine<'_>],
constants: &mut AlgoConstants,
@@ -1280,7 +1290,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<AvailableSpace>,
@@ -1330,7 +1340,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<Option<f32>>,
available_space: Size<AvailableSpace>,
flex_lines: &mut [FlexLine],
@@ -1525,31 +1535,36 @@ fn handle_align_content_stretch(flex_lines: &mut [FlexLine], node_size: Size<Opt
///
/// **Note that this step does not affect the main size of the flex item, even if it has an intrinsic aspect ratio**.
#[inline]
-fn determine_used_cross_size(tree: &impl LayoutPartialTree, flex_lines: &mut [FlexLine], constants: &AlgoConstants) {
+fn determine_used_cross_size(
+ tree: &impl LayoutFlexboxContainer,
+ flex_lines: &mut [FlexLine],
+ constants: &AlgoConstants,
+) {
for line in flex_lines {
let line_cross_size = line.cross_size;
for child in line.items.iter_mut() {
- let child_style = tree.get_style(child.node);
+ let child_style = tree.get_flexbox_child_style(child.node);
child.target_size.set_cross(
constants.dir,
if child.align_self == AlignSelf::Stretch
&& !child.margin_is_auto.cross_start(constants.dir)
&& !child.margin_is_auto.cross_end(constants.dir)
- && child_style.size.cross(constants.dir) == Dimension::Auto
+ && child_style.size().cross(constants.dir) == Dimension::Auto
{
// For some reason this particular usage of max_width is an exception to the rule that max_width's transfer
// using the aspect_ratio (if set). Both Chrome and Firefox agree on this. And reading the spec, it seems like
// a reasonable interpretation. Although it seems to me that the spec *should* apply aspect_ratio here.
-
- let padding = child_style.padding.resolve_or_zero(constants.node_inner_size);
- let border = child_style.border.resolve_or_zero(constants.node_inner_size);
+ let padding = child_style.padding().resolve_or_zero(constants.node_inner_size);
+ let border = child_style.border().resolve_or_zero(constants.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 };
- let max_size_ignoring_aspect_ratio =
- child_style.max_size.maybe_resolve(constants.node_inner_size).maybe_add(box_sizing_adjustment);
+ let max_size_ignoring_aspect_ratio = child_style
+ .max_size()
+ .maybe_resolve(constants.node_inner_size)
+ .maybe_add(box_sizing_adjustment);
(line_cross_size - child.margin.cross_axis_sum(constants.dir)).maybe_clamp(
child.min_size.cross(constants.dir),
@@ -1807,7 +1822,7 @@ fn align_flex_lines_per_align_content(flex_lines: &mut [FlexLine], constants: &A
/// Calculates the layout for a flex-item
#[allow(clippy::too_many_arguments)]
fn calculate_flex_item(
- tree: &mut impl LayoutPartialTree,
+ tree: &mut impl LayoutFlexboxContainer,
item: &mut FlexItem,
total_offset_main: &mut f32,
total_offset_cross: f32,
@@ -1889,7 +1904,7 @@ fn calculate_flex_item(
/// Calculates the layout line
#[allow(clippy::too_many_arguments)]
fn calculate_layout_line(
- tree: &mut impl LayoutPartialTree,
+ tree: &mut impl LayoutFlexboxContainer,
line: &mut FlexLine,
total_offset_cross: &mut f32,
#[cfg(feature = "content_size")] content_size: &mut Size<f32>,
@@ -1939,7 +1954,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<f32> {
@@ -1984,7 +1999,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<f32> {
@@ -1998,58 +2013,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 };
+ 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 +2074,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 +2141,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 +2184,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<f32>,
@@ -66,36 +66,39 @@ pub(super) fn align_and_position_item(
) -> (Size<f32>, 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<Option<f32>>,
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<GridTrack>,
counts: TrackCounts,
- track_template: &GridTrackVec<TrackSizingFunction>,
+ 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<Item = &'a Style>,
+ child_styles_iter: impl Iterator<Item = S>,
) -> (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<Item = &'a Style>,
+fn get_known_child_positions<'a, S: GridItemStyle + 'a>(
+ children_iter: impl Iterator<Item = S>,
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..c15c98e7b 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -2,14 +2,16 @@
//! <https://www.w3.org/TR/css-grid-1>
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::{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::*, 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};
use implicit_grid::compute_grid_size_estimate;
@@ -35,36 +37,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);
// 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 +75,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
@@ -82,6 +84,11 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
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();
+
let constrained_available_space = known_dimensions
.or(preferred_size)
.map(|size| size.map(AvailableSpace::Definite))
@@ -114,7 +121,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 +155,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(),
+ 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)
@@ -171,20 +181,22 @@ 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),
);
+ drop(style);
+
// 6. Track Sizing
// Convert grid placements in origin-zero coordinates to indexes into the GridTrack (rows and columns) vectors
@@ -205,7 +217,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
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,
@@ -225,7 +237,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
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,
@@ -338,7 +350,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
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,
@@ -400,7 +412,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutPartialTree, node: NodeId, inpu
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,
@@ -420,7 +432,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),
+ justify_content,
);
// Align rows
align_tracks(
@@ -428,7 +440,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),
+ align_content,
);
// 9. Size, Align, and Position Grid Items
@@ -439,7 +451,7 @@ 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: justify_items, vertical: align_items };
// Position in-flow children (stored in items vector)
for (index, item) in items.iter_mut().enumerate() {
@@ -471,10 +483,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 +502,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 +515,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 +534,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<GridItem>,
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<Item = (usize, NodeId, &'a Style)>,
+ S: GridItemStyle + 'a,
+ ChildIter: Iterator<Item = (usize, NodeId, S)>,
{
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<S: GridItemStyle>(
cell_occupancy_matrix: &mut CellOccupancyMatrix,
items: &mut Vec<GridItem>,
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<S: GridItemStyle>(
node: NodeId,
col_span: Line<OriginZeroLine>,
row_span: Line<OriginZeroLine>,
- 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<MeasureFunction>(
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<AvailableSpace>) {
@@ -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/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<LengthPercentage> {
+ 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<AlignContent> {
+ Style::DEFAULT.align_content
+ }
+ /// How this node's children aligned in the cross/block axis?
+ #[inline(always)]
+ fn align_items(&self) -> Option<AlignItems> {
+ Style::DEFAULT.align_items
+ }
+ /// How this node's children should be aligned in the inline axis
+ #[inline(always)]
+ fn justify_content(&self) -> Option<JustifyContent> {
+ 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<AlignSelf> {
+ Style::DEFAULT.align_self
+ }
+}
use crate::geometry::AbsoluteAxis;
diff --git a/src/style/grid.rs b/src/style/grid.rs
index b2d2b04b4..d2597e69c 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -1,13 +1,124 @@
//! 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<LengthPercentage> {
+ 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<AlignContent> {
+ Style::DEFAULT.align_content
+ }
+ /// How should contained within this item be aligned in the main/inline axis
+ #[inline(always)]
+ fn justify_content(&self) -> Option<JustifyContent> {
+ Style::DEFAULT.justify_content
+ }
+ /// How this node's children aligned in the cross/block axis?
+ #[inline(always)]
+ fn align_items(&self) -> Option<AlignItems> {
+ Style::DEFAULT.align_items
+ }
+ /// How this node's children should be aligned in the inline axis
+ #[inline(always)]
+ fn justify_items(&self) -> Option<AlignItems> {
+ 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)
+pub trait GridItemStyle: CoreStyle {
+ /// Defines which row in the grid the item should start and end at
+ #[inline(always)]
+ fn grid_row(&self) -> Line<GridPlacement> {
+ Style::DEFAULT.grid_row
+ }
+ /// Defines which column in the grid the item should start and end at
+ #[inline(always)]
+ fn grid_column(&self) -> Line<GridPlacement> {
+ 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<AlignSelf> {
+ 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<AlignSelf> {
+ 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<GridPlacement> {
+ 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.
///
/// 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.
@@ -600,30 +711,3 @@ impl From<MinMax<MinTrackSizingFunction, MaxTrackSizingFunction>> 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<TrackSizingFunction> {
- 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<GridPlacement> {
- 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),
- }
- }
-}
diff --git a/src/style/mod.rs b/src/style/mod.rs
index 31f4419b0..d32924879 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<Overflow> {
+ Style::DEFAULT.overflow
+ }
+ /// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
+ #[inline(always)]
+ fn scrollbar_width(&self) -> f32 {
+ 0.0
+ }
+
+ // Position properties
+ /// What should the `position` value of this struct use as a base offset?
+ #[inline(always)]
+ fn position(&self) -> Position {
+ Style::DEFAULT.position
+ }
+ /// How should the position of this element be tweaked relative to the layout defined?
+ #[inline(always)]
+ fn inset(&self) -> Rect<LengthPercentageAuto> {
+ Style::DEFAULT.inset
+ }
+
+ // Size properies
+ /// Sets the initial size of the item
+ #[inline(always)]
+ fn size(&self) -> Size<Dimension> {
+ Style::DEFAULT.size
+ }
+ /// Controls the minimum size of the item
+ #[inline(always)]
+ fn min_size(&self) -> Size<Dimension> {
+ Style::DEFAULT.min_size
+ }
+ /// Controls the maximum size of the item
+ #[inline(always)]
+ fn max_size(&self) -> Size<Dimension> {
+ Style::DEFAULT.max_size
+ }
+ /// Sets the preferred aspect ratio for the item
+ /// The ratio is calculated as width divided by height.
+ #[inline(always)]
+ fn aspect_ratio(&self) -> Option<f32> {
+ Style::DEFAULT.aspect_ratio
+ }
+
+ // Spacing Properties
+ /// How large should the margin be on each side?
+ #[inline(always)]
+ fn margin(&self) -> Rect<LengthPercentageAuto> {
+ Style::DEFAULT.margin
+ }
+ /// How large should the padding be on each side?
+ #[inline(always)]
+ fn padding(&self) -> Rect<LengthPercentage> {
+ Style::DEFAULT.padding
+ }
+ /// How large should the border be on each side?
+ #[inline(always)]
+ fn border(&self) -> Rect<LengthPercentage> {
+ Style::DEFAULT.border
+ }
+}
+
/// Sets the layout used for the children of this node
///
/// The default values depends on on which feature flags are enabled. The order of precedence is: Flex, Grid, Block, None.
@@ -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: <https://www.w3.org/TR/css-display-3/#box-generation>
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BoxGenerationMode {
+ /// The node generates a box in the regular way
+ Normal,
+ /// The node and it's descendants generate no boxes (they are hidden)
+ None,
+}
+
+impl BoxGenerationMode {
+ /// The default of BoxGenerationMode
+ pub const DEFAULT: BoxGenerationMode = BoxGenerationMode::Normal;
+}
+
+impl Default for BoxGenerationMode {
fn default() -> Self {
Self::DEFAULT
}
@@ -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<TrackSizingFunction>,
- /// 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<TrackSizingFunction>,
/// 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<Overflow> {
+ self.overflow
+ }
+ #[inline(always)]
+ fn scrollbar_width(&self) -> f32 {
+ self.scrollbar_width
+ }
+ #[inline(always)]
+ fn position(&self) -> Position {
+ self.position
+ }
+ #[inline(always)]
+ fn inset(&self) -> Rect<LengthPercentageAuto> {
+ self.inset
+ }
+ #[inline(always)]
+ fn size(&self) -> Size<Dimension> {
+ self.size
+ }
+ #[inline(always)]
+ fn min_size(&self) -> Size<Dimension> {
+ self.min_size
+ }
+ #[inline(always)]
+ fn max_size(&self) -> Size<Dimension> {
+ self.max_size
+ }
+ #[inline(always)]
+ fn aspect_ratio(&self) -> Option<f32> {
+ self.aspect_ratio
+ }
+ #[inline(always)]
+ fn margin(&self) -> Rect<LengthPercentageAuto> {
+ self.margin
+ }
+ #[inline(always)]
+ fn padding(&self) -> Rect<LengthPercentage> {
+ self.padding
+ }
+ #[inline(always)]
+ fn border(&self) -> Rect<LengthPercentage> {
+ self.border
+ }
+}
+
+impl<T: CoreStyle> CoreStyle for &'_ T {
+ #[inline(always)]
+ fn box_generation_mode(&self) -> BoxGenerationMode {
+ (*self).box_generation_mode()
+ }
+ #[inline(always)]
+ fn is_block(&self) -> bool {
+ (*self).is_block()
+ }
+ #[inline(always)]
+ fn box_sizing(&self) -> BoxSizing {
+ (*self).box_sizing()
+ }
+ #[inline(always)]
+ fn overflow(&self) -> Point<Overflow> {
+ (*self).overflow()
+ }
+ #[inline(always)]
+ fn scrollbar_width(&self) -> f32 {
+ (*self).scrollbar_width()
+ }
+ #[inline(always)]
+ fn position(&self) -> Position {
+ (*self).position()
+ }
+ #[inline(always)]
+ fn inset(&self) -> Rect<LengthPercentageAuto> {
+ (*self).inset()
+ }
+ #[inline(always)]
+ fn size(&self) -> Size<Dimension> {
+ (*self).size()
+ }
+ #[inline(always)]
+ fn min_size(&self) -> Size<Dimension> {
+ (*self).min_size()
+ }
+ #[inline(always)]
+ fn max_size(&self) -> Size<Dimension> {
+ (*self).max_size()
+ }
+ #[inline(always)]
+ fn aspect_ratio(&self) -> Option<f32> {
+ (*self).aspect_ratio()
+ }
+ #[inline(always)]
+ fn margin(&self) -> Rect<LengthPercentageAuto> {
+ (*self).margin()
+ }
+ #[inline(always)]
+ fn padding(&self) -> Rect<LengthPercentage> {
+ (*self).padding()
+ }
+ #[inline(always)]
+ fn border(&self) -> Rect<LengthPercentage> {
+ (*self).border()
+ }
+}
+
+#[cfg(feature = "flexbox")]
+impl FlexboxContainerStyle for &Style {
+ #[inline(always)]
+ fn flex_direction(&self) -> FlexDirection {
+ self.flex_direction
+ }
+ #[inline(always)]
+ fn flex_wrap(&self) -> FlexWrap {
+ self.flex_wrap
+ }
+ #[inline(always)]
+ fn gap(&self) -> Size<LengthPercentage> {
+ self.gap
+ }
+ #[inline(always)]
+ fn align_content(&self) -> Option<AlignContent> {
+ self.align_content
+ }
+ #[inline(always)]
+ fn align_items(&self) -> Option<AlignItems> {
+ self.align_items
+ }
+ #[inline(always)]
+ fn justify_content(&self) -> Option<JustifyContent> {
+ self.justify_content
+ }
+}
+
+#[cfg(feature = "flexbox")]
+impl<T: FlexboxContainerStyle> FlexboxContainerStyle for &'_ T {
+ #[inline(always)]
+ fn flex_direction(&self) -> FlexDirection {
+ (*self).flex_direction()
+ }
+ #[inline(always)]
+ fn flex_wrap(&self) -> FlexWrap {
+ (*self).flex_wrap()
+ }
+ #[inline(always)]
+ fn gap(&self) -> Size<LengthPercentage> {
+ (*self).gap()
+ }
+ #[inline(always)]
+ fn align_content(&self) -> Option<AlignContent> {
+ (*self).align_content()
+ }
+ #[inline(always)]
+ fn align_items(&self) -> Option<AlignItems> {
+ (*self).align_items()
+ }
+ #[inline(always)]
+ fn justify_content(&self) -> Option<JustifyContent> {
+ (*self).justify_content()
+ }
+}
+
+#[cfg(feature = "flexbox")]
+impl FlexboxItemStyle for Style {
+ #[inline(always)]
+ fn flex_basis(&self) -> Dimension {
+ self.flex_basis
+ }
+ #[inline(always)]
+ fn flex_grow(&self) -> f32 {
+ self.flex_grow
+ }
+ #[inline(always)]
+ fn flex_shrink(&self) -> f32 {
+ self.flex_shrink
+ }
+ #[inline(always)]
+ fn align_self(&self) -> Option<AlignSelf> {
+ self.align_self
+ }
+}
+
+#[cfg(feature = "flexbox")]
+impl<T: FlexboxItemStyle> FlexboxItemStyle for &'_ T {
+ #[inline(always)]
+ fn flex_basis(&self) -> Dimension {
+ (*self).flex_basis()
+ }
+ #[inline(always)]
+ fn flex_grow(&self) -> f32 {
+ (*self).flex_grow()
+ }
+ #[inline(always)]
+ fn flex_shrink(&self) -> f32 {
+ (*self).flex_shrink()
+ }
+ #[inline(always)]
+ fn align_self(&self) -> Option<AlignSelf> {
+ (*self).align_self()
+ }
+}
+
+#[cfg(feature = "grid")]
+impl GridContainerStyle for Style {
+ #[inline(always)]
+ fn grid_template_rows(&self) -> &[TrackSizingFunction] {
+ &self.grid_template_rows
+ }
+ #[inline(always)]
+ fn grid_template_columns(&self) -> &[TrackSizingFunction] {
+ &self.grid_template_columns
+ }
+ #[inline(always)]
+ fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] {
+ &self.grid_auto_rows
+ }
+ #[inline(always)]
+ fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] {
+ &self.grid_auto_columns
+ }
+ #[inline(always)]
+ fn grid_auto_flow(&self) -> GridAutoFlow {
+ self.grid_auto_flow
+ }
+ #[inline(always)]
+ fn gap(&self) -> Size<LengthPercentage> {
+ self.gap
+ }
+ #[inline(always)]
+ fn align_content(&self) -> Option<AlignContent> {
+ self.align_content
+ }
+ #[inline(always)]
+ fn justify_content(&self) -> Option<JustifyContent> {
+ self.justify_content
+ }
+ #[inline(always)]
+ fn align_items(&self) -> Option<AlignItems> {
+ self.align_items
+ }
+ #[inline(always)]
+ fn justify_items(&self) -> Option<AlignItems> {
+ self.justify_items
+ }
+}
+
+#[cfg(feature = "grid")]
+impl<T: GridContainerStyle> GridContainerStyle for &'_ T {
+ #[inline(always)]
+ fn grid_template_rows(&self) -> &[TrackSizingFunction] {
+ (*self).grid_template_rows()
+ }
+ #[inline(always)]
+ fn grid_template_columns(&self) -> &[TrackSizingFunction] {
+ (*self).grid_template_columns()
+ }
+ #[inline(always)]
+ fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] {
+ (*self).grid_auto_rows()
+ }
+ #[inline(always)]
+ fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] {
+ (*self).grid_auto_columns()
+ }
+ #[inline(always)]
+ fn grid_auto_flow(&self) -> GridAutoFlow {
+ (*self).grid_auto_flow()
+ }
+ #[inline(always)]
+ fn gap(&self) -> Size<LengthPercentage> {
+ (*self).gap()
+ }
+ #[inline(always)]
+ fn align_content(&self) -> Option<AlignContent> {
+ (*self).align_content()
+ }
+ #[inline(always)]
+ fn justify_content(&self) -> Option<JustifyContent> {
+ (*self).justify_content()
+ }
+ #[inline(always)]
+ fn align_items(&self) -> Option<AlignItems> {
+ (*self).align_items()
+ }
+ #[inline(always)]
+ fn justify_items(&self) -> Option<AlignItems> {
+ (*self).justify_items()
+ }
+}
+
+#[cfg(feature = "grid")]
+impl GridItemStyle for &'_ Style {
+ #[inline(always)]
+ fn grid_row(&self) -> Line<GridPlacement> {
+ self.grid_row
+ }
+ #[inline(always)]
+ fn grid_column(&self) -> Line<GridPlacement> {
+ self.grid_column
+ }
+ #[inline(always)]
+ fn align_self(&self) -> Option<AlignSelf> {
+ self.align_self
+ }
+ #[inline(always)]
+ fn justify_self(&self) -> Option<AlignSelf> {
+ self.justify_self
+ }
+}
+
+#[cfg(feature = "grid")]
+impl<T: GridItemStyle> GridItemStyle for &'_ T {
+ #[inline(always)]
+ fn grid_row(&self) -> Line<GridPlacement> {
+ (*self).grid_row()
+ }
+ #[inline(always)]
+ fn grid_column(&self) -> Line<GridPlacement> {
+ (*self).grid_column()
+ }
+ #[inline(always)]
+ fn align_self(&self) -> Option<AlignSelf> {
+ (*self).align_self()
+ }
+ #[inline(always)]
+ fn justify_self(&self) -> Option<AlignSelf> {
+ (*self).justify_self()
+ }
+}
+
#[cfg(test)]
mod tests {
use super::Style;
diff --git a/src/tree/mod.rs b/src/tree/mod.rs
index 7a8961f3a..ccb5b625e 100644
--- a/src/tree/mod.rs
+++ b/src/tree/mod.rs
@@ -15,6 +15,15 @@ pub use node::NodeId;
pub(crate) use traits::LayoutPartialTreeExt;
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;
#[cfg(feature = "taffy_tree")]
diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs
index 7ec8deea5..788941fdf 100644
--- a/src/tree/taffy_tree.rs
+++ b/src/tree/taffy_tree.rs
@@ -14,15 +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,
};
+#[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<T> = Result<T, TaffyError>;
@@ -271,9 +271,12 @@ where
MeasureFunction:
FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
{
+ type CoreContainerStyle<'a> = &'a Style where Self : 'a;
+ type CacheMut<'b> = &'b mut Cache where Self : 'b;
+
#[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)]
@@ -301,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);
@@ -337,6 +340,66 @@ where
}
}
+#[cfg(feature = "block_layout")]
+impl<'t, NodeContext, MeasureFunction> LayoutBlockContainer for TaffyView<'t, NodeContext, MeasureFunction>
+where
+ MeasureFunction:
+ FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
+{
+ 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::BlockContainerStyle<'_> {
+ self.get_core_container_style(node_id)
+ }
+
+ #[inline(always)]
+ fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_> {
+ self.get_core_container_style(child_node_id)
+ }
+}
+
+#[cfg(feature = "flexbox")]
+impl<'t, NodeContext, MeasureFunction> LayoutFlexboxContainer for TaffyView<'t, NodeContext, MeasureFunction>
+where
+ MeasureFunction:
+ FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
+{
+ 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::FlexboxContainerStyle<'_> {
+ &self.taffy.nodes[node_id.into()].style
+ }
+
+ #[inline(always)]
+ fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
+ &self.taffy.nodes[child_node_id.into()].style
+ }
+}
+
+#[cfg(feature = "grid")]
+impl<'t, NodeContext, MeasureFunction> LayoutGridContainer for TaffyView<'t, NodeContext, MeasureFunction>
+where
+ MeasureFunction:
+ FnMut(Size<Option<f32>>, Size<AvailableSpace>, NodeId, Option<&mut NodeContext>, &Style) -> Size<f32>,
+{
+ 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::GridContainerStyle<'_> {
+ &self.taffy.nodes[node_id.into()].style
+ }
+
+ #[inline(always)]
+ fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
+ &self.taffy.nodes[child_node_id.into()].style
+ }
+}
+
// RoundTree impl for TaffyView
impl<'t, NodeContext, MeasureFunction> RoundTree for TaffyView<'t, NodeContext, MeasureFunction>
where
diff --git a/src/tree/traits.rs b/src/tree/traits.rs
index ce6688294..a549232ea 100644
--- a/src/tree/traits.rs
+++ b/src/tree/traits.rs
@@ -128,7 +128,12 @@
//!
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};
+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`.
@@ -157,14 +162,26 @@ 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;
+
+ /// 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<Target = Cache> + DerefMut
+ where
+ Self: 'b;
+
+ /// 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);
/// 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;
@@ -191,6 +208,64 @@ 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 FlexboxContainerStyle<'a>: FlexboxContainerStyle
+ where
+ Self: 'a;
+ /// The style type representing each Flexbox item's styles
+ type FlexboxItemStyle<'a>: FlexboxItemStyle
+ where
+ Self: 'a;
+
+ /// Get the container's styles
+ 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::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 GridContainerStyle<'a>: GridContainerStyle
+ where
+ Self: 'a;
+
+ /// The style type representing each CSS Grid item's styles
+ type GridItemStyle<'a>: GridItemStyle
+ where
+ Self: 'a;
+
+ /// Get the container's styles
+ 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::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 BlockContainerStyle<'a>: CoreStyle
+ where
+ Self: 'a;
+ /// The style type representing each CSS Block item's styles
+ type BlockItemStyle<'a>: CoreStyle
+ where
+ Self: 'a;
+
+ /// Get the container's styles
+ 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::BlockItemStyle<'_>;
+}
+
// --- PRIVATE TRAITS
/// A private trait which allows us to add extra convenience methods to types which implement