Implement `calc()` in the low-level API (#773)
Signed-off-by: Nico Burns <nico@nicoburns.com>
0386dc966a41b6b10e4089018fcbeada72504df6 · by Nico Burns · (1 year ago) · parent afa6437b0 · browse the tree at this commit
Semantic delta · 98
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/track_sizing.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 7cae4b6ae..ac070e257 100644
--- a/examples/custom_tree_owned_partial.rs
+++ b/examples/custom_tree_owned_partial.rs
@@ -146,6 +146,10 @@ impl taffy::LayoutPartialTree for Node {
self.node_from_id_mut(node_id).layout = *layout
}
+ fn resolve_calc_value(&self, _val: u64, _basis: f32) -> f32 {
+ 0.0
+ }
+
fn compute_child_layout(&mut self, node_id: NodeId, inputs: taffy::tree::LayoutInput) -> taffy::tree::LayoutOutput {
compute_cached_layout(self, node_id, inputs, |parent, node_id, inputs| {
let node = parent.node_from_id_mut(node_id);
@@ -154,17 +158,27 @@ impl taffy::LayoutPartialTree for Node {
match node.kind {
NodeKind::Flexbox => compute_flexbox_layout(node, node_id, inputs),
NodeKind::Grid => compute_grid_layout(node, node_id, inputs),
- NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
- text_measure_function(
- known_dimensions,
- available_space,
- node.text_data.as_ref().unwrap(),
- &font_metrics,
- )
- }),
- NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
- image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
- }),
+ NodeKind::Text => compute_leaf_layout(
+ inputs,
+ &node.style,
+ |_val, _basis| 0.0,
+ |known_dimensions, available_space| {
+ text_measure_function(
+ known_dimensions,
+ available_space,
+ node.text_data.as_ref().unwrap(),
+ &font_metrics,
+ )
+ },
+ ),
+ NodeKind::Image => compute_leaf_layout(
+ inputs,
+ &node.style,
+ |_val, _basis| 0.0,
+ |known_dimensions, _available_space| {
+ image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
+ },
+ ),
}
})
}
diff --git a/examples/custom_tree_owned_unsafe.rs b/examples/custom_tree_owned_unsafe.rs
index 753424b06..ed13d653a 100644
--- a/examples/custom_tree_owned_unsafe.rs
+++ b/examples/custom_tree_owned_unsafe.rs
@@ -143,6 +143,10 @@ impl LayoutPartialTree for StatelessLayoutTree {
unsafe { node_from_id_mut(node_id).unrounded_layout = *layout };
}
+ fn resolve_calc_value(&self, _val: u64, _basis: f32) -> f32 {
+ 0.0
+ }
+
fn compute_child_layout(&mut self, node_id: NodeId, inputs: taffy::tree::LayoutInput) -> taffy::tree::LayoutOutput {
compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
let node = unsafe { node_from_id_mut(node_id) };
@@ -151,17 +155,27 @@ impl LayoutPartialTree for StatelessLayoutTree {
match node.kind {
NodeKind::Flexbox => compute_flexbox_layout(tree, node_id, inputs),
NodeKind::Grid => compute_grid_layout(tree, node_id, inputs),
- NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
- text_measure_function(
- known_dimensions,
- available_space,
- node.text_data.as_ref().unwrap(),
- &font_metrics,
- )
- }),
- NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
- image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
- }),
+ NodeKind::Text => compute_leaf_layout(
+ inputs,
+ &node.style,
+ |val, basis| tree.resolve_calc_value(val, basis),
+ |known_dimensions, available_space| {
+ text_measure_function(
+ known_dimensions,
+ available_space,
+ node.text_data.as_ref().unwrap(),
+ &font_metrics,
+ )
+ },
+ ),
+ NodeKind::Image => compute_leaf_layout(
+ inputs,
+ &node.style,
+ |val, basis| tree.resolve_calc_value(val, basis),
+ |known_dimensions, _available_space| {
+ image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
+ },
+ ),
}
})
}
diff --git a/examples/custom_tree_vec.rs b/examples/custom_tree_vec.rs
index 89ed08584..a7125cb94 100644
--- a/examples/custom_tree_vec.rs
+++ b/examples/custom_tree_vec.rs
@@ -152,25 +152,39 @@ impl taffy::LayoutPartialTree for Tree {
self.node_from_id_mut(node_id).unrounded_layout = *layout;
}
+ fn resolve_calc_value(&self, _val: u64, _basis: f32) -> f32 {
+ 0.0
+ }
+
fn compute_child_layout(&mut self, node_id: NodeId, inputs: taffy::tree::LayoutInput) -> taffy::tree::LayoutOutput {
compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
- let node = tree.node_from_id_mut(node_id);
+ let node = &mut tree.nodes[usize::from(node_id)];
let font_metrics = FontMetrics { char_width: 10.0, char_height: 10.0 };
match node.kind {
NodeKind::Flexbox => compute_flexbox_layout(tree, node_id, inputs),
NodeKind::Grid => compute_grid_layout(tree, node_id, inputs),
- NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
- text_measure_function(
- known_dimensions,
- available_space,
- node.text_data.as_ref().unwrap(),
- &font_metrics,
- )
- }),
- NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
- image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
- }),
+ NodeKind::Text => compute_leaf_layout(
+ inputs,
+ &node.style,
+ |_val, _basis| 0.0,
+ |known_dimensions, available_space| {
+ text_measure_function(
+ known_dimensions,
+ available_space,
+ node.text_data.as_ref().unwrap(),
+ &font_metrics,
+ )
+ },
+ ),
+ NodeKind::Image => compute_leaf_layout(
+ inputs,
+ &node.style,
+ |_val, _basis| 0.0,
+ |known_dimensions, _available_space| {
+ image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
+ },
+ ),
}
})
}
diff --git a/src/compute/block.rs b/src/compute/block.rs
index be1c4f16d..35f5be89f 100644
--- a/src/compute/block.rs
+++ b/src/compute/block.rs
@@ -71,26 +71,26 @@ pub fn compute_block_layout(
// 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 padding = style.padding().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let border = style.border().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
let padding_border_size = (padding + border).sum_axes();
let box_sizing_adjustment =
if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };
let min_size = style
.min_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = style
.max_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let clamped_style_size = if inputs.sizing_mode == SizingMode::InherentSize {
style
.size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment)
.maybe_clamp(min_size, max_size)
@@ -132,8 +132,8 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs:
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);
+ let padding = raw_padding.resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let border = raw_border.resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
// 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
@@ -153,16 +153,19 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs:
let box_sizing_adjustment =
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);
+ let size = style
+ .size()
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
+ .maybe_apply_aspect_ratio(aspect_ratio)
+ .maybe_add(box_sizing_adjustment);
let min_size = style
.min_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = style
.max_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
@@ -214,8 +217,8 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs:
}
// 3. Perform final item layout and return content height
- let resolved_padding = raw_padding.resolve_or_zero(Some(container_outer_width));
- let resolved_border = raw_border.resolve_or_zero(Some(container_outer_width));
+ let resolved_padding = raw_padding.resolve_or_zero(Some(container_outer_width), |val, basis| tree.calc(val, basis));
+ let resolved_border = raw_border.resolve_or_zero(Some(container_outer_width), |val, basis| tree.calc(val, basis));
let resolved_content_box_inset = resolved_padding + resolved_border + scrollbar_gutter;
let (inflow_content_size, intrinsic_outer_height, first_child_top_margin_set, last_child_bottom_margin_set) =
perform_final_layout_on_in_flow_children(
@@ -279,13 +282,14 @@ fn compute_inner(tree: &mut impl LayoutBlockContainer, node_id: NodeId, inputs:
top_margin: if own_margins_collapse_with_children.start {
first_child_top_margin_set
} else {
- let margin_top = raw_margin.top.resolve_or_zero(parent_size.width);
+ let margin_top = raw_margin.top.resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
CollapsibleMarginSet::from_margin(margin_top)
},
bottom_margin: if own_margins_collapse_with_children.end {
last_child_bottom_margin_set
} else {
- let margin_bottom = raw_margin.bottom.resolve_or_zero(parent_size.width);
+ let margin_bottom =
+ raw_margin.bottom.resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
CollapsibleMarginSet::from_margin(margin_bottom)
},
margins_can_collapse_through: can_be_collapsed_through,
@@ -305,8 +309,8 @@ fn generate_item_list(
.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 padding = child_style.padding().resolve_or_zero(node_inner_size, |val, basis| tree.calc(val, basis));
+ let border = child_style.border().resolve_or_zero(node_inner_size, |val, basis| tree.calc(val, basis));
let pb_sum = (padding + border).sum_axes();
let box_sizing_adjustment =
if child_style.box_sizing() == BoxSizing::ContentBox { pb_sum } else { Size::ZERO };
@@ -316,17 +320,17 @@ fn generate_item_list(
is_table: child_style.is_table(),
size: child_style
.size()
- .maybe_resolve(node_inner_size)
+ .maybe_resolve(node_inner_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
min_size: child_style
.min_size()
- .maybe_resolve(node_inner_size)
+ .maybe_resolve(node_inner_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
max_size: child_style
.max_size()
- .maybe_resolve(node_inner_size)
+ .maybe_resolve(node_inner_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
overflow: child_style.overflow(),
@@ -361,8 +365,10 @@ fn determine_content_based_container_width(
let known_dimensions = item.size.maybe_clamp(item.min_size, item.max_size);
let width = known_dimensions.width.unwrap_or_else(|| {
- let item_x_margin_sum =
- item.margin.resolve_or_zero(available_space.width.into_option()).horizontal_axis_sum();
+ let item_x_margin_sum = item
+ .margin
+ .resolve_or_zero(available_space.width.into_option(), |val, basis| tree.calc(val, basis))
+ .horizontal_axis_sum();
let size_and_baselines = tree.perform_child_layout(
item.node_id,
known_dimensions,
@@ -410,7 +416,9 @@ fn perform_final_layout_on_in_flow_children(
if item.position == Position::Absolute {
item.static_position = Point { x: resolved_content_box_inset.left, y: y_offset_for_absolute }
} else {
- let item_margin = item.margin.map(|margin| margin.resolve_to_option(container_outer_width));
+ let item_margin = item
+ .margin
+ .map(|margin| margin.resolve_to_option(container_outer_width, |val, basis| tree.calc(val, basis)));
let item_non_auto_margin = item_margin.map(|m| m.unwrap_or(0.0));
let item_non_auto_x_margin_sum = item_non_auto_margin.horizontal_axis_sum();
let known_dimensions = if item.is_table {
@@ -462,8 +470,9 @@ fn perform_final_layout_on_in_flow_children(
};
// Resolve item inset
- let inset =
- item.inset.zip_size(Size { width: container_inner_width, height: 0.0 }, |p, s| p.maybe_resolve(s));
+ let inset = item.inset.zip_size(Size { width: container_inner_width, height: 0.0 }, |p, s| {
+ p.maybe_resolve(s, |val, basis| tree.calc(val, basis))
+ });
let inset_offset = Point {
x: inset.left.or(inset.right.map(|x| -x)).unwrap_or(0.0),
y: inset.top.or(inset.bottom.map(|x| -x)).unwrap_or(0.0),
@@ -590,35 +599,36 @@ fn perform_absolute_layout_on_absolute_children(
}
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 margin =
+ child_style.margin().map(|margin| margin.resolve_to_option(area_width, |val, basis| tree.calc(val, basis)));
+ let padding = child_style.padding().resolve_or_zero(Some(area_width), |val, basis| tree.calc(val, basis));
+ let border = child_style.border().resolve_or_zero(Some(area_width), |val, basis| tree.calc(val, basis));
let padding_border_sum = (padding + border).sum_axes();
let box_sizing_adjustment =
if child_style.box_sizing() == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO };
// Resolve inset
- 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, |val, basis| tree.calc(val, basis));
+ let right = child_style.inset().right.maybe_resolve(area_width, |val, basis| tree.calc(val, basis));
+ let top = child_style.inset().top.maybe_resolve(area_height, |val, basis| tree.calc(val, basis));
+ let bottom = child_style.inset().bottom.maybe_resolve(area_height, |val, basis| tree.calc(val, basis));
// Compute known dimensions from min/max/inherent size styles
let style_size = child_style
.size()
- .maybe_resolve(area_size)
+ .maybe_resolve(area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let min_size = child_style
.min_size()
- .maybe_resolve(area_size)
+ .maybe_resolve(area_size, |val, basis| tree.calc(val, basis))
.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()
- .maybe_resolve(area_size)
+ .maybe_resolve(area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let mut known_dimensions = style_size.maybe_clamp(min_size, max_size);
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index e34d193ba..90d526440 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -171,26 +171,26 @@ pub fn compute_flexbox_layout(
// 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 padding = style.padding().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let border = style.border().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
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 min_size = style
.min_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = style
.max_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let clamped_style_size = if inputs.sizing_mode == SizingMode::InherentSize {
style
.size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment)
.maybe_clamp(min_size, max_size)
@@ -227,7 +227,7 @@ fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inp
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_flexbox_container_style(node), known_dimensions, parent_size);
+ let mut constants = compute_constants(tree, tree.get_flexbox_container_style(node), known_dimensions, parent_size);
// 9. Flex Layout Algorithm
@@ -284,7 +284,11 @@ fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inp
// Re-resolve percentage gaps
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, |val, basis| tree.calc(val, basis))
+ .unwrap_or(0.0);
constants.gap.set_main(constants.dir, new_gap);
}
@@ -411,6 +415,7 @@ fn compute_preliminary(tree: &mut impl LayoutFlexboxContainer, node: NodeId, inp
/// Compute constants that can be reused during the flexbox algorithm.
#[inline]
fn compute_constants(
+ tree: &impl LayoutFlexboxContainer,
style: impl FlexboxContainerStyle,
known_dimensions: Size<Option<f32>>,
parent_size: Size<Option<f32>>,
@@ -422,9 +427,9 @@ fn compute_constants(
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 margin = style.margin().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let padding = style.padding().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let border = style.border().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
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 };
@@ -447,7 +452,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()), |val, basis| tree.calc(val, basis));
let container_size = Size::zero();
let inner_container_size = Size::zero();
@@ -460,12 +465,12 @@ fn compute_constants(
is_wrap_reverse,
min_size: style
.min_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
max_size: style
.max_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
margin,
@@ -501,8 +506,12 @@ fn generate_anonymous_flex_items(
.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 padding = child_style
+ .padding()
+ .resolve_or_zero(constants.node_inner_size.width, |val, basis| tree.calc(val, basis));
+ let border = child_style
+ .border()
+ .resolve_or_zero(constants.node_inner_size.width, |val, basis| tree.calc(val, basis));
let pb_sum = (padding + border).sum_axes();
let box_sizing_adjustment =
if child_style.box_sizing() == BoxSizing::ContentBox { pb_sum } else { Size::ZERO };
@@ -511,25 +520,33 @@ fn generate_anonymous_flex_items(
order: index as u32,
size: child_style
.size()
- .maybe_resolve(constants.node_inner_size)
+ .maybe_resolve(constants.node_inner_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
min_size: child_style
.min_size()
- .maybe_resolve(constants.node_inner_size)
+ .maybe_resolve(constants.node_inner_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
max_size: child_style
.max_size()
- .maybe_resolve(constants.node_inner_size)
+ .maybe_resolve(constants.node_inner_size, |val, basis| tree.calc(val, basis))
.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),
+ inset: child_style
+ .inset()
+ .zip_size(constants.node_inner_size, |p, s| p.maybe_resolve(s, |val, basis| tree.calc(val, basis))),
+ margin: child_style
+ .margin()
+ .resolve_or_zero(constants.node_inner_size.width, |val, basis| tree.calc(val, basis)),
margin_is_auto: child_style.margin().map(LengthPercentageAuto::is_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),
+ padding: child_style
+ .padding()
+ .resolve_or_zero(constants.node_inner_size.width, |val, basis| tree.calc(val, basis)),
+ border: child_style
+ .border()
+ .resolve_or_zero(constants.node_inner_size.width, |val, basis| tree.calc(val, basis)),
align_self: child_style.align_self().unwrap_or(constants.align_items),
overflow: child_style.overflow(),
scrollbar_width: child_style.scrollbar_width(),
@@ -670,14 +687,17 @@ fn determine_flex_base_size(
let container_width = constants.node_inner_size.main(dir);
let box_sizing_adjustment = if child_style.box_sizing() == BoxSizing::ContentBox {
- let padding = child_style.padding().resolve_or_zero(container_width);
- let border = child_style.border().resolve_or_zero(container_width);
+ let padding = child_style.padding().resolve_or_zero(container_width, |val, basis| tree.calc(val, basis));
+ let border = child_style.border().resolve_or_zero(container_width, |val, basis| tree.calc(val, basis));
(padding + border).sum_axes()
} else {
Size::ZERO
}
.main(dir);
- let flex_basis = child_style.flex_basis().maybe_resolve(container_width).maybe_add(box_sizing_adjustment);
+ let flex_basis = child_style
+ .flex_basis()
+ .maybe_resolve(container_width, |val, basis| tree.calc(val, basis))
+ .maybe_add(box_sizing_adjustment);
drop(child_style);
@@ -1583,15 +1603,19 @@ fn determine_used_cross_size(
// 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, |val, basis| tree.calc(val, basis));
+ let border = child_style
+ .border()
+ .resolve_or_zero(constants.node_inner_size, |val, basis| tree.calc(val, basis));
let pb_sum = (padding + border).sum_axes();
let box_sizing_adjustment =
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_resolve(constants.node_inner_size, |val, basis| tree.calc(val, basis))
.maybe_add(box_sizing_adjustment);
(line_cross_size - child.margin.cross_axis_sum(constants.dir)).maybe_clamp(
@@ -2056,36 +2080,43 @@ fn perform_absolute_layout_on_absolute_children(
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 margin = child_style
+ .margin()
+ .map(|margin| margin.resolve_to_option(inset_relative_size.width, |val, basis| tree.calc(val, basis)));
+ let padding =
+ child_style.padding().resolve_or_zero(Some(inset_relative_size.width), |val, basis| tree.calc(val, basis));
+ let border =
+ child_style.border().resolve_or_zero(Some(inset_relative_size.width), |val, basis| tree.calc(val, basis));
let padding_border_sum = (padding + border).sum_axes();
let box_sizing_adjustment =
if child_style.box_sizing() == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO };
// Resolve inset
// Insets are resolved against the container size minus border
- let left = child_style.inset().left.maybe_resolve(inset_relative_size.width);
- let right = child_style.inset().right.maybe_resolve(inset_relative_size.width);
- let top = child_style.inset().top.maybe_resolve(inset_relative_size.height);
- let bottom = child_style.inset().bottom.maybe_resolve(inset_relative_size.height);
+ let left =
+ child_style.inset().left.maybe_resolve(inset_relative_size.width, |val, basis| tree.calc(val, basis));
+ let right =
+ child_style.inset().right.maybe_resolve(inset_relative_size.width, |val, basis| tree.calc(val, basis));
+ let top = child_style.inset().top.maybe_resolve(inset_relative_size.height, |val, basis| tree.calc(val, basis));
+ let bottom =
+ child_style.inset().bottom.maybe_resolve(inset_relative_size.height, |val, basis| tree.calc(val, basis));
// Compute known dimensions from min/max/inherent size styles
let style_size = child_style
.size()
- .maybe_resolve(inset_relative_size)
+ .maybe_resolve(inset_relative_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let min_size = child_style
.min_size()
- .maybe_resolve(inset_relative_size)
+ .maybe_resolve(inset_relative_size, |val, basis| tree.calc(val, basis))
.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()
- .maybe_resolve(inset_relative_size)
+ .maybe_resolve(inset_relative_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let mut known_dimensions = style_size.maybe_clamp(min_size, max_size);
diff --git a/src/compute/grid/alignment.rs b/src/compute/grid/alignment.rs
index aeeed4424..68303f9bc 100644
--- a/src/compute/grid/alignment.rs
+++ b/src/compute/grid/alignment.rs
@@ -75,11 +75,18 @@ pub(super) fn align_and_position_item(
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 inset_horizontal = style
+ .inset()
+ .horizontal_components()
+ .map(|size| size.resolve_to_option(grid_area_size.width, |val, basis| tree.calc(val, basis)));
+ let inset_vertical = style
+ .inset()
+ .vertical_components()
+ .map(|size| size.resolve_to_option(grid_area_size.height, |val, basis| tree.calc(val, basis)));
+ let padding =
+ style.padding().map(|p| p.resolve_or_zero(Some(grid_area_size.width), |val, basis| tree.calc(val, basis)));
+ let border =
+ style.border().map(|p| p.resolve_or_zero(Some(grid_area_size.width), |val, basis| tree.calc(val, basis)));
let padding_border_size = (padding + border).sum_axes();
let box_sizing_adjustment =
@@ -87,19 +94,19 @@ pub(super) fn align_and_position_item(
let inherent_size = style
.size()
- .maybe_resolve(grid_area_size)
+ .maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let min_size = style
.min_size()
- .maybe_resolve(grid_area_size)
+ .maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.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()
- .maybe_resolve(grid_area_size)
+ .maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
@@ -126,7 +133,8 @@ 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, |val, basis| tree.calc(val, basis)));
let grid_area_minus_item_margins_size = Size {
width: grid_area_size.width.maybe_sub(margin.left).maybe_sub(margin.right),
diff --git a/src/compute/grid/explicit_grid.rs b/src/compute/grid/explicit_grid.rs
index 6faca1af9..fbb5168bd 100644
--- a/src/compute/grid/explicit_grid.rs
+++ b/src/compute/grid/explicit_grid.rs
@@ -14,6 +14,7 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
style: &impl GridContainerStyle,
template: &[TrackSizingFunction],
inner_container_size: Size<Option<f32>>,
+ resolve_calc_value: impl Fn(u64, f32) -> f32,
axis: AbsoluteAxis,
) -> u16 {
// If template contains no tracks, then there are trivially zero explicit tracks
@@ -88,9 +89,10 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
// Otherwise, if the grid container has a definite min size in the relevant 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 style_size_is_definite = style.size().get_abs(axis).maybe_resolve(inner_container_size.get_abs(axis)).is_some();
+ let style_size_is_definite =
+ style.size().get_abs(axis).maybe_resolve(inner_container_size.get_abs(axis), &resolve_calc_value).is_some();
let style_max_size_is_definite =
- style.max_size().get_abs(axis).maybe_resolve(inner_container_size.get_abs(axis)).is_some();
+ style.max_size().get_abs(axis).maybe_resolve(inner_container_size.get_abs(axis), &resolve_calc_value).is_some();
let size_is_maximum = style_size_is_definite | style_max_size_is_definite;
// Determine the number of repetitions
@@ -101,9 +103,13 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
/// ...treating each track as its max track sizing function if that is definite or as its minimum track sizing function
/// otherwise, flooring the max track sizing function by the min track sizing function if both are definite
- fn track_definite_value(sizing_function: &NonRepeatedTrackSizingFunction, parent_size: Option<f32>) -> f32 {
- let max_size = sizing_function.max.definite_value(parent_size);
- let min_size = sizing_function.min.definite_value(parent_size);
+ fn track_definite_value(
+ sizing_function: &NonRepeatedTrackSizingFunction,
+ parent_size: Option<f32>,
+ calc_resolver: impl Fn(u64, f32) -> f32,
+ ) -> f32 {
+ let max_size = sizing_function.max.definite_value(parent_size, &calc_resolver);
+ let min_size = sizing_function.min.definite_value(parent_size, &calc_resolver);
max_size.map(|max| max.maybe_min(min_size)).or(min_size).unwrap()
}
@@ -113,12 +119,14 @@ pub(crate) fn compute_explicit_grid_size_in_axis(
use GridTrackRepetition::{AutoFill, AutoFit, Count};
match track_def {
TrackSizingFunction::Single(sizing_function) => {
- track_definite_value(sizing_function, parent_size)
+ track_definite_value(sizing_function, parent_size, &resolve_calc_value)
}
TrackSizingFunction::Repeat(Count(count), repeated_tracks) => {
let sum = repeated_tracks
.iter()
- .map(|sizing_function| track_definite_value(sizing_function, parent_size))
+ .map(|sizing_function| {
+ track_definite_value(sizing_function, parent_size, &resolve_calc_value)
+ })
.sum::<f32>();
sum * (*count as f32)
}
@@ -126,12 +134,12 @@ 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), &resolve_calc_value);
// Compute the amount of space that a single repetition of the repeated track list takes
let per_repetition_track_used_space: f32 = repetition_definition
.iter()
- .map(|sizing_function| track_definite_value(sizing_function, parent_size))
+ .map(|sizing_function| track_definite_value(sizing_function, parent_size, &resolve_calc_value))
.sum::<f32>();
// We special case the first repetition here because the number of gaps in the first repetition
@@ -295,12 +303,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 2);
@@ -322,12 +332,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 3);
@@ -349,12 +361,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 3);
@@ -376,12 +390,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
inner_container_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
inner_container_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 3);
@@ -403,12 +419,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
inner_container_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
inner_container_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 4);
@@ -430,12 +448,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 4); // 2 repetitions * 2 repeated tracks = 4 tracks in total
@@ -458,12 +478,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 2); // 2 tracks + 1 gap
@@ -485,12 +507,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 3);
@@ -513,12 +537,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
preferred_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 3); // 3 tracks + 2 gaps
@@ -541,12 +567,14 @@ mod test {
&grid_style,
&grid_style.grid_template_columns,
inner_container_size,
+ |_, _| 42.42,
AbsoluteAxis::Horizontal,
);
let height = compute_explicit_grid_size_in_axis(
&grid_style,
&grid_style.grid_template_rows,
inner_container_size,
+ |_, _| 42.42,
AbsoluteAxis::Vertical,
);
assert_eq!(width, 5); // 40px horizontal padding
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index d8949dfe4..32338efed 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -42,7 +42,11 @@ 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 LayoutGridContainer, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
+pub fn compute_grid_layout<Tree: LayoutGridContainer>(
+ tree: &mut Tree,
+ node: NodeId,
+ inputs: LayoutInput,
+) -> LayoutOutput {
let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
let style = tree.get_grid_container_style(node);
@@ -50,8 +54,8 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
// 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 padding = style.padding().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let border = style.border().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
let padding_border = padding + border;
let padding_border_size = padding_border.sum_axes();
let box_sizing_adjustment =
@@ -59,18 +63,18 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
let min_size = style
.min_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = style
.max_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let preferred_size = if inputs.sizing_mode == SizingMode::InherentSize {
style
.size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(style.aspect_ratio())
.maybe_add(box_sizing_adjustment)
} else {
@@ -153,12 +157,14 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
&style,
grid_template_columms.borrow(),
auto_fit_container_size,
+ |val, basis| tree.calc(val, basis),
AbsoluteAxis::Horizontal,
);
let explicit_row_count = compute_explicit_grid_size_in_axis(
&style,
grid_template_rows.borrow(),
auto_fit_container_size,
+ |val, basis| tree.calc(val, basis),
AbsoluteAxis::Vertical,
);
@@ -247,7 +253,9 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
&mut columns,
&mut rows,
&mut items,
- |track: &GridTrack, parent_size: Option<f32>| track.max_track_sizing_function.definite_value(parent_size),
+ |track: &GridTrack, parent_size: Option<f32>, tree: &Tree| {
+ track.max_track_sizing_function.definite_value(parent_size, |val, basis| tree.calc(val, basis))
+ },
has_baseline_aligned_item,
);
let initial_column_sum = columns.iter().map(|track| track.base_size).sum::<f32>();
@@ -267,7 +275,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
&mut rows,
&mut columns,
&mut items,
- |track: &GridTrack, _| Some(track.base_size),
+ |track: &GridTrack, _, _| Some(track.base_size),
false, // TODO: Support baseline alignment in the vertical axis
);
let initial_row_sum = rows.iter().map(|track| track.base_size).sum::<f32>();
@@ -307,17 +315,23 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
// and therefore need to be re-resolved here based on the content-sized content box of the container
if !available_grid_space.width.is_definite() {
for column in &mut columns {
- let min: Option<f32> =
- column.min_track_sizing_function.resolved_percentage_size(container_content_box.width);
- let max: Option<f32> =
- column.max_track_sizing_function.resolved_percentage_size(container_content_box.width);
+ let min: Option<f32> = column
+ .min_track_sizing_function
+ .resolved_percentage_size(container_content_box.width, |val, basis| tree.calc(val, basis));
+ let max: Option<f32> = column
+ .max_track_sizing_function
+ .resolved_percentage_size(container_content_box.width, |val, basis| tree.calc(val, basis));
column.base_size = column.base_size.maybe_clamp(min, max);
}
}
if !available_grid_space.height.is_definite() {
for row in &mut rows {
- let min: Option<f32> = row.min_track_sizing_function.resolved_percentage_size(container_content_box.height);
- let max: Option<f32> = row.max_track_sizing_function.resolved_percentage_size(container_content_box.height);
+ let min: Option<f32> = row
+ .min_track_sizing_function
+ .resolved_percentage_size(container_content_box.height, |val, basis| tree.calc(val, basis));
+ let max: Option<f32> = row
+ .max_track_sizing_function
+ .resolved_percentage_size(container_content_box.height, |val, basis| tree.calc(val, basis));
row.base_size = row.base_size.maybe_clamp(min, max);
}
}
@@ -377,7 +391,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
&mut columns,
&mut rows,
&mut items,
- |track: &GridTrack, _| Some(track.base_size),
+ |track: &GridTrack, _, _| Some(track.base_size),
has_baseline_aligned_item,
);
@@ -436,7 +450,7 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
&mut rows,
&mut columns,
&mut items,
- |track: &GridTrack, _| Some(track.base_size),
+ |track: &GridTrack, _, _| Some(track.base_size),
false, // TODO: Support baseline alignment in the vertical axis
);
}
diff --git a/src/compute/grid/track_sizing.rs b/src/compute/grid/track_sizing.rs
index d0483ecec..bf95772b7 100644
--- a/src/compute/grid/track_sizing.rs
+++ b/src/compute/grid/track_sizing.rs
@@ -67,7 +67,7 @@ impl ItemBatcher {
struct IntrisicSizeMeasurer<'tree, 'oat, Tree, EstimateFunction>
where
Tree: LayoutPartialTree,
- EstimateFunction: Fn(&GridTrack, Option<f32>) -> Option<f32>,
+ EstimateFunction: Fn(&GridTrack, Option<f32>, &Tree) -> Option<f32>,
{
/// The layout tree
tree: &'tree mut Tree,
@@ -85,7 +85,7 @@ where
impl<Tree, EstimateFunction> IntrisicSizeMeasurer<'_, '_, Tree, EstimateFunction>
where
Tree: LayoutPartialTree,
- EstimateFunction: Fn(&GridTrack, Option<f32>) -> Option<f32>,
+ EstimateFunction: Fn(&GridTrack, Option<f32>, &Tree) -> Option<f32>,
{
/// Compute the available_space to be passed to the child sizing functions
/// These are estimates based on either the max track sizing function or the provisional base size in the opposite
@@ -97,7 +97,7 @@ where
self.axis,
self.other_axis_tracks,
self.inner_node_size.get(self.axis.other()),
- &self.get_track_size_estimate,
+ |track, basis| (self.get_track_size_estimate)(track, basis, self.tree),
)
}
@@ -105,7 +105,13 @@ where
/// to zero if the container size is indefinite as otherwise this would introduce a cyclic dependency.
#[inline(always)]
fn margins_axis_sums_with_baseline_shims(&self, item: &GridItem) -> Size<f32> {
- item.margins_axis_sums_with_baseline_shims(self.inner_node_size.width)
+ item.margins_axis_sums_with_baseline_shims(self.inner_node_size.width, self.tree)
+ }
+
+ /// Simple pass-through function to `LayoutPartialTreeExt::calc`
+ #[inline(always)]
+ fn calc(&self, val: u64, basis: f32) -> f32 {
+ self.tree.calc(val, basis)
}
/// Retrieve the item's min content contribution from the cache or compute it using the provided parameters
@@ -271,12 +277,12 @@ pub(super) fn track_sizing_algorithm<Tree: LayoutPartialTree>(
axis_tracks: &mut [GridTrack],
other_axis_tracks: &mut [GridTrack],
items: &mut [GridItem],
- get_track_size_estimate: fn(&GridTrack, Option<f32>) -> Option<f32>,
+ get_track_size_estimate: fn(&GridTrack, Option<f32>, &Tree) -> Option<f32>,
has_baseline_aligned_item: bool,
) {
// 11.4 Initialise Track sizes
// Initialize each track’s base size and growth limit.
- initialize_track_sizes(axis_tracks, inner_node_size.get(axis));
+ initialize_track_sizes(tree, axis_tracks, inner_node_size.get(axis));
// 11.5.1 Shim item baselines
if has_baseline_aligned_item {
@@ -296,7 +302,7 @@ pub(super) fn track_sizing_algorithm<Tree: LayoutPartialTree>(
let gutter_alignment_adjustment = compute_alignment_gutter_adjustment(
other_axis_alignment,
inner_node_size.get(axis.other()),
- get_track_size_estimate,
+ |track, basis| get_track_size_estimate(track, basis, tree),
other_axis_tracks,
);
if other_axis_tracks.len() > 3 {
@@ -397,7 +403,11 @@ fn flush_planned_growth_limit_increases(tracks: &mut [GridTrack], set_infinitely
/// 11.4 Initialise Track sizes
/// Initialize each track’s base size and growth limit.
#[inline(always)]
-fn initialize_track_sizes(axis_tracks: &mut [GridTrack], axis_inner_node_size: Option<f32>) {
+fn initialize_track_sizes(
+ tree: &impl LayoutPartialTree,
+ axis_tracks: &mut [GridTrack],
+ axis_inner_node_size: Option<f32>,
+) {
for track in axis_tracks.iter_mut() {
// For each track, if the track’s min track sizing function is:
// - A fixed sizing function
@@ -405,7 +415,10 @@ fn initialize_track_sizes(axis_tracks: &mut [GridTrack], axis_inner_node_size: O
// Note: Indefinite lengths cannot occur, as they’re treated as auto.
// - An intrinsic sizing function
// Use an initial base size of zero.
- track.base_size = track.min_track_sizing_function.definite_value(axis_inner_node_size).unwrap_or(0.0);
+ track.base_size = track
+ .min_track_sizing_function
+ .definite_value(axis_inner_node_size, |val, basis| tree.calc(val, basis))
+ .unwrap_or(0.0);
// For each track, if the track’s max track sizing function is:
// - A fixed sizing function
@@ -414,8 +427,10 @@ fn initialize_track_sizes(axis_tracks: &mut [GridTrack], axis_inner_node_size: O
// Use an initial growth limit of infinity.
// - A flexible sizing function
// Use an initial growth limit of infinity.
- track.growth_limit =
- track.max_track_sizing_function.definite_value(axis_inner_node_size).unwrap_or(f32::INFINITY);
+ track.growth_limit = track
+ .max_track_sizing_function
+ .definite_value(axis_inner_node_size, |val, basis| tree.calc(val, basis))
+ .unwrap_or(f32::INFINITY);
// In all cases, if the growth limit is less than the base size, increase the growth limit to match the base size.
if track.growth_limit < track.base_size {
@@ -482,7 +497,10 @@ fn resolve_item_baselines(
let baseline = measured_size_and_baselines.first_baselines.y;
let height = measured_size_and_baselines.size.height;
- item.baseline = Some(baseline.unwrap_or(height) + item.margin.top.resolve_or_zero(inner_node_size.width));
+ item.baseline = Some(
+ baseline.unwrap_or(height)
+ + item.margin.top.resolve_or_zero(inner_node_size.width, |val, basis| tree.calc(val, basis)),
+ );
}
// Compute the max baseline of all items in the row
@@ -498,15 +516,15 @@ fn resolve_item_baselines(
/// 11.5 Resolve Intrinsic Track Sizes
#[allow(clippy::too_many_arguments)]
-fn resolve_intrinsic_track_sizes(
- tree: &mut impl LayoutPartialTree,
+fn resolve_intrinsic_track_sizes<Tree: LayoutPartialTree>(
+ tree: &mut Tree,
axis: AbstractAxis,
axis_tracks: &mut [GridTrack],
other_axis_tracks: &[GridTrack],
items: &mut [GridItem],
axis_available_grid_space: AvailableSpace,
inner_node_size: Size<Option<f32>>,
- get_track_size_estimate: fn(&GridTrack, Option<f32>) -> Option<f32>,
+ get_track_size_estimate: impl Fn(&GridTrack, Option<f32>, &Tree) -> Option<f32>,
) {
// Step 1. Shim baseline-aligned items so their intrinsic size contributions reflect their baseline alignment.
@@ -577,7 +595,9 @@ fn resolve_intrinsic_track_sizes(
{
let axis_minimum_size = item_sizer.minimum_contribution(item, axis_tracks);
let axis_min_content_size = item_sizer.min_content_contribution(item);
- let limit = track.max_track_sizing_function.definite_limit(axis_inner_node_size);
+ let limit = track
+ .max_track_sizing_function
+ .definite_limit(axis_inner_node_size, |val, basis| item_sizer.calc(val, basis));
axis_min_content_size.maybe_min(limit).max(axis_minimum_size)
}
_ => item_sizer.minimum_contribution(item, axis_tracks),
@@ -588,6 +608,14 @@ fn resolve_intrinsic_track_sizes(
// Do nothing as it's not an intrinsic track sizing function
track.base_size
}
+ // Handle calc() like percentage
+ _ if track.min_track_sizing_function.0.is_calc() => {
+ if axis_inner_node_size.is_none() {
+ f32_max(track.base_size, item_sizer.min_content_contribution(item))
+ } else {
+ track.base_size
+ }
+ }
_ => unreachable!(),
};
let track = &mut axis_tracks[track_index as usize];
@@ -645,8 +673,6 @@ fn resolve_intrinsic_track_sizes(
// 1. For intrinsic minimums:
// First increase the base size of tracks with an intrinsic min track sizing function
- let has_intrinsic_min_track_sizing_function =
- move |track: &GridTrack| track.min_track_sizing_function.definite_value(axis_inner_node_size).is_none();
for item in batch.iter_mut().filter(|item| item.crosses_intrinsic_track(axis)) {
// ...by distributing extra space as needed to accommodate these items’ minimum contributions.
//
@@ -663,13 +689,21 @@ fn resolve_intrinsic_track_sizes(
{
let axis_minimum_size = item_sizer.minimum_contribution(item, axis_tracks);
let axis_min_content_size = item_sizer.min_content_contribution(item);
- let limit = item.spanned_track_limit(axis, axis_tracks, axis_inner_node_size);
+ let limit = item.spanned_track_limit(axis, axis_tracks, axis_inner_node_size, &|val, basis| {
+ item_sizer.calc(val, basis)
+ });
axis_min_content_size.maybe_min(limit).max(axis_minimum_size)
}
_ => item_sizer.minimum_contribution(item, axis_tracks),
};
let tracks = &mut axis_tracks[item.track_range_excluding_lines(axis)];
if space > 0.0 {
+ let has_intrinsic_min_track_sizing_function = |track: &GridTrack| {
+ track
+ .min_track_sizing_function
+ .definite_value(axis_inner_node_size, |val, basis| item_sizer.calc(val, basis))
+ .is_none()
+ };
if item.overflow.get(axis).is_scroll_container() {
let fit_content_limit =
move |track: &GridTrack| track.fit_content_limited_growth_limit(axis_inner_node_size);
@@ -764,7 +798,9 @@ fn resolve_intrinsic_track_sizes(
for item in batch.iter_mut() {
let axis_max_content_size = item_sizer.max_content_contribution(item);
- let limit = item.spanned_track_limit(axis, axis_tracks, axis_inner_node_size);
+ let limit = item.spanned_track_limit(axis, axis_tracks, axis_inner_node_size, &|val, basis| {
+ item_sizer.calc(val, basis)
+ });
let space = axis_max_content_size.maybe_min(limit);
let tracks = &mut axis_tracks[item.track_range_excluding_lines(axis)];
if space > 0.0 {
@@ -841,7 +877,7 @@ fn resolve_intrinsic_track_sizes(
// 5. For intrinsic maximums: Next increase the growth limit of tracks with an intrinsic max track sizing function by
// distributing extra space as needed to account for these items' min-content contributions.
let has_intrinsic_max_track_sizing_function =
- move |track: &GridTrack| track.max_track_sizing_function.definite_value(axis_inner_node_size).is_none();
+ move |track: &GridTrack| track.max_track_sizing_function.has_definite_value(axis_inner_node_size);
for item in batch.iter_mut() {
let axis_min_content_size = item_sizer.min_content_contribution(item);
let space = axis_min_content_size;
diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs
index ef7722f0d..28f81a125 100644
--- a/src/compute/grid/types/grid_item.rs
+++ b/src/compute/grid/types/grid_item.rs
@@ -189,15 +189,18 @@ impl GridItem {
axis: AbstractAxis,
axis_tracks: &[GridTrack],
axis_parent_size: Option<f32>,
+ resolve_calc_value: &dyn Fn(u64, f32) -> f32,
) -> Option<f32> {
let spanned_tracks = &axis_tracks[self.track_range_excluding_lines(axis)];
- let tracks_all_fixed = spanned_tracks
- .iter()
- .all(|track| track.max_track_sizing_function.definite_limit(axis_parent_size).is_some());
+ let tracks_all_fixed = spanned_tracks.iter().all(|track| {
+ track.max_track_sizing_function.definite_limit(axis_parent_size, resolve_calc_value).is_some()
+ });
if tracks_all_fixed {
let limit: f32 = spanned_tracks
.iter()
- .map(|track| track.max_track_sizing_function.definite_limit(axis_parent_size).unwrap())
+ .map(|track| {
+ track.max_track_sizing_function.definite_limit(axis_parent_size, resolve_calc_value).unwrap()
+ })
.sum();
Some(limit)
} else {
@@ -212,15 +215,18 @@ impl GridItem {
axis: AbstractAxis,
axis_tracks: &[GridTrack],
axis_parent_size: Option<f32>,
+ resolve_calc_value: &dyn Fn(u64, f32) -> f32,
) -> Option<f32> {
let spanned_tracks = &axis_tracks[self.track_range_excluding_lines(axis)];
- let tracks_all_fixed = spanned_tracks
- .iter()
- .all(|track| track.max_track_sizing_function.definite_value(axis_parent_size).is_some());
+ let tracks_all_fixed = spanned_tracks.iter().all(|track| {
+ track.max_track_sizing_function.definite_value(axis_parent_size, resolve_calc_value).is_some()
+ });
if tracks_all_fixed {
let limit: f32 = spanned_tracks
.iter()
- .map(|track| track.max_track_sizing_function.definite_value(axis_parent_size).unwrap())
+ .map(|track| {
+ track.max_track_sizing_function.definite_value(axis_parent_size, resolve_calc_value).unwrap()
+ })
.sum();
Some(limit)
} else {
@@ -233,30 +239,31 @@ impl GridItem {
/// allow percentage sizes further down the tree to resolve properly in some cases
fn known_dimensions(
&self,
+ tree: &mut impl LayoutPartialTree,
inner_node_size: Size<Option<f32>>,
grid_area_size: Size<Option<f32>>,
) -> Size<Option<f32>> {
- let margins = self.margins_axis_sums_with_baseline_shims(inner_node_size.width);
+ let margins = self.margins_axis_sums_with_baseline_shims(inner_node_size.width, tree);
let aspect_ratio = self.aspect_ratio;
- let padding = self.padding.resolve_or_zero(grid_area_size);
- let border = self.border.resolve_or_zero(grid_area_size);
+ let padding = self.padding.resolve_or_zero(grid_area_size, |val, basis| tree.calc(val, basis));
+ let border = self.border.resolve_or_zero(grid_area_size, |val, basis| tree.calc(val, basis));
let padding_border_size = (padding + border).sum_axes();
let box_sizing_adjustment =
if self.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };
let inherent_size = self
.size
- .maybe_resolve(grid_area_size)
+ .maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let min_size = self
.min_size
- .maybe_resolve(grid_area_size)
+ .maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = self
.max_size
- .maybe_resolve(grid_area_size)
+ .maybe_resolve(grid_area_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
@@ -344,12 +351,17 @@ impl GridItem {
/// Compute the item's resolved margins for size contributions. Horizontal percentage margins always resolve
/// to zero if the container size is indefinite as otherwise this would introduce a cyclic dependency.
#[inline(always)]
- pub fn margins_axis_sums_with_baseline_shims(&self, inner_node_width: Option<f32>) -> Size<f32> {
+ pub fn margins_axis_sums_with_baseline_shims(
+ &self,
+ inner_node_width: Option<f32>,
+ tree: &impl LayoutPartialTree,
+ ) -> Size<f32> {
Rect {
- left: self.margin.left.resolve_or_zero(Some(0.0)),
- right: self.margin.right.resolve_or_zero(Some(0.0)),
- top: self.margin.top.resolve_or_zero(inner_node_width) + self.baseline_shim,
- bottom: self.margin.bottom.resolve_or_zero(inner_node_width),
+ left: self.margin.left.resolve_or_zero(Some(0.0), |val, basis| tree.calc(val, basis)),
+ right: self.margin.right.resolve_or_zero(Some(0.0), |val, basis| tree.calc(val, basis)),
+ top: self.margin.top.resolve_or_zero(inner_node_width, |val, basis| tree.calc(val, basis))
+ + self.baseline_shim,
+ bottom: self.margin.bottom.resolve_or_zero(inner_node_width, |val, basis| tree.calc(val, basis)),
}
.sum_axes()
}
@@ -362,7 +374,7 @@ impl GridItem {
available_space: Size<Option<f32>>,
inner_node_size: Size<Option<f32>>,
) -> f32 {
- let known_dimensions = self.known_dimensions(inner_node_size, available_space);
+ let known_dimensions = self.known_dimensions(tree, inner_node_size, available_space);
tree.measure_child_size(
self.node,
known_dimensions,
@@ -401,7 +413,7 @@ impl GridItem {
available_space: Size<Option<f32>>,
inner_node_size: Size<Option<f32>>,
) -> f32 {
- let known_dimensions = self.known_dimensions(inner_node_size, available_space);
+ let known_dimensions = self.known_dimensions(tree, inner_node_size, available_space);
tree.measure_child_size(
self.node,
known_dimensions,
@@ -448,20 +460,20 @@ impl GridItem {
known_dimensions: Size<Option<f32>>,
inner_node_size: Size<Option<f32>>,
) -> f32 {
- let padding = self.padding.resolve_or_zero(inner_node_size);
- let border = self.border.resolve_or_zero(inner_node_size);
+ let padding = self.padding.resolve_or_zero(inner_node_size, |val, basis| tree.calc(val, basis));
+ let border = self.border.resolve_or_zero(inner_node_size, |val, basis| tree.calc(val, basis));
let padding_border_size = (padding + border).sum_axes();
let box_sizing_adjustment =
if self.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };
let size = self
.size
- .maybe_resolve(inner_node_size)
+ .maybe_resolve(inner_node_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(self.aspect_ratio)
.maybe_add(box_sizing_adjustment)
.get(axis)
.or_else(|| {
self.min_size
- .maybe_resolve(inner_node_size)
+ .maybe_resolve(inner_node_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(self.aspect_ratio)
.maybe_add(box_sizing_adjustment)
.get(axis)
@@ -501,7 +513,9 @@ impl GridItem {
// In all cases, the size suggestion is additionally clamped by the maximum size in the affected axis, if it’s definite.
// Note: The argument to fit-content() does not clamp the content-based minimum size in the same way as a fixed max track
// sizing function.
- let limit = self.spanned_fixed_track_limit(axis, axis_tracks, inner_node_size.get(axis));
+ let limit = self.spanned_fixed_track_limit(axis, axis_tracks, inner_node_size.get(axis), &|val, basis| {
+ tree.resolve_calc_value(val, basis)
+ });
size.maybe_min(limit)
}
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index c05d54eb2..9adbcc9cf 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -15,6 +15,7 @@ use core::unreachable;
pub fn compute_leaf_layout<MeasureFunction>(
inputs: LayoutInput,
style: &impl CoreStyle,
+ resolve_calc_value: impl Fn(u64, f32) -> f32,
measure_function: MeasureFunction,
) -> LayoutOutput
where
@@ -24,9 +25,9 @@ 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, &resolve_calc_value);
+ let padding = style.padding().resolve_or_zero(parent_size.width, &resolve_calc_value);
+ let border = style.border().resolve_or_zero(parent_size.width, &resolve_calc_value);
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 };
@@ -44,15 +45,16 @@ where
let aspect_ratio = style.aspect_ratio();
let style_size = style
.size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, &resolve_calc_value)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let style_min_size = style
.min_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, &resolve_calc_value)
.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, &resolve_calc_value).maybe_add(box_sizing_adjustment);
let node_size = known_dimensions.or(style_size);
(node_size, style_min_size, style_max_size, aspect_ratio)
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 4228e21a0..cf0b78ca8 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -66,26 +66,26 @@ pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, avai
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 margin = style.margin().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let padding = style.padding().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
+ let border = style.border().resolve_or_zero(parent_size.width, |val, basis| tree.calc(val, basis));
let padding_border_size = (padding + border).sum_axes();
let box_sizing_adjustment =
if style.box_sizing() == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };
let min_size = style
.min_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = style
.max_size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let clamped_style_size = style
.size()
- .maybe_resolve(parent_size)
+ .maybe_resolve(parent_size, |val, basis| tree.calc(val, basis))
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment)
.maybe_clamp(min_size, max_size);
@@ -123,9 +123,12 @@ pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, avai
);
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 padding =
+ style.padding().resolve_or_zero(available_space.width.into_option(), |val, basis| tree.calc(val, basis));
+ let border =
+ style.border().resolve_or_zero(available_space.width.into_option(), |val, basis| tree.calc(val, basis));
+ let margin =
+ style.margin().resolve_or_zero(available_space.width.into_option(), |val, basis| tree.calc(val, basis));
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 },
diff --git a/src/lib.rs b/src/lib.rs
index 85ab924b9..d3a252d25 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -63,7 +63,6 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unsafe_code)]
-#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![warn(clippy::missing_docs_in_private_items)]
diff --git a/src/style/dimension.rs b/src/style/dimension.rs
index 59fbd2bf3..70342c335 100644
--- a/src/style/dimension.rs
+++ b/src/style/dimension.rs
@@ -12,8 +12,10 @@ pub struct CompactLength(u64);
impl CompactLength {
// Masks
- /// The low bytes (8 bits)
+ /// The low byte (8 bits)
pub const TAG_MASK: u64 = 0b11111111;
+ /// The low 3 bits
+ pub const CALC_TAG_MASK: u64 = 0b111;
/// The high 63 bits
pub const CALC_PTR_MASK: u64 = u64::MAX ^ 0b111;
@@ -55,16 +57,16 @@ impl CompactLength {
Self(((val.to_bits() as u64) << 32) | Self::PERCENT_TAG)
}
- // /// A `calc()` value. The value passed here is treated as an opaque handle to
- // /// the actual calc representation and may be a pointer, index, etc.
- // ///
- // /// The low 3 bits are used as a tag value and will be returned as 0.
- // #[inline]
- // pub fn calc(ptr: *const ()) -> Self {
- // assert_ne!(ptr as u64, 0);
- // assert_eq!(ptr as u64 & Self::CALC_PTR_MASK, 0);
- // Self(ptr as u64 & Self::CALC_TAG)
- // }
+ /// A `calc()` value. The value passed here is treated as an opaque handle to
+ /// the actual calc representation and may be a pointer, index, etc.
+ ///
+ /// The low 3 bits are used as a tag value and will be returned as 0.
+ #[inline]
+ pub fn calc(ptr: *const ()) -> Self {
+ assert_ne!(ptr as u64, 0);
+ assert_eq!(ptr as u64 & 0b111, 0);
+ Self(ptr as u64 | Self::CALC_TAG)
+ }
/// The dimension should be automatically computed according to algorithm-specific rules
/// regarding the default size of boxes.
@@ -123,6 +125,12 @@ impl CompactLength {
Self(((limit.to_bits() as u64) << 32) | Self::FIT_CONTENT_PERCENT_TAG)
}
+ /// Get the primary tag
+ #[inline(always)]
+ pub const fn tag(self) -> u64 {
+ self.0 & Self::TAG_MASK
+ }
+
/// Get the numeric value associated with the `CompactLength`
/// (e.g. the pixel value for a LENGTH variant)
#[inline(always)]
@@ -130,10 +138,17 @@ impl CompactLength {
f32::from_bits((self.0 >> 32) as u32)
}
- /// Get the primary tag
+ /// Get the numeric value associated with the `CompactLength`
+ /// (e.g. the pixel value for a LENGTH variant)
#[inline(always)]
- pub const fn tag(self) -> u64 {
- self.0 & Self::TAG_MASK
+ pub const fn calc_value(self) -> u64 {
+ self.0
+ }
+
+ /// Returns true if the value is 0 px
+ #[inline(always)]
+ pub const fn is_calc(self) -> bool {
+ self.0 & Self::CALC_TAG_MASK == 0
}
/// Returns true if the value is 0 px
@@ -221,15 +236,16 @@ impl CompactLength {
#[inline(always)]
pub const fn uses_percentage(self) -> bool {
// TODO: handle calc() values
- matches!(self.tag(), CompactLength::PERCENT_TAG | CompactLength::FIT_CONTENT_PERCENT_TAG)
+ matches!(self.tag(), CompactLength::PERCENT_TAG | CompactLength::FIT_CONTENT_PERCENT_TAG) || self.is_calc()
}
/// Resolve percentage values against the passed parent_size, returning Some(value)
/// Non-percentage values always return None.
#[inline(always)]
- pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
+ pub fn resolved_percentage_size(self, parent_size: f32, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.tag() {
CompactLength::PERCENT_TAG => Some(self.value() * parent_size),
+ _ if self.is_calc() => Some(calc_resolver(self.0, parent_size)),
_ => None,
}
}
@@ -293,10 +309,18 @@ impl FromPercent for LengthPercentage {
}
}
impl LengthPercentage {
- /// Get the raw bit representation of the value
+ /// Get the underlying `CompactLength` representation of the value
pub fn into_raw(self) -> CompactLength {
self.0
}
+
+ /// Create a LengthPercentage from a raw `CompactLength`.
+ /// # Safety
+ /// CompactLength must represent a valid variant for LengthPercentage
+ #[allow(unsafe_code)]
+ pub unsafe fn from_raw(val: CompactLength) -> Self {
+ Self(val)
+ }
}
/// A unit of linear measurement
@@ -326,12 +350,6 @@ impl From<LengthPercentage> for LengthPercentageAuto {
Self(input.0)
}
}
-impl LengthPercentageAuto {
- /// Get the raw bit representation of the value
- pub fn into_raw(self) -> CompactLength {
- self.0
- }
-}
impl LengthPercentageAuto {
/// Returns:
@@ -339,11 +357,12 @@ impl LengthPercentageAuto {
/// - Some(resolved) using the provided context for Percent variants
/// - None for Auto variants
#[inline(always)]
- pub fn resolve_to_option(self, context: f32) -> Option<f32> {
+ pub fn resolve_to_option(self, context: f32, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.0.tag() {
CompactLength::LENGTH_TAG => Some(self.0.value()),
CompactLength::PERCENT_TAG => Some(context * self.0.value()),
CompactLength::AUTO_TAG => None,
+ _ if self.0.is_calc() => Some(calc_resolver(self.0.calc_value(), context)),
_ => unreachable!("LengthPercentageAuto values cannot be constructed with other tags"),
}
}
@@ -353,6 +372,19 @@ impl LengthPercentageAuto {
pub fn is_auto(self) -> bool {
self.0.is_auto()
}
+
+ /// Get the underlying `CompactLength` representation of the value
+ pub fn into_raw(self) -> CompactLength {
+ self.0
+ }
+
+ /// Create a LengthPercentageAuto from a raw `CompactLength`.
+ /// # Safety
+ /// CompactLength must represent a valid variant for LengthPercentageAuto
+ #[allow(unsafe_code)]
+ pub unsafe fn from_raw(val: CompactLength) -> Self {
+ Self(val)
+ }
}
/// A unit of linear measurement
@@ -403,10 +435,28 @@ impl Dimension {
self.0.is_auto()
}
- /// Get the raw bit representation of the value
+ /// Get the raw `CompactLength` tag
+ pub fn tag(self) -> u64 {
+ self.0.tag()
+ }
+
+ /// Get the raw `CompactLength` value for non-calc variants that have a numeric parameter
+ pub fn value(self) -> f32 {
+ self.0.value()
+ }
+
+ /// Get the underlying `CompactLength` representation of the value
pub fn into_raw(self) -> CompactLength {
self.0
}
+
+ /// Create a Dimension from a raw `CompactLength`.
+ /// # Safety
+ /// CompactLength must represent a valid variant for Dimension
+ #[allow(unsafe_code)]
+ pub unsafe fn from_raw(val: CompactLength) -> Self {
+ Self(val)
+ }
}
impl Rect<Dimension> {
diff --git a/src/style/grid.rs b/src/style/grid.rs
index 835ed7fe0..23ea1167d 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -1,5 +1,8 @@
//! Style types for CSS Grid layout
-use super::{AlignContent, AlignItems, AlignSelf, CompactLength, CoreStyle, JustifyContent, LengthPercentage, Style};
+use super::{
+ AlignContent, AlignItems, AlignSelf, CompactLength, CoreStyle, Dimension, JustifyContent, LengthPercentage,
+ LengthPercentageAuto, Style,
+};
use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine};
use crate::geometry::{AbsoluteAxis, AbstractAxis, Line, MinMax, Size};
use crate::style_helpers::*;
@@ -397,13 +400,36 @@ impl FromFr for MaxTrackSizingFunction {
Self(CompactLength::from_fr(fr))
}
}
+impl From<LengthPercentage> for MaxTrackSizingFunction {
+ fn from(input: LengthPercentage) -> Self {
+ Self(input.0)
+ }
+}
+impl From<LengthPercentageAuto> for MaxTrackSizingFunction {
+ fn from(input: LengthPercentageAuto) -> Self {
+ Self(input.0)
+ }
+}
+impl From<Dimension> for MaxTrackSizingFunction {
+ fn from(input: Dimension) -> Self {
+ Self(input.0)
+ }
+}
impl MaxTrackSizingFunction {
- /// Get the raw bit representation of the value
+ /// Get the underlying `CompactLength` representation of the value
pub fn into_raw(self) -> CompactLength {
self.0
}
+ /// Create a MaxTrackSizingFunction from a raw `CompactLength`.
+ /// # Safety
+ /// CompactLength must represent a valid variant for MaxTrackSizingFunction
+ #[allow(unsafe_code)]
+ pub unsafe fn from_raw(val: CompactLength) -> Self {
+ Self(val)
+ }
+
/// Returns true if the max track sizing function is `MinContent`, `MaxContent`, `FitContent` or `Auto`, else false.
#[inline(always)]
pub fn is_intrinsic(&self) -> bool {
@@ -454,14 +480,26 @@ impl MaxTrackSizingFunction {
self.0.is_max_or_fit_content()
}
+ /// Returns whether the value can be resolved using `Self::definite_value`
+ #[inline(always)]
+ pub fn has_definite_value(self, parent_size: Option<f32>) -> bool {
+ match self.0.tag() {
+ CompactLength::LENGTH_TAG => true,
+ CompactLength::PERCENT_TAG => parent_size.is_some(),
+ _ if self.0.is_calc() => parent_size.is_some(),
+ _ => false,
+ }
+ }
+
/// Returns fixed point values directly. Attempts to resolve percentage values against
/// the passed available_space and returns if this results in a concrete value (which it
/// will if the available_space is `Some`). Otherwise returns None.
#[inline(always)]
- pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
+ pub fn definite_value(self, parent_size: Option<f32>, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.0.tag() {
CompactLength::LENGTH_TAG => Some(self.0.value()),
CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
+ _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
_ => None,
}
}
@@ -473,19 +511,19 @@ impl MaxTrackSizingFunction {
/// - A fit-content sizing function with percentage argument (with definite available space)
/// All other kinds of track sizing function return None.
#[inline(always)]
- pub fn definite_limit(self, parent_size: Option<f32>) -> Option<f32> {
+ pub fn definite_limit(self, parent_size: Option<f32>, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.0.tag() {
CompactLength::FIT_CONTENT_PX_TAG => Some(self.0.value()),
CompactLength::FIT_CONTENT_PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
- _ => self.definite_value(parent_size),
+ _ => self.definite_value(parent_size, calc_resolver),
}
}
/// Resolve percentage values against the passed parent_size, returning Some(value)
/// Non-percentage values always return None.
#[inline(always)]
- pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
- self.0.resolved_percentage_size(parent_size)
+ pub fn resolved_percentage_size(self, parent_size: f32, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
+ self.0.resolved_percentage_size(parent_size, calc_resolver)
}
/// Whether the track sizing functions depends on the size of the parent node
@@ -530,13 +568,31 @@ impl From<LengthPercentage> for MinTrackSizingFunction {
Self(input.0)
}
}
+impl From<LengthPercentageAuto> for MinTrackSizingFunction {
+ fn from(input: LengthPercentageAuto) -> Self {
+ Self(input.0)
+ }
+}
+impl From<Dimension> for MinTrackSizingFunction {
+ fn from(input: Dimension) -> Self {
+ Self(input.0)
+ }
+}
impl MinTrackSizingFunction {
- /// Get the raw bit representation of the value
+ /// Get the underlying `CompactLength` representation of the value
pub fn into_raw(self) -> CompactLength {
self.0
}
+ /// Create a MinTrackSizingFunction from a raw `CompactLength`.
+ /// # Safety
+ /// CompactLength must represent a valid variant for MinTrackSizingFunction
+ #[allow(unsafe_code)]
+ pub unsafe fn from_raw(val: CompactLength) -> Self {
+ Self(val)
+ }
+
/// Returns true if the min track sizing function is `MinContent`, `MaxContent` or `Auto`, else false.
#[inline(always)]
pub fn is_intrinsic(&self) -> bool {
@@ -577,10 +633,11 @@ impl MinTrackSizingFunction {
/// the passed available_space and returns if this results in a concrete value (which it
/// will if the available_space is `Some`). Otherwise returns `None`.
#[inline(always)]
- pub fn definite_value(self, parent_size: Option<f32>) -> Option<f32> {
+ pub fn definite_value(self, parent_size: Option<f32>, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.0.tag() {
CompactLength::LENGTH_TAG => Some(self.0.value()),
CompactLength::PERCENT_TAG => parent_size.map(|size| self.0.value() * size),
+ _ if self.0.is_calc() => parent_size.map(|size| calc_resolver(self.0.calc_value(), size)),
_ => None,
}
}
@@ -588,14 +645,14 @@ impl MinTrackSizingFunction {
/// Resolve percentage values against the passed parent_size, returning Some(value)
/// Non-percentage values always return None.
#[inline(always)]
- pub fn resolved_percentage_size(self, parent_size: f32) -> Option<f32> {
- self.0.resolved_percentage_size(parent_size)
+ pub fn resolved_percentage_size(self, parent_size: f32, calc_resolver: impl Fn(u64, f32) -> f32) -> Option<f32> {
+ self.0.resolved_percentage_size(parent_size, calc_resolver)
}
/// Whether the track sizing functions depends on the size of the parent node
#[inline(always)]
pub fn uses_percentage(self) -> bool {
- matches!(self.0.tag(), CompactLength::PERCENT_TAG)
+ matches!(self.0.tag(), CompactLength::PERCENT_TAG) || self.0.is_calc()
}
}
@@ -652,9 +709,19 @@ impl FromFr for NonRepeatedTrackSizingFunction {
Self { min: MinTrackSizingFunction::AUTO, max: MaxTrackSizingFunction::from_fr(flex) }
}
}
-impl From<LengthPercentage> for MaxTrackSizingFunction {
+impl From<LengthPercentage> for NonRepeatedTrackSizingFunction {
fn from(input: LengthPercentage) -> Self {
- Self(input.0)
+ Self { min: input.into(), max: input.into() }
+ }
+}
+impl From<LengthPercentageAuto> for NonRepeatedTrackSizingFunction {
+ fn from(input: LengthPercentageAuto) -> Self {
+ Self { min: input.into(), max: input.into() }
+ }
+}
+impl From<Dimension> for NonRepeatedTrackSizingFunction {
+ fn from(input: Dimension) -> Self {
+ Self { min: input.into(), max: input.into() }
}
}
diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs
index 831226067..67666e691 100644
--- a/src/tree/taffy_tree.rs
+++ b/src/tree/taffy_tree.rs
@@ -335,6 +335,11 @@ where
self.taffy.nodes[node_id.into()].unrounded_layout = *layout;
}
+ #[inline(always)]
+ fn resolve_calc_value(&self, _val: u64, _basis: f32) -> f32 {
+ 0.0
+ }
+
#[inline(always)]
fn compute_child_layout(&mut self, node: NodeId, inputs: LayoutInput) -> LayoutOutput {
// If RunMode is PerformHiddenLayout then this indicates that an ancestor node is `Display::None`
@@ -379,7 +384,8 @@ where
let measure_function = |known_dimensions, available_space| {
(tree.measure_function)(known_dimensions, available_space, node, node_context, style)
};
- compute_leaf_layout(inputs, style, measure_function)
+ // TODO: implement calc() in high-level API
+ compute_leaf_layout(inputs, style, |_, _| 0.0, measure_function)
}
}
})
diff --git a/src/tree/traits.rs b/src/tree/traits.rs
index c59b28976..8837d3f18 100644
--- a/src/tree/traits.rs
+++ b/src/tree/traits.rs
@@ -180,6 +180,9 @@ pub trait LayoutPartialTree: TraversePartialTree {
/// Get core style
fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_>;
+ /// Resolve calc value
+ fn resolve_calc_value(&self, val: u64, basis: f32) -> f32;
+
/// Set the node's unrounded layout
fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout);
@@ -360,6 +363,12 @@ pub(crate) trait LayoutPartialTreeExt: LayoutPartialTree {
},
)
}
+
+ /// Alias to `resolve_calc_value` with a shorter function name
+ #[inline(always)]
+ fn calc(&self, val: u64, basis: f32) -> f32 {
+ self.resolve_calc_value(val, basis)
+ }
}
impl<T: LayoutPartialTree> LayoutPartialTreeExt for T {}
diff --git a/src/util/resolve.rs b/src/util/resolve.rs
index 3f9dc619c..e52861cec 100644
--- a/src/util/resolve.rs
+++ b/src/util/resolve.rs
@@ -12,7 +12,7 @@ use crate::CompactLength;
/// Will return a `None` if it unable to resolve.
pub trait MaybeResolve<In, Out> {
/// Resolve a dimension that might be dependent on a context, with `None` as fallback value
- fn maybe_resolve(self, context: In) -> Out;
+ fn maybe_resolve(self, context: In, calc: impl Fn(u64, f32) -> f32) -> Out;
}
/// Trait to encapsulate behaviour where we need to resolve from a
@@ -22,16 +22,17 @@ pub trait MaybeResolve<In, Out> {
/// Will return a default value if it unable to resolve.
pub trait ResolveOrZero<TContext, TOutput: TaffyZero> {
/// Resolve a dimension that might be dependent on a context, with a default fallback value
- fn resolve_or_zero(self, context: TContext) -> TOutput;
+ fn resolve_or_zero(self, context: TContext, calc: impl Fn(u64, f32) -> f32) -> TOutput;
}
impl MaybeResolve<Option<f32>, Option<f32>> for LengthPercentage {
/// Converts the given [`LengthPercentage`] into an absolute length
/// Can return `None`
- fn maybe_resolve(self, context: Option<f32>) -> Option<f32> {
+ fn maybe_resolve(self, context: Option<f32>, calc: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.0.tag() {
CompactLength::LENGTH_TAG => Some(self.0.value()),
CompactLength::PERCENT_TAG => context.map(|dim| dim * self.0.value()),
+ _ if self.0.is_calc() => context.map(|dim| calc(self.0.calc_value(), dim)),
_ => unreachable!(),
}
}
@@ -40,11 +41,12 @@ impl MaybeResolve<Option<f32>, Option<f32>> for LengthPercentage {
impl MaybeResolve<Option<f32>, Option<f32>> for LengthPercentageAuto {
/// Converts the given [`LengthPercentageAuto`] into an absolute length
/// Can return `None`
- fn maybe_resolve(self, context: Option<f32>) -> Option<f32> {
+ fn maybe_resolve(self, context: Option<f32>, calc: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.0.tag() {
+ CompactLength::AUTO_TAG => None,
CompactLength::LENGTH_TAG => Some(self.0.value()),
CompactLength::PERCENT_TAG => context.map(|dim| dim * self.0.value()),
- CompactLength::AUTO_TAG => None,
+ _ if self.0.is_calc() => context.map(|dim| calc(self.0.calc_value(), dim)),
_ => unreachable!(),
}
}
@@ -54,11 +56,12 @@ impl MaybeResolve<Option<f32>, Option<f32>> for Dimension {
/// Converts the given [`Dimension`] into an absolute length
///
/// Can return `None`
- fn maybe_resolve(self, context: Option<f32>) -> Option<f32> {
+ fn maybe_resolve(self, context: Option<f32>, calc: impl Fn(u64, f32) -> f32) -> Option<f32> {
match self.0.tag() {
+ CompactLength::AUTO_TAG => None,
CompactLength::LENGTH_TAG => Some(self.0.value()),
CompactLength::PERCENT_TAG => context.map(|dim| dim * self.0.value()),
- CompactLength::AUTO_TAG => None,
+ _ if self.0.is_calc() => context.map(|dim| calc(self.0.calc_value(), dim)),
_ => unreachable!(),
}
}
@@ -69,57 +72,63 @@ impl MaybeResolve<Option<f32>, Option<f32>> for Dimension {
impl<T: MaybeResolve<Option<f32>, Option<f32>>> MaybeResolve<f32, Option<f32>> for T {
/// Converts the given MaybeResolve value into an absolute length
/// Can return `None`
- fn maybe_resolve(self, context: f32) -> Option<f32> {
- self.maybe_resolve(Some(context))
+ fn maybe_resolve(self, context: f32, calc: impl Fn(u64, f32) -> f32) -> Option<f32> {
+ self.maybe_resolve(Some(context), calc)
}
}
// Generic MaybeResolve for Size
impl<In, Out, T: MaybeResolve<In, Out>> MaybeResolve<Size<In>, Size<Out>> for Size<T> {
/// Converts any `parent`-relative values for size into an absolute size
- fn maybe_resolve(self, context: Size<In>) -> Size<Out> {
- Size { width: self.width.maybe_resolve(context.width), height: self.height.maybe_resolve(context.height) }
+ fn maybe_resolve(self, context: Size<In>, calc: impl Fn(u64, f32) -> f32) -> Size<Out> {
+ Size {
+ width: self.width.maybe_resolve(context.width, &calc),
+ height: self.height.maybe_resolve(context.height, &calc),
+ }
}
}
impl ResolveOrZero<Option<f32>, f32> for LengthPercentage {
/// Will return a default value of result is evaluated to `None`
- fn resolve_or_zero(self, context: Option<f32>) -> f32 {
- self.maybe_resolve(context).unwrap_or(0.0)
+ fn resolve_or_zero(self, context: Option<f32>, calc: impl Fn(u64, f32) -> f32) -> f32 {
+ self.maybe_resolve(context, calc).unwrap_or(0.0)
}
}
impl ResolveOrZero<Option<f32>, f32> for LengthPercentageAuto {
/// Will return a default value of result is evaluated to `None`
- fn resolve_or_zero(self, context: Option<f32>) -> f32 {
- self.maybe_resolve(context).unwrap_or(0.0)
+ fn resolve_or_zero(self, context: Option<f32>, calc: impl Fn(u64, f32) -> f32) -> f32 {
+ self.maybe_resolve(context, calc).unwrap_or(0.0)
}
}
impl ResolveOrZero<Option<f32>, f32> for Dimension {
/// Will return a default value of result is evaluated to `None`
- fn resolve_or_zero(self, context: Option<f32>) -> f32 {
- self.maybe_resolve(context).unwrap_or(0.0)
+ fn resolve_or_zero(self, context: Option<f32>, calc: impl Fn(u64, f32) -> f32) -> f32 {
+ self.maybe_resolve(context, calc).unwrap_or(0.0)
}
}
// Generic ResolveOrZero for Size
impl<In, Out: TaffyZero, T: ResolveOrZero<In, Out>> ResolveOrZero<Size<In>, Size<Out>> for Size<T> {
/// Converts any `parent`-relative values for size into an absolute size
- fn resolve_or_zero(self, context: Size<In>) -> Size<Out> {
- Size { width: self.width.resolve_or_zero(context.width), height: self.height.resolve_or_zero(context.height) }
+ fn resolve_or_zero(self, context: Size<In>, calc: impl Fn(u64, f32) -> f32) -> Size<Out> {
+ Size {
+ width: self.width.resolve_or_zero(context.width, &calc),
+ height: self.height.resolve_or_zero(context.height, &calc),
+ }
}
}
// Generic ResolveOrZero for resolving Rect against Size
impl<In: Copy, Out: TaffyZero, T: ResolveOrZero<In, Out>> ResolveOrZero<Size<In>, Rect<Out>> for Rect<T> {
/// Converts any `parent`-relative values for Rect into an absolute Rect
- fn resolve_or_zero(self, context: Size<In>) -> Rect<Out> {
+ fn resolve_or_zero(self, context: Size<In>, calc: impl Fn(u64, f32) -> f32) -> Rect<Out> {
Rect {
- left: self.left.resolve_or_zero(context.width),
- right: self.right.resolve_or_zero(context.width),
- top: self.top.resolve_or_zero(context.height),
- bottom: self.bottom.resolve_or_zero(context.height),
+ left: self.left.resolve_or_zero(context.width, &calc),
+ right: self.right.resolve_or_zero(context.width, &calc),
+ top: self.top.resolve_or_zero(context.height, &calc),
+ bottom: self.bottom.resolve_or_zero(context.height, &calc),
}
}
}
@@ -127,12 +136,12 @@ impl<In: Copy, Out: TaffyZero, T: ResolveOrZero<In, Out>> ResolveOrZero<Size<In>
// Generic ResolveOrZero for resolving Rect against Option
impl<Out: TaffyZero, T: ResolveOrZero<Option<f32>, Out>> ResolveOrZero<Option<f32>, Rect<Out>> for Rect<T> {
/// Converts any `parent`-relative values for Rect into an absolute Rect
- fn resolve_or_zero(self, context: Option<f32>) -> Rect<Out> {
+ fn resolve_or_zero(self, context: Option<f32>, calc: impl Fn(u64, f32) -> f32) -> Rect<Out> {
Rect {
- left: self.left.resolve_or_zero(context),
- right: self.right.resolve_or_zero(context),
- top: self.top.resolve_or_zero(context),
- bottom: self.bottom.resolve_or_zero(context),
+ left: self.left.resolve_or_zero(context, &calc),
+ right: self.right.resolve_or_zero(context, &calc),
+ top: self.top.resolve_or_zero(context, &calc),
+ bottom: self.bottom.resolve_or_zero(context, &calc),
}
}
}
@@ -149,7 +158,7 @@ mod tests {
Lhs: MaybeResolve<Rhs, Out>,
Out: PartialEq + Debug,
{
- assert_eq!(input.maybe_resolve(context), expected);
+ assert_eq!(input.maybe_resolve(context, |_, _| 42.42), expected);
}
// ResolveOrZero test runner
@@ -158,7 +167,7 @@ mod tests {
Lhs: ResolveOrZero<Rhs, Out>,
Out: PartialEq + Debug + TaffyZero,
{
- assert_eq!(input.resolve_or_zero(context), expected);
+ assert_eq!(input.resolve_or_zero(context, |_, _| 42.42), expected);
}
mod maybe_resolve_dimension {