Implement §9.9.1. Flex Container Intrinsic Main Sizes (#354)
* Add intrinsic sizing main size row test
* Resolve flexbox container percentages against parent_size not known_dimensions
* Flexbox: Do single pass layout if both dimensions are known either via passed-in known_dimensions or min/max/preferred styles
* Add documentation to resolve_flexible_lengths function
* Make padding_border adjustment consistent in determine_available_space
* Optimise flex-line packing
* Don't subtract margin in compute_constants as width style defines border-box not margin-box
* When sizing a wrapping flex-container under a min-content constraint, put each item on it's own line
* Remove space character from intrinsic_sizing_main_size_row test
* Add another reduced percentage complex test
* Convert simple_child test to a gentest
* Implement §9.9.1 "Flex Container Intrinsic Main Sizes"
* Remove unused variables
* Add additional main size intrinsic sizing tests
* Add intrinsic cross sizing test
* Fix clippy lints
* Only set outer_target_size for frozen children
* Remove commented out code
* Apply aspect ratio in flexbox algorthims top-level compute function
bf3dfaec9e387a7e67408fc78ca869d7eaaa8e1f · por Nico Burns · 2023-02-07T18:09:12Z (hace 3 años) · padre baf028789 · ver el árbol en este commit
Delta semántico · 69
benches/generated/intrinsic_sizing_cross_size_column.rs
benches/generated/intrinsic_sizing_main_size_column.rs
benches/generated/intrinsic_sizing_main_size_column_nested.rs
benches/generated/intrinsic_sizing_main_size_column_wrap.rs
benches/generated/intrinsic_sizing_main_size_row.rs
benches/generated/intrinsic_sizing_main_size_row_nested.rs
benches/generated/intrinsic_sizing_main_size_row_wrap.rs
benches/generated/percentage_moderate_complexity2.rs
benches/generated/simple_child.rs
tests/generated/intrinsic_sizing_cross_size_column.rs
tests/generated/intrinsic_sizing_main_size_column.rs
tests/generated/intrinsic_sizing_main_size_column_nested.rs
tests/generated/intrinsic_sizing_main_size_column_wrap.rs
tests/generated/intrinsic_sizing_main_size_row.rs
tests/generated/intrinsic_sizing_main_size_row_nested.rs
tests/generated/intrinsic_sizing_main_size_row_wrap.rs
tests/generated/percentage_moderate_complexity2.rs
tests/generated/simple_child.rs
diff --git a/benches/generated/intrinsic_sizing_cross_size_column.rs b/benches/generated/intrinsic_sizing_cross_size_column.rs
new file mode 100644
index 000000000..9836059d5
--- /dev/null
+++ b/benches/generated/intrinsic_sizing_cross_size_column.rs
@@ -0,0 +1,21 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/intrinsic_sizing_main_size_column.rs b/benches/generated/intrinsic_sizing_main_size_column.rs
new file mode 100644
index 000000000..97c76fc94
--- /dev/null
+++ b/benches/generated/intrinsic_sizing_main_size_column.rs
@@ -0,0 +1,21 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/intrinsic_sizing_main_size_column_nested.rs b/benches/generated/intrinsic_sizing_main_size_column_nested.rs
new file mode 100644
index 000000000..3b1fe8549
--- /dev/null
+++ b/benches/generated/intrinsic_sizing_main_size_column_nested.rs
@@ -0,0 +1,27 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ &[node0],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/intrinsic_sizing_main_size_column_wrap.rs b/benches/generated/intrinsic_sizing_main_size_column_wrap.rs
new file mode 100644
index 000000000..27527e811
--- /dev/null
+++ b/benches/generated/intrinsic_sizing_main_size_column_wrap.rs
@@ -0,0 +1,46 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node1 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ flex_direction: taffy::style::FlexDirection::Column,
+ flex_wrap: taffy::style::FlexWrap::Wrap,
+ ..Default::default()
+ },
+ &[node0, node1],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/intrinsic_sizing_main_size_row.rs b/benches/generated/intrinsic_sizing_main_size_row.rs
new file mode 100644
index 000000000..619d54ce3
--- /dev/null
+++ b/benches/generated/intrinsic_sizing_main_size_row.rs
@@ -0,0 +1,21 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/intrinsic_sizing_main_size_row_nested.rs b/benches/generated/intrinsic_sizing_main_size_row_nested.rs
new file mode 100644
index 000000000..e1087b04e
--- /dev/null
+++ b/benches/generated/intrinsic_sizing_main_size_row_nested.rs
@@ -0,0 +1,22 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/intrinsic_sizing_main_size_row_wrap.rs b/benches/generated/intrinsic_sizing_main_size_row_wrap.rs
new file mode 100644
index 000000000..fb2a580a0
--- /dev/null
+++ b/benches/generated/intrinsic_sizing_main_size_row_wrap.rs
@@ -0,0 +1,42 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node1 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style { flex_wrap: taffy::style::FlexWrap::Wrap, ..Default::default() },
+ &[node0, node1],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/mod.rs b/benches/generated/mod.rs
index fdc984b80..611172882 100644
--- a/benches/generated/mod.rs
+++ b/benches/generated/mod.rs
@@ -698,6 +698,13 @@ mod grid_span_2_min_content_min_content_indefinite;
mod grid_span_6_all_non_flex_indefinite;
#[cfg(feature = "grid")]
mod grid_span_8_all_track_types_indefinite;
+mod intrinsic_sizing_cross_size_column;
+mod intrinsic_sizing_main_size_column;
+mod intrinsic_sizing_main_size_column_nested;
+mod intrinsic_sizing_main_size_column_wrap;
+mod intrinsic_sizing_main_size_row;
+mod intrinsic_sizing_main_size_row_nested;
+mod intrinsic_sizing_main_size_row_wrap;
mod justify_content_column_center;
mod justify_content_column_flex_end;
mod justify_content_column_flex_start;
@@ -815,6 +822,7 @@ mod percentage_flex_basis_main_min_width;
mod percentage_main_max_height;
mod percentage_margin_should_calculate_based_only_on_width;
mod percentage_moderate_complexity;
+mod percentage_moderate_complexity2;
mod percentage_multiple_nested_with_padding_margin_and_percentage_values;
mod percentage_padding_should_calculate_based_only_on_width;
mod percentage_position_bottom_right;
@@ -836,6 +844,7 @@ mod rounding_fractial_input_4;
mod rounding_inner_node_controversy_vertical;
mod rounding_total_fractial;
mod rounding_total_fractial_nested;
+mod simple_child;
mod single_flex_child_after_absolute_child;
mod size_defined_by_child;
mod size_defined_by_child_with_border;
@@ -1509,6 +1518,13 @@ fn benchmark(c: &mut Criterion) {
grid_span_6_all_non_flex_indefinite::compute();
#[cfg(feature = "grid")]
grid_span_8_all_track_types_indefinite::compute();
+ intrinsic_sizing_cross_size_column::compute();
+ intrinsic_sizing_main_size_column::compute();
+ intrinsic_sizing_main_size_column_nested::compute();
+ intrinsic_sizing_main_size_column_wrap::compute();
+ intrinsic_sizing_main_size_row::compute();
+ intrinsic_sizing_main_size_row_nested::compute();
+ intrinsic_sizing_main_size_row_wrap::compute();
justify_content_column_center::compute();
justify_content_column_flex_end::compute();
justify_content_column_flex_start::compute();
@@ -1626,6 +1642,7 @@ fn benchmark(c: &mut Criterion) {
percentage_main_max_height::compute();
percentage_margin_should_calculate_based_only_on_width::compute();
percentage_moderate_complexity::compute();
+ percentage_moderate_complexity2::compute();
percentage_multiple_nested_with_padding_margin_and_percentage_values::compute();
percentage_padding_should_calculate_based_only_on_width::compute();
percentage_position_bottom_right::compute();
@@ -1647,6 +1664,7 @@ fn benchmark(c: &mut Criterion) {
rounding_inner_node_controversy_vertical::compute();
rounding_total_fractial::compute();
rounding_total_fractial_nested::compute();
+ simple_child::compute();
single_flex_child_after_absolute_child::compute();
size_defined_by_child::compute();
size_defined_by_child_with_border::compute();
diff --git a/benches/generated/percentage_moderate_complexity2.rs b/benches/generated/percentage_moderate_complexity2.rs
new file mode 100644
index 000000000..1e1e0a24f
--- /dev/null
+++ b/benches/generated/percentage_moderate_complexity2.rs
@@ -0,0 +1,44 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node00 = taffy
+ .new_leaf(taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(20f32),
+ height: taffy::style::Dimension::Points(20f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node0 = taffy
+ .new_with_children(
+ taffy::style::Style {
+ flex_direction: taffy::style::FlexDirection::Column,
+ size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.5f32), height: auto() },
+ padding: taffy::geometry::Rect {
+ left: taffy::style::LengthPercentage::Percent(0.1f32),
+ right: taffy::style::LengthPercentage::Percent(0.1f32),
+ top: taffy::style::LengthPercentage::Percent(0.1f32),
+ bottom: taffy::style::LengthPercentage::Percent(0.1f32),
+ },
+ ..Default::default()
+ },
+ &[node00],
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ flex_direction: taffy::style::FlexDirection::Column,
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(200f32),
+ height: taffy::style::Dimension::Points(200f32),
+ },
+ ..Default::default()
+ },
+ &[node0],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/benches/generated/simple_child.rs b/benches/generated/simple_child.rs
new file mode 100644
index 000000000..d2c79e814
--- /dev/null
+++ b/benches/generated/simple_child.rs
@@ -0,0 +1,72 @@
+pub fn compute() {
+ #[allow(unused_imports)]
+ use taffy::prelude::*;
+ let mut taffy = taffy::Taffy::new();
+ let node000 = taffy
+ .new_leaf(taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node00 = taffy
+ .new_with_children(
+ taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ },
+ &[node000],
+ )
+ .unwrap();
+ let node010 = taffy
+ .new_leaf(taffy::style::Style {
+ align_self: Some(taffy::style::AlignSelf::Center),
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node011 = taffy
+ .new_leaf(taffy::style::Style {
+ align_self: Some(taffy::style::AlignSelf::Center),
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node01 = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node010, node011]).unwrap();
+ let node0 = taffy
+ .new_with_children(
+ taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Percent(1f32),
+ height: taffy::style::Dimension::Percent(1f32),
+ },
+ ..Default::default()
+ },
+ &[node00, node01],
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(100f32),
+ height: taffy::style::Dimension::Points(100f32),
+ },
+ ..Default::default()
+ },
+ &[node0],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+}
diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index b0379c935..82c07611b 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -65,6 +65,11 @@ struct FlexItem {
/// The cross-alignment of this item
align_self: AlignSelf,
+ /// The flex shrink style of the item
+ flex_shrink: f32,
+ /// The flex grow style of the item
+ flex_grow: f32,
+
/// The minimum size of the item. This differs from min_size above because it also
/// takes into account content based automatic minimum sizes
resolved_minimum_size: Size<f32>,
@@ -87,6 +92,10 @@ struct FlexItem {
/// Is the size of this item locked
frozen: bool,
+ /// Either the max- or min- content flex fraction
+ /// See https://www.w3.org/TR/css-flexbox-1/#intrinsic-main-sizes
+ content_flex_fraction: f32,
+
/// The proposed inner size of this item
hypothetical_inner_size: Size<f32>,
/// The proposed outer size of this item
@@ -115,9 +124,6 @@ struct FlexItem {
struct FlexLine<'a> {
/// The slice of items to iterate over during computation of this line
items: &'a mut [FlexItem],
- /// The length in the main-axis that this line contributes to the overall main
- /// main size of the container.
- container_main_size_contribution: f32,
/// The dimensions of the cross-axis
cross_size: f32,
/// The relative offset of the cross-axis
@@ -132,6 +138,8 @@ struct AlgoConstants {
is_row: bool,
/// Is this segment a column
is_column: bool,
+ /// Is wrapping enabled (in either direction)
+ is_wrap: bool,
/// Is the wrap direction inverted
is_wrap_reverse: bool,
@@ -148,6 +156,8 @@ struct AlgoConstants {
/// The align_content property of this node
align_content: AlignContent,
+ /// The border-box size of the node being laid out (if known)
+ node_outer_size: Size<Option<f32>>,
/// The content-box size of the node being laid out (if known)
node_inner_size: Size<Option<f32>>,
@@ -173,17 +183,30 @@ pub fn compute(
|| style.max_size.height.is_defined();
// Pull these out earlier to avoid borrowing issues
- let min_size = style.min_size.maybe_resolve(known_dimensions);
- let max_size = style.max_size.maybe_resolve(known_dimensions);
- let clamped_style_size = style.size.maybe_resolve(known_dimensions).maybe_clamp(min_size, max_size);
-
- if has_min_max_sizes {
+ let aspect_ratio = style.aspect_ratio;
+ let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+ let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
+ let clamped_style_size =
+ style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size);
+
+ // If both min and max in a given axis are set and max <= min then this determines the size in that axis
+ let min_max_definite_size = min_size.zip_map(max_size, |min, max| match (min, max) {
+ (Some(min), Some(max)) if max <= min => Some(min),
+ _ => None,
+ });
+ let styled_based_known_dimensions = known_dimensions.or(min_max_definite_size).or(clamped_style_size);
+
+ if styled_based_known_dimensions.both_axis_defined() || !has_min_max_sizes {
+ #[cfg(feature = "debug")]
+ NODE_LOGGER.log("FLEX: single-pass");
+ compute_preliminary(tree, node, styled_based_known_dimensions, parent_size, available_space, run_mode)
+ } else {
#[cfg(feature = "debug")]
NODE_LOGGER.log("FLEX: two-pass");
let first_pass = compute_preliminary(
tree,
node,
- known_dimensions.zip_map(clamped_style_size, |known, style| known.or(style)),
+ styled_based_known_dimensions,
parent_size,
available_space,
RunMode::ComputeSize,
@@ -195,15 +218,12 @@ pub fn compute(
compute_preliminary(
tree,
node,
- known_dimensions.zip_map(clamped_first_pass_size, |known, first_pass| known.or_else(|| first_pass.into())),
+ styled_based_known_dimensions
+ .zip_map(clamped_first_pass_size, |known, first_pass| known.or_else(|| first_pass.into())),
parent_size,
available_space,
run_mode,
)
- } else {
- #[cfg(feature = "debug")]
- NODE_LOGGER.log("FLEX: single-pass");
- compute_preliminary(tree, node, known_dimensions.or(clamped_style_size), parent_size, available_space, run_mode)
}
}
@@ -259,16 +279,23 @@ fn compute_preliminary(
NODE_LOGGER.log("collect_flex_lines");
let mut flex_lines = collect_flex_lines(tree, node, &constants, available_space, &mut flex_items);
- // If container size is undefined, re-resolve gap based on resolved base sizes
+ // If container size is undefined, determine the container's main size
+ // and then re-resolve gaps based on newly determined size
let original_gap = constants.gap;
- if constants.node_inner_size.main(constants.dir).is_none() {
- let longest_line_length = flex_lines.iter().fold(f32::MIN, |acc, line| {
- let length: f32 = line.items.iter().map(|item| item.hypothetical_outer_size.main(constants.dir)).sum();
- acc.max(length)
- });
+ if let Some(inner_main_size) = constants.node_inner_size.main(constants.dir) {
+ let outer_main_size = inner_main_size + constants.padding_border.main_axis_sum(constants.dir);
+ constants.inner_container_size.set_main(constants.dir, inner_main_size);
+ constants.container_size.set_main(constants.dir, outer_main_size);
+ } else {
+ // Sets constants.container_size and constants.outer_container_size
+ determine_container_main_size(tree, available_space.main(constants.dir), &mut flex_lines, &mut constants);
+ constants.node_inner_size.set_main(constants.dir, Some(constants.inner_container_size.main(constants.dir)));
+ constants.node_outer_size.set_main(constants.dir, Some(constants.container_size.main(constants.dir)));
+ // Re-resolve percentage gaps
let style = tree.style(node);
- let new_gap = style.gap.main(constants.dir).maybe_resolve(longest_line_length).unwrap_or(0.0);
+ 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);
constants.gap.set_main(constants.dir, new_gap);
}
@@ -279,24 +306,6 @@ fn compute_preliminary(
resolve_flexible_lengths(tree, line, &constants, original_gap);
}
- // Find the inner and outer used main_size of the container
- constants.container_size.set_main(
- constants.dir,
- known_dimensions.main(constants.dir).unwrap_or({
- let longest_line =
- flex_lines.iter().fold(f32::MIN, |acc, line| acc.max(line.container_main_size_contribution));
- let size = longest_line + constants.padding_border.main_axis_sum(constants.dir);
- match available_space.main(constants.dir) {
- AvailableSpace::Definite(val) if flex_lines.len() > 1 && size < val => val,
- _ => size,
- }
- }),
- );
- constants.inner_container_size.set_main(
- constants.dir,
- constants.container_size.main(constants.dir) - constants.padding_border.main_axis_sum(constants.dir),
- );
-
// 9.4. Cross Size Determination
// 7. Determine the hypothetical cross size of each item.
@@ -429,13 +438,9 @@ fn compute_constants(
let dir = style.flex_direction;
let is_row = dir.is_row();
let is_column = dir.is_column();
+ let is_wrap = matches!(style.flex_wrap, FlexWrap::Wrap | FlexWrap::WrapReverse);
let is_wrap_reverse = style.flex_wrap == FlexWrap::WrapReverse;
- let aspect_ratio = style.aspect_ratio;
- let size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
- let min_size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
- let max_size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(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);
@@ -444,15 +449,7 @@ fn compute_constants(
let padding_border = padding + border;
- let node_outer_size = Size {
- width: known_dimensions
- .width
- .or_else(|| size.width.maybe_sub(margin.horizontal_axis_sum()).maybe_clamp(min_size.width, max_size.width)),
- height: known_dimensions.height.or_else(|| {
- size.height.maybe_sub(margin.vertical_axis_sum()).maybe_clamp(min_size.height, max_size.height)
- }),
- };
-
+ let node_outer_size = known_dimensions;
let node_inner_size = Size {
width: node_outer_size.width.maybe_sub(padding_border.horizontal_axis_sum()),
height: node_outer_size.height.maybe_sub(padding_border.vertical_axis_sum()),
@@ -466,6 +463,7 @@ fn compute_constants(
dir,
is_row,
is_column,
+ is_wrap,
is_wrap_reverse,
margin,
border,
@@ -473,6 +471,7 @@ fn compute_constants(
padding_border,
align_items,
align_content,
+ node_outer_size,
node_inner_size,
container_size,
inner_container_size,
@@ -509,6 +508,8 @@ fn generate_anonymous_flex_items(tree: &impl LayoutTree, node: Node, constants:
padding: child_style.padding.resolve_or_zero(constants.node_inner_size.width),
border: child_style.border.resolve_or_zero(constants.node_inner_size.width),
align_self: child_style.align_self.unwrap_or(constants.align_items),
+ flex_grow: child_style.flex_grow,
+ flex_shrink: child_style.flex_shrink,
flex_basis: 0.0,
inner_flex_basis: 0.0,
violation: 0.0,
@@ -519,6 +520,7 @@ fn generate_anonymous_flex_items(tree: &impl LayoutTree, node: Node, constants:
hypothetical_outer_size: Size::zero(),
target_size: Size::zero(),
outer_target_size: Size::zero(),
+ content_flex_fraction: 0.0,
baseline: 0.0,
@@ -545,8 +547,9 @@ fn determine_available_space(
outer_available_space: Size<AvailableSpace>,
constants: &AlgoConstants,
) -> Size<AvailableSpace> {
+ // Note: min/max/preferred size styles have already been applied to known_dimensions in the `compute` function above
let width = match known_dimensions.width {
- Some(node_width) => AvailableSpace::Definite(node_width),
+ Some(node_width) => AvailableSpace::Definite(node_width - constants.padding_border.horizontal_axis_sum()),
None => outer_available_space
.width
.maybe_sub(constants.margin.horizontal_axis_sum())
@@ -554,7 +557,7 @@ fn determine_available_space(
};
let height = match known_dimensions.height {
- Some(node_height) => AvailableSpace::Definite(node_height),
+ Some(node_height) => AvailableSpace::Definite(node_height - constants.padding_border.vertical_axis_sum()),
None => outer_available_space
.height
.maybe_sub(constants.margin.vertical_axis_sum())
@@ -674,6 +677,16 @@ fn determine_flex_base_size(
child.inner_flex_basis =
child.flex_basis - child.padding.main_axis_sum(constants.dir) - child.border.main_axis_sum(constants.dir);
+ let hypothetical_inner_min_main = child.min_size.main(constants.dir);
+ child.hypothetical_inner_size.set_main(
+ constants.dir,
+ child.flex_basis.maybe_clamp(hypothetical_inner_min_main, child.max_size.main(constants.dir)),
+ );
+ child.hypothetical_outer_size.set_main(
+ constants.dir,
+ child.hypothetical_inner_size.main(constants.dir) + child.margin.main_axis_sum(constants.dir),
+ );
+
let min_content_size = GenericAlgorithm::measure_size(
tree,
child.node,
@@ -685,18 +698,8 @@ fn determine_flex_base_size(
// 4.5. Automatic Minimum Size of Flex Items
// https://www.w3.org/TR/css-flexbox-1/#min-size-auto
- child.resolved_minimum_size =
- child.min_size.unwrap_or(min_content_size.maybe_min(child.size).maybe_min(child.max_size));
-
- let hypothetical_inner_min_main = child.resolved_minimum_size.main(constants.dir).into();
- child.hypothetical_inner_size.set_main(
- constants.dir,
- child.flex_basis.maybe_clamp(hypothetical_inner_min_main, child.max_size.main(constants.dir)),
- );
- child.hypothetical_outer_size.set_main(
- constants.dir,
- child.hypothetical_inner_size.main(constants.dir) + child.margin.main_axis_sum(constants.dir),
- );
+ let clamped_min_content_size = min_content_size.maybe_min(child.size).maybe_min(child.max_size);
+ child.resolved_minimum_size = child.min_size.unwrap_or(clamped_min_content_size);
}
}
@@ -725,48 +728,234 @@ fn collect_flex_lines<'a>(
available_space: Size<AvailableSpace>,
flex_items: &'a mut Vec<FlexItem>,
) -> Vec<FlexLine<'a>> {
- let mut lines = crate::sys::new_vec_with_capacity(1);
-
if tree.style(node).flex_wrap == FlexWrap::NoWrap {
- lines.push(FlexLine {
- items: flex_items.as_mut_slice(),
- container_main_size_contribution: 0.0,
- cross_size: 0.0,
- offset_cross: 0.0,
- });
+ vec![FlexLine { items: flex_items.as_mut_slice(), cross_size: 0.0, offset_cross: 0.0 }]
} else {
- let mut flex_items = &mut flex_items[..];
- let main_axis_gap = constants.gap.main(constants.dir);
+ match available_space.main(constants.dir) {
+ // If we're sizing under a max-content constraint then the flex items will never wrap
+ // (at least for now - future extensions to the CSS spec may add provisions for forced wrap points)
+ AvailableSpace::MaxContent => {
+ vec![FlexLine { items: flex_items.as_mut_slice(), cross_size: 0.0, offset_cross: 0.0 }]
+ }
+ // If flex-wrap is Wrap and we're sizing under a min-content constraint, then we take every possible wrapping opportunity
+ // and place each item in it's own line
+ AvailableSpace::MinContent => {
+ let mut lines = crate::sys::new_vec_with_capacity(flex_items.len());
+ let mut items = &mut flex_items[..];
+ while !items.is_empty() {
+ let (line_items, rest) = items.split_at_mut(1);
+ lines.push(FlexLine { items: line_items, cross_size: 0.0, offset_cross: 0.0 });
+ items = rest;
+ }
+ lines
+ }
+ AvailableSpace::Definite(main_axis_available_space) => {
+ let mut lines = crate::sys::new_vec_with_capacity(1);
+ let mut flex_items = &mut flex_items[..];
+ let main_axis_gap = constants.gap.main(constants.dir);
+
+ while !flex_items.is_empty() {
+ // Find index of the first item in the next line
+ // (or the last item if all remaining items are in the current line)
+ let mut line_length = 0.0;
+ let index = flex_items
+ .iter()
+ .enumerate()
+ .find(|&(idx, child)| {
+ // Gaps only occur between items (not before the first one or after the last one)
+ // So first item in the line does not contribute a gap to the line length
+ let gap_contribution = if idx == 0 { 0.0 } else { main_axis_gap };
+ line_length += child.hypothetical_outer_size.main(constants.dir) + gap_contribution;
+ line_length > main_axis_available_space && idx != 0
+ })
+ .map(|(idx, _)| idx)
+ .unwrap_or(flex_items.len());
+
+ let (items, rest) = flex_items.split_at_mut(index);
+ lines.push(FlexLine { items, cross_size: 0.0, offset_cross: 0.0 });
+ flex_items = rest;
+ }
+ lines
+ }
+ }
+ }
+}
- while !flex_items.is_empty() {
- let mut line_length = 0.0;
- let index = flex_items
- .iter()
- .enumerate()
- .find(|&(idx, child)| {
- // Gaps only occur between items (not before the first one or after the last one)
- // So first item in the line does not contribute a gap to the line length
- let gap_contribution = if idx == 0 { 0.0 } else { main_axis_gap };
- line_length += child.hypothetical_outer_size.main(constants.dir) + gap_contribution;
- if let AvailableSpace::Definite(main) = available_space.main(constants.dir) {
- line_length > main && idx != 0
- } else {
- false
+/// Determine the container's main size (if not already known)
+fn determine_container_main_size(
+ tree: &mut impl LayoutTree,
+ main_axis_available_space: AvailableSpace,
+ lines: &mut Vec<FlexLine<'_>>,
+ constants: &mut AlgoConstants,
+) {
+ let outer_main_size: f32 = constants.node_outer_size.main(constants.dir).unwrap_or_else(|| {
+ match main_axis_available_space {
+ AvailableSpace::Definite(main_axis_available_space) => {
+ let longest_line_length: f32 = lines
+ .iter()
+ .map(|line| {
+ let line_main_axis_gap = sum_axis_gaps(constants.gap.main(constants.dir), line.items.len());
+ let total_target_size = line
+ .items
+ .iter()
+ .map(|child| child.flex_basis + child.margin.main_axis_sum(constants.dir))
+ .sum::<f32>();
+ total_target_size + line_main_axis_gap
+ })
+ .max_by(|a, b| a.total_cmp(b))
+ .unwrap_or(0.0);
+ let size = longest_line_length + constants.padding_border.main_axis_sum(constants.dir);
+ if lines.len() > 1 {
+ f32_max(size, main_axis_available_space)
+ } else {
+ size
+ }
+ }
+ AvailableSpace::MinContent if constants.is_wrap => {
+ let longest_line_length: f32 = lines
+ .iter()
+ .map(|line| {
+ let line_main_axis_gap = sum_axis_gaps(constants.gap.main(constants.dir), line.items.len());
+ let total_target_size = line
+ .items
+ .iter()
+ .map(|child| child.flex_basis + child.margin.main_axis_sum(constants.dir))
+ .sum::<f32>();
+ total_target_size + line_main_axis_gap
+ })
+ .max_by(|a, b| a.total_cmp(b))
+ .unwrap_or(0.0);
+ longest_line_length + constants.padding_border.main_axis_sum(constants.dir)
+ }
+ AvailableSpace::MinContent | AvailableSpace::MaxContent => {
+ // Define a base main_size variable. This is mutated once for iteration over the outer
+ // loop over the flex lines as:
+ // "The flex container’s max-content size is the largest sum of the afore-calculated sizes of all items within a single line."
+ let mut main_size = 0.0;
+
+ for line in lines.iter_mut() {
+ for item in line.items.iter_mut() {
+ let style_min = item.min_size.main(constants.dir);
+ let style_preferred = item.size.main(constants.dir);
+ let style_max = item.max_size.main(constants.dir);
+ let flex_basis_min = Some(item.flex_basis).filter(|_| item.flex_shrink == 0.0);
+ let flex_basis_max = Some(item.flex_basis).filter(|_| item.flex_grow == 0.0);
+ let min_main_size = style_min.maybe_max(flex_basis_min).or(flex_basis_min);
+ let max_main_size = style_max.maybe_min(flex_basis_max).or(flex_basis_max);
+
+ let content_contribution = match (min_main_size, style_preferred, max_main_size) {
+ // If the clamping values are such that max <= min, then we can avoid the expensive step of computing the content size
+ // as we know that the clamping values will override it anyway
+ (Some(min), Some(pref), Some(max)) if max <= min || max <= pref => {
+ pref.min(max).max(min) + item.margin.main_axis_sum(constants.dir)
+ }
+ (Some(min), _, Some(max)) if max <= min => min + item.margin.main_axis_sum(constants.dir),
+ (_, Some(pref), Some(max)) if max <= pref => max + item.margin.main_axis_sum(constants.dir),
+ // Else compute the min- or -max content size and apply the full formula for computing the
+ // min- or max- content contributuon
+ _ => {
+ // Either the min- or max- content size depending on which constraint we are sizing under.
+ let content_main_size = GenericAlgorithm::measure_size(
+ tree,
+ item.node,
+ Size::NONE,
+ constants.node_inner_size,
+ Size { width: main_axis_available_space, height: main_axis_available_space },
+ SizingMode::InherentSize,
+ )
+ .main(constants.dir)
+ + item.margin.main_axis_sum(constants.dir);
+
+ // This is somewhat bizarre in that it's asymetrical depending whether the flex container is a column or a row.
+ //
+ // I *think* this might relate to https://drafts.csswg.org/css-flexbox-1/#algo-main-container:
+ //
+ // "The automatic block size of a block-level flex container is its max-content size."
+ //
+ // Which could suggest that flex-basis defining a vertical size does not shrink because it is in the block axis, and the automatic size
+ // in the block axis is a MAX content size. Whereas a flex-basis defining a horizontal size does shrink because the automatic size in
+ // inline axis is MIN content size (although I don't have a reference for that).
+ //
+ // Ultimately, this was not found by reading the spec, but by trial and error fixing tests to align with Webkit/Firefox output.
+ // (see the `flex_basis_unconstraint_row` and `flex_basis_uncontraint_column` generated tests which demonstrate this)
+ if constants.is_row {
+ content_main_size.maybe_clamp(style_min, style_max)
+ } else {
+ content_main_size.max(item.flex_basis).maybe_clamp(style_min, style_max)
+ }
+ }
+ };
+ item.content_flex_fraction = {
+ let diff = content_contribution - item.flex_basis;
+ if diff > 0.0 {
+ diff / f32_max(1.0, item.flex_grow)
+ } else if diff < 0.0 {
+ let scaled_shrink_factor = f32_max(1.0, item.flex_shrink) * item.inner_flex_basis;
+ // let scaled_shrink_factor - f32_max(1.0, item.flex_shrink * item.inner_flex_basis);
+ diff / scaled_shrink_factor
+ } else {
+ // We are assuming that diff is 0.0 here and that we haven't accidentally introduced a NaN
+ 0.0
+ }
+ };
}
- })
- .map(|(idx, _)| idx)
- .unwrap_or(flex_items.len());
- let (items, rest) = flex_items.split_at_mut(index);
- lines.push(FlexLine { items, container_main_size_contribution: 0.0, cross_size: 0.0, offset_cross: 0.0 });
- flex_items = rest;
- }
- }
+ // TODO Spec says to scale everything by the line's max flex fraction. But neither Chrome nor firefox implement this
+ // so we don't either. But if we did want to, we'd need this computation here (and to use it below):
+ //
+ // Within each line, find the largest max-content flex fraction among all the flex items.
+ // let line_flex_fraction = line
+ // .items
+ // .iter()
+ // .map(|item| item.content_flex_fraction)
+ // .max_by(|a, b| a.total_cmp(b))
+ // .unwrap_or(0.0); // Unwrap case never gets hit because there is always at least one item a line
+
+ // Add each item’s flex base size to the product of:
+ // - its flex grow factor (or scaled flex shrink factor,if the chosen max-content flex fraction was negative)
+ // - the chosen max-content flex fraction
+ // then clamp that result by the max main size floored by the min main size.
+ //
+ // The flex container’s max-content size is the largest sum of the afore-calculated sizes of all items within a single line.
+ let item_main_size_sum = line
+ .items
+ .iter_mut()
+ .map(|item| {
+ let flex_fraction = item.content_flex_fraction;
+ // let flex_fraction = line_flex_fraction;
+
+ let flex_contribution = if item.content_flex_fraction > 0.0 {
+ f32_max(1.0, item.flex_grow) * flex_fraction
+ } else if item.content_flex_fraction < 0.0 {
+ let scaled_shrink_factor = f32_max(1.0, item.flex_shrink) * item.inner_flex_basis;
+ scaled_shrink_factor * flex_fraction
+ } else {
+ 0.0
+ };
+ let size = item.flex_basis + flex_contribution;
+ item.outer_target_size.set_main(constants.dir, size);
+ item.target_size.set_main(constants.dir, size);
+ size
+ })
+ .sum::<f32>();
+
+ let gap_sum = sum_axis_gaps(constants.gap.main(constants.dir), line.items.len());
+ main_size = f32_max(main_size, item_main_size_sum + gap_sum)
+ }
- lines
+ main_size + constants.padding_border.main_axis_sum(constants.dir)
+ }
+ }
+ });
+ // let outer_main_size = inner_main_size + constants.padding_border.main_axis_sum(constants.dir);
+ let inner_main_size = outer_main_size - constants.padding_border.main_axis_sum(constants.dir);
+ constants.container_size.set_main(constants.dir, outer_main_size);
+ constants.inner_container_size.set_main(constants.dir, inner_main_size);
+ constants.node_inner_size.set_main(constants.dir, Some(inner_main_size));
}
/// Resolve the flexible lengths of the items within a flex line.
+/// Sets the `main` component of each item's `target_size` and `outer_target_size`
///
/// # [9.7. Resolving Flexible Lengths](https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths)
#[inline]
@@ -798,35 +987,8 @@ fn resolve_flexible_lengths(
// smaller than its hypothetical main size
for child in line.items.iter_mut() {
- // This is somewhat bizarre in that it's asymetrical depending whether the flex container is a column or a row.
- //
- // I *think* this might relate to https://drafts.csswg.org/css-flexbox-1/#algo-main-container:
- //
- // "The automatic block size of a block-level flex container is its max-content size."
- //
- // Which could suggest that flex-basis defining a vertical size does not shrink because it is in the block axis, and the automatic size
- // in the block axis is a MAX content size. Whereas a flex-basis defining a horizontal size does shrink because the automatic size in
- // inline axis is MIN content size (although I don't have a reference for that).
- //
- // Ultimately, this was not found by reading the spec, but by trial and error fixing tests to align with Webkit/Firefox output.
- // (see the `flex_basis_unconstraint_row` and `flex_basis_uncontraint_column` generated tests which demonstrate this)
- if constants.node_inner_size.main(constants.dir).is_none() && constants.is_row {
- child.target_size.set_main(
- constants.dir,
- child.size.main(constants.dir).unwrap_or(0.0).maybe_clamp(
- child.resolved_minimum_size.main(constants.dir).into(),
- child.max_size.main(constants.dir),
- ),
- );
- } else {
- child.target_size.set_main(constants.dir, child.hypothetical_inner_size.main(constants.dir));
- }
-
- // TODO this should really only be set inside the if-statement below but
- // that causes the target_main_size to never be set for some items
- child
- .outer_target_size
- .set_main(constants.dir, child.target_size.main(constants.dir) + child.margin.main_axis_sum(constants.dir));
+ let inner_target_size = child.hypothetical_inner_size.main(constants.dir);
+ child.target_size.set_main(constants.dir, inner_target_size);
let child_style = tree.style(child.node);
if (child_style.flex_grow == 0.0 && child_style.flex_shrink == 0.0)
@@ -834,12 +996,11 @@ fn resolve_flexible_lengths(
|| (shrinking && child.flex_basis < child.hypothetical_inner_size.main(constants.dir))
{
child.frozen = true;
+ let outer_target_size = inner_target_size + child.margin.main_axis_sum(constants.dir);
+ child.outer_target_size.set_main(constants.dir, outer_target_size);
}
}
- let total_target_size = line.items.iter().map(|child| child.outer_target_size.main(constants.dir)).sum::<f32>();
- line.container_main_size_contribution = total_target_size + total_original_main_axis_gap;
-
// 3. Calculate initial free space. Sum the outer sizes of all items on the line,
// and subtract this from the flex container’s inner main size. For frozen items,
// use their outer target main size; for other items, use their outer flex base size.
diff --git a/src/geometry.rs b/src/geometry.rs
index 21a187b00..ac4db54c9 100644
--- a/src/geometry.rs
+++ b/src/geometry.rs
@@ -412,6 +412,12 @@ impl<T> Size<Option<T>> {
pub fn or(self, alt: Size<Option<T>>) -> Size<Option<T>> {
Size { width: self.width.or(alt.width), height: self.height.or(alt.height) }
}
+
+ /// Return true if both components are Some, else false.
+ #[inline(always)]
+ pub fn both_axis_defined(&self) -> bool {
+ self.width.is_some() && self.height.is_some()
+ }
}
impl Size<Dimension> {
diff --git a/test_fixtures/intrinsic_sizing_cross_size_column.html b/test_fixtures/intrinsic_sizing_cross_size_column.html
new file mode 100644
index 000000000..cc44cbdf6
--- /dev/null
+++ b/test_fixtures/intrinsic_sizing_cross_size_column.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="flex-direction: column;">HH​HH</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/intrinsic_sizing_main_size_column.html b/test_fixtures/intrinsic_sizing_main_size_column.html
new file mode 100644
index 000000000..b9e564ec1
--- /dev/null
+++ b/test_fixtures/intrinsic_sizing_main_size_column.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="flex-direction: column;writing-mode: vertical-lr;">HH​HH</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/intrinsic_sizing_main_size_column_nested.html b/test_fixtures/intrinsic_sizing_main_size_column_nested.html
new file mode 100644
index 000000000..9da87acca
--- /dev/null
+++ b/test_fixtures/intrinsic_sizing_main_size_column_nested.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="flex-direction: column;">
+ <div style="flex-direction: column;writing-mode: vertical-lr;">HH​HH</div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/intrinsic_sizing_main_size_column_wrap.html b/test_fixtures/intrinsic_sizing_main_size_column_wrap.html
new file mode 100644
index 000000000..7d89683bd
--- /dev/null
+++ b/test_fixtures/intrinsic_sizing_main_size_column_wrap.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="flex-wrap:wrap;flex-direction: column;">
+ <div style="flex-direction: column;writing-mode: vertical-lr;">HH​HH</div>
+ <div style="flex-direction: column;writing-mode: vertical-lr;">HH​HH</div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/intrinsic_sizing_main_size_row.html b/test_fixtures/intrinsic_sizing_main_size_row.html
new file mode 100644
index 000000000..94829889c
--- /dev/null
+++ b/test_fixtures/intrinsic_sizing_main_size_row.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root">HH​HH</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/intrinsic_sizing_main_size_row_nested.html b/test_fixtures/intrinsic_sizing_main_size_row_nested.html
new file mode 100644
index 000000000..872aa0ea7
--- /dev/null
+++ b/test_fixtures/intrinsic_sizing_main_size_row_nested.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root">
+ <div>HH​HH</div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/intrinsic_sizing_main_size_row_wrap.html b/test_fixtures/intrinsic_sizing_main_size_row_wrap.html
new file mode 100644
index 000000000..3a64aabca
--- /dev/null
+++ b/test_fixtures/intrinsic_sizing_main_size_row_wrap.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="flex-wrap:wrap">
+ <div>HH​HH</div>
+ <div>HH​HH</div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/percentage_moderate_complexity2.html b/test_fixtures/percentage_moderate_complexity2.html
new file mode 100644
index 000000000..49b4340d6
--- /dev/null
+++ b/test_fixtures/percentage_moderate_complexity2.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="width: 200px; height: 200px; flex-direction: column;">
+ <div style="width: 50%; padding: 10%; flex-direction: column;">
+ <div style="width:20px;height: 20px"></div>
+ </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/test_fixtures/simple_child.html b/test_fixtures/simple_child.html
new file mode 100644
index 000000000..98065d30b
--- /dev/null
+++ b/test_fixtures/simple_child.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <script src="../scripts/gentest/test_helper.js"></script>
+ <link rel="stylesheet" type="text/css" href="../scripts/gentest/test_base_style.css">
+ <title>
+ Test description
+ </title>
+<head/>
+<body>
+
+<div id="test-root" style="width:100px;height:100px">
+ <div style="width:100%;height:100%">
+ <div style="width:10px;height:10px">
+ <div style="width:10px;height:10px"></div>
+ </div>
+ <div>
+ <div style="width:10px;height:10px;align-self:center"></div>
+ <div style="width:10px;height:10px;align-self:center"></div>
+ </div>
+ </div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/tests/generated/intrinsic_sizing_cross_size_column.rs b/tests/generated/intrinsic_sizing_cross_size_column.rs
new file mode 100644
index 000000000..d91e17a5c
--- /dev/null
+++ b/tests/generated/intrinsic_sizing_cross_size_column.rs
@@ -0,0 +1,31 @@
+#[test]
+fn intrinsic_sizing_cross_size_column() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+}
diff --git a/tests/generated/intrinsic_sizing_main_size_column.rs b/tests/generated/intrinsic_sizing_main_size_column.rs
new file mode 100644
index 000000000..8a2d46e4d
--- /dev/null
+++ b/tests/generated/intrinsic_sizing_main_size_column.rs
@@ -0,0 +1,31 @@
+#[test]
+fn intrinsic_sizing_main_size_column() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+}
diff --git a/tests/generated/intrinsic_sizing_main_size_column_nested.rs b/tests/generated/intrinsic_sizing_main_size_column_nested.rs
new file mode 100644
index 000000000..4fd9c8ede
--- /dev/null
+++ b/tests/generated/intrinsic_sizing_main_size_column_nested.rs
@@ -0,0 +1,42 @@
+#[test]
+fn intrinsic_sizing_main_size_column_nested() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ &[node0],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 10f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+}
diff --git a/tests/generated/intrinsic_sizing_main_size_column_wrap.rs b/tests/generated/intrinsic_sizing_main_size_column_wrap.rs
new file mode 100644
index 000000000..4071c5452
--- /dev/null
+++ b/tests/generated/intrinsic_sizing_main_size_column_wrap.rs
@@ -0,0 +1,66 @@
+#[test]
+fn intrinsic_sizing_main_size_column_wrap() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node1 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { flex_direction: taffy::style::FlexDirection::Column, ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Vertical,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ flex_direction: taffy::style::FlexDirection::Column,
+ flex_wrap: taffy::style::FlexWrap::Wrap,
+ ..Default::default()
+ },
+ &[node0, node1],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.width);
+ assert_eq!(size.height, 80f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 80f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 10f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node1).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 10f32, size.width);
+ assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.x);
+ assert_eq!(location.y, 40f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.y);
+}
diff --git a/tests/generated/intrinsic_sizing_main_size_row.rs b/tests/generated/intrinsic_sizing_main_size_row.rs
new file mode 100644
index 000000000..1fc68111d
--- /dev/null
+++ b/tests/generated/intrinsic_sizing_main_size_row.rs
@@ -0,0 +1,31 @@
+#[test]
+fn intrinsic_sizing_main_size_row() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+}
diff --git a/tests/generated/intrinsic_sizing_main_size_row_nested.rs b/tests/generated/intrinsic_sizing_main_size_row_nested.rs
new file mode 100644
index 000000000..8149ba75c
--- /dev/null
+++ b/tests/generated/intrinsic_sizing_main_size_row_nested.rs
@@ -0,0 +1,37 @@
+#[test]
+fn intrinsic_sizing_main_size_row_nested() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node0]).unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 40f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+}
diff --git a/tests/generated/intrinsic_sizing_main_size_row_wrap.rs b/tests/generated/intrinsic_sizing_main_size_row_wrap.rs
new file mode 100644
index 000000000..273c53cf8
--- /dev/null
+++ b/tests/generated/intrinsic_sizing_main_size_row_wrap.rs
@@ -0,0 +1,62 @@
+#[test]
+fn intrinsic_sizing_main_size_row_wrap() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node0 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node1 = taffy
+ .new_leaf_with_measure(
+ taffy::style::Style { ..Default::default() },
+ taffy::node::MeasureFunc::Raw(|known_dimensions, available_space| {
+ const TEXT: &str = "HH\u{200b}HH";
+ super::measure_standard_text(
+ known_dimensions,
+ available_space,
+ TEXT,
+ super::WritingMode::Horizontal,
+ None,
+ )
+ }),
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style { flex_wrap: taffy::style::FlexWrap::Wrap, ..Default::default() },
+ &[node0, node1],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 80f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 80f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 40f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node1).unwrap();
+ assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 10f32, size.height);
+ assert_eq!(location.x, 40f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y);
+}
diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs
index f119b78db..53ff8577b 100644
--- a/tests/generated/mod.rs
+++ b/tests/generated/mod.rs
@@ -697,6 +697,13 @@ mod grid_span_2_min_content_min_content_indefinite;
mod grid_span_6_all_non_flex_indefinite;
#[cfg(feature = "grid")]
mod grid_span_8_all_track_types_indefinite;
+mod intrinsic_sizing_cross_size_column;
+mod intrinsic_sizing_main_size_column;
+mod intrinsic_sizing_main_size_column_nested;
+mod intrinsic_sizing_main_size_column_wrap;
+mod intrinsic_sizing_main_size_row;
+mod intrinsic_sizing_main_size_row_nested;
+mod intrinsic_sizing_main_size_row_wrap;
mod justify_content_column_center;
mod justify_content_column_flex_end;
mod justify_content_column_flex_start;
@@ -814,6 +821,7 @@ mod percentage_flex_basis_main_min_width;
mod percentage_main_max_height;
mod percentage_margin_should_calculate_based_only_on_width;
mod percentage_moderate_complexity;
+mod percentage_moderate_complexity2;
mod percentage_multiple_nested_with_padding_margin_and_percentage_values;
mod percentage_padding_should_calculate_based_only_on_width;
mod percentage_position_bottom_right;
@@ -835,6 +843,7 @@ mod rounding_fractial_input_4;
mod rounding_inner_node_controversy_vertical;
mod rounding_total_fractial;
mod rounding_total_fractial_nested;
+mod simple_child;
mod single_flex_child_after_absolute_child;
mod size_defined_by_child;
mod size_defined_by_child_with_border;
diff --git a/tests/generated/percentage_moderate_complexity2.rs b/tests/generated/percentage_moderate_complexity2.rs
new file mode 100644
index 000000000..3f98db2cb
--- /dev/null
+++ b/tests/generated/percentage_moderate_complexity2.rs
@@ -0,0 +1,64 @@
+#[test]
+fn percentage_moderate_complexity2() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node00 = taffy
+ .new_leaf(taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(20f32),
+ height: taffy::style::Dimension::Points(20f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node0 = taffy
+ .new_with_children(
+ taffy::style::Style {
+ flex_direction: taffy::style::FlexDirection::Column,
+ size: taffy::geometry::Size { width: taffy::style::Dimension::Percent(0.5f32), height: auto() },
+ padding: taffy::geometry::Rect {
+ left: taffy::style::LengthPercentage::Percent(0.1f32),
+ right: taffy::style::LengthPercentage::Percent(0.1f32),
+ top: taffy::style::LengthPercentage::Percent(0.1f32),
+ bottom: taffy::style::LengthPercentage::Percent(0.1f32),
+ },
+ ..Default::default()
+ },
+ &[node00],
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ flex_direction: taffy::style::FlexDirection::Column,
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(200f32),
+ height: taffy::style::Dimension::Points(200f32),
+ },
+ ..Default::default()
+ },
+ &[node0],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 200f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.width);
+ assert_eq!(size.height, 200f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 200f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.width);
+ assert_eq!(size.height, 60f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 60f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+ assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.width);
+ assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, size.height);
+ assert_eq!(location.x, 20f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, location.x);
+ assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 20f32, location.y);
+}
diff --git a/tests/generated/simple_child.rs b/tests/generated/simple_child.rs
new file mode 100644
index 000000000..66b269004
--- /dev/null
+++ b/tests/generated/simple_child.rs
@@ -0,0 +1,112 @@
+#[test]
+fn simple_child() {
+ use slotmap::Key;
+ #[allow(unused_imports)]
+ use taffy::{layout::Layout, prelude::*};
+ let mut taffy = taffy::Taffy::new();
+ let node000 = taffy
+ .new_leaf(taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node00 = taffy
+ .new_with_children(
+ taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ },
+ &[node000],
+ )
+ .unwrap();
+ let node010 = taffy
+ .new_leaf(taffy::style::Style {
+ align_self: Some(taffy::style::AlignSelf::Center),
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node011 = taffy
+ .new_leaf(taffy::style::Style {
+ align_self: Some(taffy::style::AlignSelf::Center),
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(10f32),
+ height: taffy::style::Dimension::Points(10f32),
+ },
+ ..Default::default()
+ })
+ .unwrap();
+ let node01 = taffy.new_with_children(taffy::style::Style { ..Default::default() }, &[node010, node011]).unwrap();
+ let node0 = taffy
+ .new_with_children(
+ taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Percent(1f32),
+ height: taffy::style::Dimension::Percent(1f32),
+ },
+ ..Default::default()
+ },
+ &[node00, node01],
+ )
+ .unwrap();
+ let node = taffy
+ .new_with_children(
+ taffy::style::Style {
+ size: taffy::geometry::Size {
+ width: taffy::style::Dimension::Points(100f32),
+ height: taffy::style::Dimension::Points(100f32),
+ },
+ ..Default::default()
+ },
+ &[node0],
+ )
+ .unwrap();
+ taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
+ println!("\nComputed tree:");
+ taffy::debug::print_tree(&taffy, node);
+ println!();
+ let Layout { size, location, .. } = taffy.layout(node).unwrap();
+ assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width);
+ assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node0).unwrap();
+ assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.width);
+ assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node00).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node00.data(), 10f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node00.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node000).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node000.data(), 10f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node000.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node000.data(), 0f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node000.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node01).unwrap();
+ assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node01.data(), 20f32, size.width);
+ assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node01.data(), 100f32, size.height);
+ assert_eq!(location.x, 10f32, "x of node {:?}. Expected {}. Actual {}", node01.data(), 10f32, location.x);
+ assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node01.data(), 0f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node010).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node010.data(), 10f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node010.data(), 10f32, size.height);
+ assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node010.data(), 0f32, location.x);
+ assert_eq!(location.y, 45f32, "y of node {:?}. Expected {}. Actual {}", node010.data(), 45f32, location.y);
+ let Layout { size, location, .. } = taffy.layout(node011).unwrap();
+ assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node011.data(), 10f32, size.width);
+ assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node011.data(), 10f32, size.height);
+ assert_eq!(location.x, 10f32, "x of node {:?}. Expected {}. Actual {}", node011.data(), 10f32, location.x);
+ assert_eq!(location.y, 45f32, "y of node {:?}. Expected {}. Actual {}", node011.data(), 45f32, location.y);
+}
diff --git a/tests/simple_child.rs b/tests/simple_child.rs
deleted file mode 100644
index b53a671d3..000000000
--- a/tests/simple_child.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use taffy::{geometry::Point, style::AvailableSpace, style::Dimension};
-
-#[test]
-fn simple_child() {
- let mut taffy = taffy::Taffy::new();
- let node0_0 = taffy
- .new_leaf(taffy::style::Style {
- align_self: Some(taffy::prelude::AlignSelf::Center),
- size: taffy::geometry::Size { width: Dimension::Points(10f32), height: Dimension::Points(10f32) },
- ..Default::default()
- })
- .unwrap();
- let node0 = taffy
- .new_with_children(
- taffy::style::Style {
- size: taffy::geometry::Size { width: Dimension::Points(10f32), height: Dimension::Points(10f32) },
- ..Default::default()
- },
- &[node0_0],
- )
- .unwrap();
- let node1_0 = taffy
- .new_leaf(taffy::style::Style {
- align_self: Some(taffy::prelude::AlignSelf::Center),
- size: taffy::geometry::Size { width: Dimension::Points(10f32), height: Dimension::Points(10f32) },
- ..Default::default()
- })
- .unwrap();
- let node1_1 = taffy
- .new_leaf(taffy::style::Style {
- align_self: Some(taffy::prelude::AlignSelf::Center),
- size: taffy::geometry::Size { width: Dimension::Points(10f32), height: Dimension::Points(10f32) },
- ..Default::default()
- })
- .unwrap();
- let node1 = taffy
- .new_with_children(
- taffy::style::Style { size: taffy::geometry::Size::auto(), ..Default::default() },
- &[node1_0, node1_1],
- )
- .unwrap();
- let node = taffy
- .new_with_children(
- taffy::style::Style {
- size: taffy::geometry::Size { width: Dimension::Percent(100.0), height: Dimension::Percent(100.0) },
- ..Default::default()
- },
- &[node0, node1],
- )
- .unwrap();
- taffy
- .compute_layout(
- node,
- taffy::geometry::Size { width: AvailableSpace::Definite(100.), height: AvailableSpace::Definite(100.) },
- )
- .unwrap();
- assert_eq!(taffy.layout(node).unwrap().location, Point { x: 0.0, y: 0.0 });
- assert_eq!(taffy.layout(node0).unwrap().location, Point { x: 0.0, y: 0.0 });
- assert_eq!(taffy.layout(node1).unwrap().location, Point { x: 10.0, y: 0.0 });
- assert_eq!(taffy.layout(node0_0).unwrap().location, Point { x: 0.0, y: 0.0 });
- // Layout is relative so node1_0 location starts at (0,0) and is not ofset by it's parent location
- assert_eq!(taffy.layout(node1_0).unwrap().location, Point { x: 00.0, y: 0.0 });
- assert_eq!(taffy.layout(node1_1).unwrap().location, Point { x: 10.0, y: 0.0 });
-}