Semántico sayk'uy · 36
src/style.rs
- silq'uyninpi t'ikrakurqan struct Node pub
- silq'uyninpi t'ikrakurqan def resolve
diff --git a/src/algo.rs b/src/algo.rs
index f466c90d8..7e3209b5d 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -3,6 +3,10 @@ use std::f32;
use crate::layout;
use crate::style;
+use crate::number::MinMax;
+use crate::number::Number;
+use crate::number::Number::*;
+
#[derive(Debug, Copy, Clone)]
struct FlexSize {
width: f32,
@@ -25,31 +29,6 @@ impl FlexSize {
}
}
-// TODO - Temporary soltion. Will refactor to implement math function on Option<f32> instead
-// of relying on nan.
-trait SafeMath {
- fn safe_min(&self, rhs: f32) -> f32;
- fn safe_max(&self, rhs: f32) -> f32;
-}
-
-impl SafeMath for f32 {
- fn safe_min(&self, rhs: f32) -> f32 {
- if self.is_nan() {
- f32::NAN
- } else {
- self.min(rhs)
- }
- }
-
- fn safe_max(&self, rhs: f32) -> f32 {
- if self.is_nan() {
- f32::NAN
- } else {
- self.max(rhs)
- }
- }
-}
-
struct FlexItem<'a> {
node: &'a style::Node,
@@ -100,11 +79,11 @@ pub fn compute(root: &style::Node) -> layout::Node {
// Probably want to pass min/max down as top level paramerer instead.
let first_pass = compute_internal(
root,
- root.width.resolve(f32::NAN, f32::NAN),
- root.height.resolve(f32::NAN, f32::NAN),
- f32::NAN,
+ root.width.resolve(Undefined).unwrap_or(f32::NAN),
+ root.height.resolve(Undefined).unwrap_or(f32::NAN),
f32::NAN,
f32::NAN,
+ Undefined,
);
let result = compute_internal(
@@ -112,16 +91,18 @@ pub fn compute(root: &style::Node) -> layout::Node {
first_pass
.size
.width
- .max(root.min_width.resolve(f32::NAN, f32::NAN))
- .min(root.max_width.resolve(f32::NAN, f32::NAN)),
+ .maybe_max(root.min_width.resolve(Undefined))
+ .maybe_min(root.max_width.resolve(Undefined))
+ .unwrap_or(f32::NAN),
first_pass
.size
.height
- .max(root.min_height.resolve(f32::NAN, f32::NAN))
- .min(root.max_height.resolve(f32::NAN, f32::NAN)),
- f32::NAN,
+ .maybe_max(root.min_height.resolve(Undefined))
+ .maybe_min(root.max_height.resolve(Undefined))
+ .unwrap_or(f32::NAN),
f32::NAN,
f32::NAN,
+ Undefined,
);
round_layout(
@@ -178,7 +159,7 @@ fn compute_internal(
// This will always be the parent width except for the case when
// the child is in an absolute context. This value should only
// be used for calculated percentage values.
- percent_calc_base: f32,
+ percent_calc_base: Number,
) -> ComputeResult {
// Define some general constants we will need for the remainder
// of the algorithm.
@@ -193,38 +174,38 @@ fn compute_internal(
};
let (margin_main_start, margin_cross_start) = (
- node.main_margin_start(node.flex_direction).resolve(percent_calc_base, 0.0),
- node.cross_margin_start(node.flex_direction).resolve(percent_calc_base, 0.0),
+ node.main_margin_start(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
+ node.cross_margin_start(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
);
let (margin_main_end, margin_cross_end) = (
- node.main_margin_end(node.flex_direction).resolve(percent_calc_base, 0.0),
- node.cross_margin_end(node.flex_direction).resolve(percent_calc_base, 0.0),
+ node.main_margin_end(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
+ node.cross_margin_end(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
);
let (margin_main, margin_cross) = (margin_main_start + margin_main_end, margin_cross_start + margin_cross_end);
let (padding_main_start, padding_cross_start) = (
- node.main_padding_start(node.flex_direction).resolve(percent_calc_base, 0.0),
- node.cross_padding_start(node.flex_direction).resolve(percent_calc_base, 0.0),
+ node.main_padding_start(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
+ node.cross_padding_start(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
);
let (padding_main_end, padding_cross_end) = (
- node.main_padding_end(node.flex_direction).resolve(percent_calc_base, 0.0),
- node.cross_padding_end(node.flex_direction).resolve(percent_calc_base, 0.0),
+ node.main_padding_end(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
+ node.cross_padding_end(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
);
let (padding_main, padding_cross) =
(padding_main_start + padding_main_end, padding_cross_start + padding_cross_end);
let (border_main_start, border_cross_start) = (
- node.main_border_start(node.flex_direction).resolve(percent_calc_base, 0.0),
- node.cross_border_start(node.flex_direction).resolve(percent_calc_base, 0.0),
+ node.main_border_start(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
+ node.cross_border_start(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
);
let (border_main_end, border_cross_end) = (
- node.main_border_end(node.flex_direction).resolve(percent_calc_base, 0.0),
- node.cross_border_end(node.flex_direction).resolve(percent_calc_base, 0.0),
+ node.main_border_end(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
+ node.cross_border_end(node.flex_direction).resolve(percent_calc_base).unwrap_or(0.0),
);
let (border_main, border_cross) = (border_main_start + border_main_end, border_cross_start + border_cross_end);
@@ -234,7 +215,8 @@ fn compute_internal(
let wrap_reverse = node.flex_wrap == style::FlexWrap::WrapReverse;
- let percent_calc_base_child = if node.flex_direction.is_row() { node_inner_main } else { node_inner_cross };
+ let percent_calc_base_child =
+ Number::from_f32(if node.flex_direction.is_row() { node_inner_main } else { node_inner_cross });
// 9.2. Line Length Determination
@@ -296,7 +278,7 @@ fn compute_internal(
for child in &mut flex_items {
// A. If the item has a definite used flex basis, that’s the flex base size.
- let flex_basis = child.node.flex_basis.resolve(percent_calc_base_child, f32::NAN);
+ let flex_basis = child.node.flex_basis.resolve(percent_calc_base_child).unwrap_or(f32::NAN);
if flex_basis.is_finite() {
child.flex_basis = flex_basis;
continue;
@@ -307,7 +289,7 @@ fn compute_internal(
// then the flex base size is calculated from its inner
// cross size and the flex item’s intrinsic aspect ratio.
- if let Some(ratio) = child.node.aspect_ratio {
+ if let Defined(ratio) = child.node.aspect_ratio {
if node_cross.is_finite() && child.node.flex_basis == style::Dimension::Auto {
child.flex_basis = ratio * node_cross;
continue;
@@ -342,23 +324,23 @@ fn compute_internal(
// child
// .node
// .width
- // .resolve(percent_calc_base_child, f32::NAN)
- // .safe_max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
- // .safe_min(child.node.max_width.resolve(percent_calc_base_child, f32::NAN)),
+ // .resolve(percent_calc_base_child).unwrap_or(f32::NAN)
+ // .safe_max(child.node.min_width.resolve(percent_calc_base_child).unwrap_or(f32::NAN))
+ // .safe_min(child.node.max_width.resolve(percent_calc_base_child).unwrap_or(f32::NAN)),
// child
// .node
// .height
- // .resolve(percent_calc_base_child, f32::NAN)
- // .safe_max(child.node.min_height.resolve(percent_calc_base_child, f32::NAN))
- // .safe_min(child.node.max_height.resolve(percent_calc_base_child, f32::NAN)),
+ // .resolve(percent_calc_base_child).unwrap_or(f32::NAN)
+ // .safe_max(child.node.min_height.resolve(percent_calc_base_child).unwrap_or(f32::NAN))
+ // .safe_min(child.node.max_height.resolve(percent_calc_base_child).unwrap_or(f32::NAN)),
// if node.flex_direction.is_row() { available_main } else { available_cross },
// if node.flex_direction.is_row() { available_cross } else { available_main },
// percent_calc_base_child,
// ).size;
// child.flex_basis = size.main(node.flex_direction)
- // .max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- // .min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN));
+ // .max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(f32::NAN))
+ // .min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(f32::NAN));
// continue;
// }
@@ -374,15 +356,17 @@ fn compute_internal(
child
.node
.width
- .resolve(percent_calc_base_child, f32::NAN)
- .safe_max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
- .safe_min(child.node.max_width.resolve(percent_calc_base_child, f32::NAN)),
+ .resolve(percent_calc_base_child)
+ .maybe_max(child.node.min_width.resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_width.resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN),
child
.node
.height
- .resolve(percent_calc_base_child, f32::NAN)
- .safe_max(child.node.min_height.resolve(percent_calc_base_child, f32::NAN))
- .safe_min(child.node.max_height.resolve(percent_calc_base_child, f32::NAN)),
+ .resolve(percent_calc_base_child)
+ .maybe_max(child.node.min_height.resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_height.resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN),
if node.flex_direction.is_row() { available_main } else { available_cross },
if node.flex_direction.is_row() { available_cross } else { available_main },
percent_calc_base_child,
@@ -391,18 +375,23 @@ fn compute_internal(
child.flex_basis = size
.main(node.flex_direction)
- .max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN));
+ .maybe_max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN);
}
// The hypothetical main size is the item’s flex base size clamped according to its
// used min and max main sizes (and flooring the content box size at zero).
for child in &mut flex_items {
- let padding_start = child.node.main_padding_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
- let padding_end = child.node.main_padding_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
- let border_start = child.node.main_border_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
- let border_end = child.node.main_border_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ let padding_start =
+ child.node.main_padding_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
+ let padding_end =
+ child.node.main_padding_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
+ let border_start =
+ child.node.main_border_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
+ let border_end =
+ child.node.main_border_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
child.inner_flex_basis = child.flex_basis - (padding_start + padding_end + border_start + border_end);
// TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
@@ -420,21 +409,21 @@ fn compute_internal(
)
.size
.width
- .min(child.node.width.resolve(percent_calc_base_child, f32::NAN))
- .max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
+ .maybe_min(child.node.width.resolve(percent_calc_base_child))
+ .maybe_max(child.node.min_width.resolve(percent_calc_base_child))
} else {
- child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN)
+ child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child)
};
child.hypothetical_inner_main_size = child
.flex_basis
- .safe_max(min_main)
- .safe_min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .max(0.0);
+ .maybe_max(min_main)
+ .maybe_min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(0.0);
child.hypothetical_outer_main_size = child.hypothetical_inner_main_size
- + child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ + child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
}
// 9.3. Main Size Determination
@@ -512,23 +501,26 @@ fn compute_internal(
child
.node
.width
- .resolve(percent_calc_base_child, f32::NAN)
- .safe_max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
- .safe_min(child.node.max_width.resolve(percent_calc_base_child, f32::NAN)),
+ .resolve(percent_calc_base_child)
+ .maybe_max(child.node.min_width.resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_width.resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN),
child
.node
.height
- .resolve(percent_calc_base_child, f32::NAN)
- .safe_max(child.node.min_height.resolve(percent_calc_base_child, f32::NAN))
- .safe_min(child.node.max_height.resolve(percent_calc_base_child, f32::NAN)),
+ .resolve(percent_calc_base_child)
+ .maybe_max(child.node.min_height.resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_height.resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN),
if node.flex_direction.is_row() { available_main } else { available_cross },
if node.flex_direction.is_row() { available_cross } else { available_main },
percent_calc_base_child,
)
.size
.main(node.flex_direction)
- .max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN));
+ .maybe_max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN);
} else {
child.target_main_size = child.hypothetical_inner_main_size;
}
@@ -537,8 +529,8 @@ fn compute_internal(
// that casues the target_main_size to never be set for some items
child.outer_target_main_size = child.target_main_size
- + child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ + child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
if (child.node.flex_grow == 0.0 && child.node.flex_shrink == 0.0)
|| (growing && child.flex_basis > child.hypothetical_inner_main_size)
@@ -556,8 +548,8 @@ fn compute_internal(
.items
.iter()
.map(|child| {
- child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0)
+ child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ if child.frozen { child.target_main_size } else { child.flex_basis }
})
.sum();
@@ -593,8 +585,12 @@ fn compute_internal(
let used_space: f32 = Iterator::chain(frozen.iter(), unfrozen.iter())
.map(|child| {
- child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0)
+ child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ + child
+ .node
+ .main_margin_end(node.flex_direction)
+ .resolve(percent_calc_base_child)
+ .unwrap_or(0.0)
+ if child.frozen { child.target_main_size } else { child.flex_basis }
})
.sum();
@@ -670,21 +666,22 @@ fn compute_internal(
)
.size
.width
- .min(child.node.width.resolve(percent_calc_base_child, f32::NAN))
- .max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
+ .maybe_min(child.node.width.resolve(percent_calc_base_child))
+ .maybe_max(child.node.min_width.resolve(percent_calc_base_child))
} else {
- child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN)
+ child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child)
};
- let max_main = child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN);
+ let max_main = child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child);
- let clamped = child.target_main_size.safe_min(max_main).safe_max(min_main).max(0.0);
+ let clamped =
+ child.target_main_size.maybe_min(max_main).maybe_max(min_main).maybe_max(0.0).unwrap_or(0.0);
child.violation = clamped - child.target_main_size;
total_violation += child.violation;
child.target_main_size = clamped;
child.outer_target_main_size = child.target_main_size
- + child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ + child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
}
// e. Freeze over-flexed items. The total violation is the sum of the adjustments
@@ -746,9 +743,10 @@ fn compute_internal(
let child_cross = child
.node
.cross_size(node.flex_direction)
- .resolve(percent_calc_base_child, f32::NAN)
- .safe_max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .safe_min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN));
+ .resolve(percent_calc_base_child)
+ .maybe_max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN);
let size = compute_internal(
child.node,
@@ -762,13 +760,13 @@ fn compute_internal(
child.hypothetical_inner_cross_size = size
.cross(node.flex_direction)
- .safe_max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .safe_min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .max(0.0);
+ .maybe_max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(0.0);
child.hypothetical_outer_cross_size = child.hypothetical_inner_cross_size
- + child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- + child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ + child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ + child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
}
}
@@ -903,17 +901,22 @@ fn compute_internal(
&& child.node.cross_size(node.flex_direction) == style::Dimension::Auto
{
(line.cross_size
- - child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- - child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0))
- .safe_max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .safe_min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
+ - child
+ .node
+ .cross_margin_start(node.flex_direction)
+ .resolve(percent_calc_base_child)
+ .unwrap_or(0.0)
+ - child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0))
+ .maybe_max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .maybe_min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN)
} else {
child.hypothetical_inner_cross_size
};
child.outer_target_cross_size = child.target_cross_size
- + child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- + child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ + child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0)
+ + child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
}
}
@@ -932,9 +935,9 @@ fn compute_internal(
// TODO does not make a ton of sense to have this here but we want to have this somewhere.
for child in &mut line.items {
child.main_margin_start =
- child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
child.main_margin_end =
- child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
}
let mut num_auto_margins = 0;
@@ -1031,9 +1034,9 @@ fn compute_internal(
for child in &mut line.items {
// TODO probably move this somewhere else, as with main margin resolution. Only auto margins should be resolved here.
child.cross_margin_start =
- child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
child.cross_margin_end =
- child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+ child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child).unwrap_or(0.0);
let free_space = line.cross_size - child.outer_target_cross_size;
@@ -1158,7 +1161,8 @@ fn compute_internal(
}
// Do a final layout pass and gather the resulting layouts
- let percent_calc_base_child = if node.flex_direction.is_row() { container_main_size } else { container_cross_size };
+ let percent_calc_base_child =
+ Number::from_f32(if node.flex_direction.is_row() { container_main_size } else { container_cross_size });
let mut children: Vec<layout::Node> = {
let mut lines: Vec<Vec<layout::Node>> = vec![];
@@ -1185,8 +1189,16 @@ fn compute_internal(
total_offset_main
+ child.offset_main
+ child.main_margin_start
- + (child.node.main_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- - child.node.main_end(node.flex_direction).resolve(percent_calc_base_child, 0.0))
+ + (child
+ .node
+ .main_start(node.flex_direction)
+ .resolve(percent_calc_base_child)
+ .unwrap_or(0.0)
+ - child
+ .node
+ .main_end(node.flex_direction)
+ .resolve(percent_calc_base_child)
+ .unwrap_or(0.0))
};
let offset_cross = {
@@ -1194,8 +1206,16 @@ fn compute_internal(
+ child.offset_cross
+ line_offset_cross
+ child.cross_margin_start
- + (child.node.cross_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
- - child.node.cross_end(node.flex_direction).resolve(percent_calc_base_child, 0.0))
+ + (child
+ .node
+ .cross_start(node.flex_direction)
+ .resolve(percent_calc_base_child)
+ .unwrap_or(0.0)
+ - child
+ .node
+ .cross_end(node.flex_direction)
+ .resolve(percent_calc_base_child)
+ .unwrap_or(0.0))
};
children.push(layout::Node {
@@ -1251,27 +1271,34 @@ fn compute_internal(
node.children.iter().filter(|child| child.position == style::Position::Absolute).collect();
for child in absolute_children {
- let start =
- child.start.resolve(container_width, f32::NAN) + child.margin.start.resolve(container_width, f32::NAN);
- let end = child.end.resolve(container_width, f32::NAN) + child.margin.end.resolve(container_width, f32::NAN);
- let top = child.top.resolve(container_height, f32::NAN) + child.margin.top.resolve(container_height, f32::NAN);
- let bottom =
- child.bottom.resolve(container_height, f32::NAN) + child.margin.bottom.resolve(container_height, f32::NAN);
+ let width_percent_calc = Number::from_f32(container_width);
+ let height_percent_calc = Number::from_f32(container_height);
+
+ let start = child.start.resolve(width_percent_calc).unwrap_or(f32::NAN)
+ + child.margin.start.resolve(width_percent_calc).unwrap_or(f32::NAN);
+ let end = child.end.resolve(width_percent_calc).unwrap_or(f32::NAN)
+ + child.margin.end.resolve(width_percent_calc).unwrap_or(f32::NAN);
+ let top = child.top.resolve(height_percent_calc).unwrap_or(f32::NAN)
+ + child.margin.top.resolve(height_percent_calc).unwrap_or(f32::NAN);
+ let bottom = child.bottom.resolve(height_percent_calc).unwrap_or(f32::NAN)
+ + child.margin.bottom.resolve(height_percent_calc).unwrap_or(f32::NAN);
let (start_main, end_main) = if node.flex_direction.is_row() { (start, end) } else { (top, bottom) };
let (start_cross, end_cross) = if node.flex_direction.is_row() { (top, bottom) } else { (start, end) };
let child_width = child
.width
- .resolve(container_width, f32::NAN)
- .safe_max(child.min_width.resolve(container_width, f32::NAN))
- .safe_min(child.max_width.resolve(container_width, f32::NAN));
+ .resolve(width_percent_calc)
+ .maybe_max(child.min_width.resolve(width_percent_calc))
+ .maybe_min(child.max_width.resolve(width_percent_calc))
+ .unwrap_or(f32::NAN);
let child_height = child
.height
- .resolve(container_height, f32::NAN)
- .safe_max(child.min_height.resolve(container_height, f32::NAN))
- .safe_min(child.max_height.resolve(container_height, f32::NAN));
+ .resolve(height_percent_calc)
+ .maybe_max(child.min_height.resolve(height_percent_calc))
+ .maybe_min(child.max_height.resolve(height_percent_calc))
+ .unwrap_or(f32::NAN);
let width = if child_width.is_finite() { child_width } else { container_width - start - end };
@@ -1283,21 +1310,23 @@ fn compute_internal(
height,
if node.flex_direction.is_row() { container_main_size } else { container_cross_size },
if node.flex_direction.is_row() { container_cross_size } else { container_main_size },
- container_main_size,
+ width_percent_calc,
);
let free_main_space = container_main_size
- result
.size
.main(node.flex_direction)
- .max(child.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .min(child.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN));
+ .maybe_max(child.min_main_size(node.flex_direction).resolve(percent_calc_base_child))
+ .maybe_min(child.max_main_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN);
let free_cross_space = container_cross_size
- result
.size
.cross(node.flex_direction)
- .max(child.min_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN))
- .min(child.max_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN));
+ .maybe_max(child.min_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .maybe_min(child.max_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+ .unwrap_or(f32::NAN);
let offset_main = if start_main.is_finite() {
start_main + border_main_start
diff --git a/src/lib.rs b/src/lib.rs
index 8580b02d7..c14d15171 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,5 @@
pub mod layout;
+pub mod number;
pub mod style;
mod algo;
diff --git a/src/number.rs b/src/number.rs
new file mode 100644
index 000000000..df99196cc
--- /dev/null
+++ b/src/number.rs
@@ -0,0 +1,196 @@
+use std::ops;
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Number {
+ Defined(f32),
+ Undefined,
+}
+
+impl Default for Number {
+ fn default() -> Number {
+ Number::Undefined
+ }
+}
+
+impl Number {
+ pub fn unwrap_or(self, default: f32) -> f32 {
+ match self {
+ Number::Defined(val) => val,
+ Number::Undefined => default,
+ }
+ }
+
+ pub fn is_defined(self) -> bool {
+ match self {
+ Number::Defined(_) => true,
+ Number::Undefined => false,
+ }
+ }
+
+ pub fn from_f32(from: f32) -> Number {
+ if from.is_nan() {
+ Number::Undefined
+ } else {
+ Number::Defined(from)
+ }
+ }
+}
+
+pub trait MinMax<T> {
+ fn maybe_min(self, rhs: T) -> Number;
+ fn maybe_max(self, rhs: T) -> Number;
+}
+
+impl MinMax<Number> for Number {
+ fn maybe_min(self, rhs: Number) -> Number {
+ match self {
+ Number::Defined(val) => match rhs {
+ Number::Defined(other) => Number::Defined(val.min(other)),
+ Number::Undefined => self,
+ },
+ Number::Undefined => Number::Undefined,
+ }
+ }
+
+ fn maybe_max(self, rhs: Number) -> Number {
+ match self {
+ Number::Defined(val) => match rhs {
+ Number::Defined(other) => Number::Defined(val.max(other)),
+ Number::Undefined => self,
+ },
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl MinMax<f32> for Number {
+ fn maybe_min(self, rhs: f32) -> Number {
+ match self {
+ Number::Defined(val) => Number::Defined(val.min(rhs)),
+ Number::Undefined => Number::Undefined,
+ }
+ }
+
+ fn maybe_max(self, rhs: f32) -> Number {
+ match self {
+ Number::Defined(val) => Number::Defined(val.max(rhs)),
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl MinMax<Number> for f32 {
+ fn maybe_min(self, rhs: Number) -> Number {
+ match rhs {
+ Number::Defined(val) => Number::Defined(self.min(val)),
+ Number::Undefined => Number::Defined(self),
+ }
+ }
+
+ fn maybe_max(self, rhs: Number) -> Number {
+ match rhs {
+ Number::Defined(val) => Number::Defined(self.max(val)),
+ Number::Undefined => Number::Defined(self),
+ }
+ }
+}
+
+impl ops::Add<f32> for Number {
+ type Output = Number;
+
+ fn add(self, rhs: f32) -> Number {
+ match self {
+ Number::Defined(val) => Number::Defined(val + rhs),
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl ops::Add<Number> for Number {
+ type Output = Number;
+
+ fn add(self, rhs: Number) -> Number {
+ match self {
+ Number::Defined(val) => match rhs {
+ Number::Defined(other) => Number::Defined(val + other),
+ Number::Undefined => self,
+ },
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl ops::Sub<f32> for Number {
+ type Output = Number;
+
+ fn sub(self, rhs: f32) -> Number {
+ match self {
+ Number::Defined(val) => Number::Defined(val - rhs),
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl ops::Sub<Number> for Number {
+ type Output = Number;
+
+ fn sub(self, rhs: Number) -> Number {
+ match self {
+ Number::Defined(val) => match rhs {
+ Number::Defined(other) => Number::Defined(val - other),
+ Number::Undefined => self,
+ },
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl ops::Mul<f32> for Number {
+ type Output = Number;
+
+ fn mul(self, rhs: f32) -> Number {
+ match self {
+ Number::Defined(val) => Number::Defined(val * rhs),
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl ops::Mul<Number> for Number {
+ type Output = Number;
+
+ fn mul(self, rhs: Number) -> Number {
+ match self {
+ Number::Defined(val) => match rhs {
+ Number::Defined(other) => Number::Defined(val * other),
+ Number::Undefined => self,
+ },
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl ops::Div<f32> for Number {
+ type Output = Number;
+
+ fn div(self, rhs: f32) -> Number {
+ match self {
+ Number::Defined(val) => Number::Defined(val / rhs),
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
+
+impl ops::Div<Number> for Number {
+ type Output = Number;
+
+ fn div(self, rhs: Number) -> Number {
+ match self {
+ Number::Defined(val) => match rhs {
+ Number::Defined(other) => Number::Defined(val / other),
+ Number::Undefined => self,
+ },
+ Number::Undefined => Number::Undefined,
+ }
+ }
+}
diff --git a/src/style.rs b/src/style.rs
index 93d5b4ba8..de06eb6d0 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -1,3 +1,5 @@
+use crate::number::Number;
+
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AlignItems {
FlexStart,
@@ -166,11 +168,11 @@ impl Default for Dimension {
}
impl Dimension {
- pub(crate) fn resolve(&self, parent_width: f32, auto_size: f32) -> f32 {
+ pub(crate) fn resolve(&self, parent_width: Number) -> Number {
match self {
- Dimension::Points(points) => *points,
- Dimension::Percent(percent) if parent_width.is_finite() => percent * parent_width,
- _ => auto_size,
+ Dimension::Points(points) => Number::Defined(*points),
+ Dimension::Percent(percent) => parent_width * *percent,
+ _ => Number::Undefined,
}
}
}
@@ -230,7 +232,7 @@ pub struct Node {
pub min_height: Dimension,
pub max_height: Dimension,
- pub aspect_ratio: Option<f32>,
+ pub aspect_ratio: Number,
pub children: Vec<Node>,
}