From cd73db35cfa2b31555a796e7972cd97a45554e17 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 29 Jun 2024 23:21:09 +1200 Subject: [PATCH] Fix computation of intrinsic main size when it depends on a child's known cross size (#673) * Improve debug logging * Flexbox: pass cross-axis known_dimensions when sizing a child to determine container main size (match the inputs we usually pass when determining a child's base size) * Add test for DioxusLabs/Blitz#88 --- src/compute/flexbox.rs | 21 +++- src/compute/mod.rs | 4 +- test_fixtures/flex/blitz_issue_88.html | 23 ++++ tests/generated/flex/blitz_issue_88.rs | 148 +++++++++++++++++++++++++ tests/generated/flex/mod.rs | 1 + 5 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 test_fixtures/flex/blitz_issue_88.html create mode 100644 tests/generated/flex/blitz_issue_88.rs diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs index 67b094dfb..b9bb7667a 100644 --- a/src/compute/flexbox.rs +++ b/src/compute/flexbox.rs @@ -188,7 +188,7 @@ pub fn compute_flexbox_layout(tree: &mut impl LayoutPartialTree, node: NodeId, i } } - debug_log!("FLEX: single-pass"); + debug_log!("FLEX:", dbg:style.flex_direction); compute_preliminary(tree, node, LayoutInput { known_dimensions: styled_based_known_dimensions, ..inputs }) } @@ -658,6 +658,7 @@ fn determine_flex_base_size( ) .with_cross(dir, cross_axis_available_space); + debug_log!("COMPUTE CHILD BASE SIZE:"); break 'flex_basis tree.measure_child_size( child.node, child_known_dimensions, @@ -708,6 +709,7 @@ fn determine_flex_base_size( let min_content_main_size = { let child_available_space = Size::MIN_CONTENT.with_cross(dir, cross_axis_available_space); + debug_log!("COMPUTE CHILD MIN SIZE:"); tree.measure_child_size( child.node, child_known_dimensions, @@ -918,11 +920,26 @@ fn determine_container_main_size( let child_available_space = available_space.with_cross(dir, cross_axis_available_space); + // Known dimensions for child sizing + let child_known_dimensions = { + let mut ckd = item.size.with_main(dir, None); + if item.align_self == AlignSelf::Stretch && ckd.cross(dir).is_none() { + ckd.set_cross( + dir, + cross_axis_available_space + .into_option() + .maybe_sub(item.margin.cross_axis_sum(dir)), + ); + } + ckd + }; + // Either the min- or max- content size depending on which constraint we are sizing under. // TODO: Optimise by using already computed values where available + debug_log!("COMPUTE CHILD BASE SIZE (for intrinsic main size):"); let content_main_size = tree.measure_child_size( item.node, - Size::NONE, + child_known_dimensions, constants.node_inner_size, child_available_space, SizingMode::InherentSize, diff --git a/src/compute/mod.rs b/src/compute/mod.rs index 746997af4..d9e787d50 100644 --- a/src/compute/mod.rs +++ b/src/compute/mod.rs @@ -107,12 +107,14 @@ where // First we check if we have a cached result for the given input let cache_entry = tree.get_cache_mut(node).get(known_dimensions, available_space, run_mode); if let Some(cached_size_and_baselines) = cache_entry { - debug_log!("CACHE", dbg:cached_size_and_baselines.size); debug_log_node!(known_dimensions, inputs.parent_size, available_space, run_mode, inputs.sizing_mode); + debug_log!("RESULT (CACHED)", dbg:cached_size_and_baselines.size); debug_pop_node!(); return cached_size_and_baselines; } + debug_log_node!(known_dimensions, inputs.parent_size, available_space, run_mode, inputs.sizing_mode); + let computed_size_and_baselines = compute_uncached(tree, node, inputs); // Cache result diff --git a/test_fixtures/flex/blitz_issue_88.html b/test_fixtures/flex/blitz_issue_88.html new file mode 100644 index 000000000..7c4a9356a --- /dev/null +++ b/test_fixtures/flex/blitz_issue_88.html @@ -0,0 +1,23 @@ + + + + + + + Test description + + + + +
+
+
+
+ HHHH​HHHH​HHHH​HHHH​HHHH +
+
+
+
+ + + \ No newline at end of file diff --git a/tests/generated/flex/blitz_issue_88.rs b/tests/generated/flex/blitz_issue_88.rs new file mode 100644 index 000000000..bef5bc405 --- /dev/null +++ b/tests/generated/flex/blitz_issue_88.rs @@ -0,0 +1,148 @@ +#[test] +fn blitz_issue_88() { + #[allow(unused_imports)] + use taffy::{prelude::*, tree::Layout, TaffyTree}; + let mut taffy: TaffyTree = TaffyTree::new(); + let node000 = taffy + .new_leaf_with_context( + taffy::style::Style { + display: taffy::style::Display::Block, + flex_grow: 1f32, + flex_basis: taffy::style::Dimension::Length(0f32), + ..Default::default() + }, + crate::TextMeasure { + text_content: "HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH\u{200b}HHHH", + writing_mode: crate::WritingMode::Horizontal, + _aspect_ratio: None, + }, + ) + .unwrap(); + let node00 = taffy + .new_with_children( + taffy::style::Style { display: taffy::style::Display::Flex, flex_grow: 1f32, ..Default::default() }, + &[node000], + ) + .unwrap(); + let node0 = taffy + .new_with_children( + taffy::style::Style { + display: taffy::style::Display::Flex, + flex_direction: taffy::style::FlexDirection::Column, + justify_content: Some(taffy::style::JustifyContent::Start), + ..Default::default() + }, + &[node00], + ) + .unwrap(); + let node = taffy + .new_with_children( + taffy::style::Style { + display: taffy::style::Display::Block, + size: taffy::geometry::Size { width: taffy::style::Dimension::Length(600f32), height: auto() }, + ..Default::default() + }, + &[node0], + ) + .unwrap(); + taffy.compute_layout_with_measure(node, taffy::geometry::Size::MAX_CONTENT, crate::test_measure_function).unwrap(); + println!("\nComputed tree:"); + taffy.print_tree(node); + println!(); + #[cfg_attr(not(feature = "content_size"), allow(unused_variables))] + let layout @ Layout { size, location, .. } = taffy.layout(node).unwrap(); + assert_eq!(size.width, 600f32, "width of node {:?}. Expected {}. Actual {}", node, 600f32, size.width); + assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node, 10f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node, 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node, 0f32, location.y); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_width(), + 0f32, + "scroll_width of node {:?}. Expected {}. Actual {}", + node, + 0f32, + layout.scroll_width() + ); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_height(), + 0f32, + "scroll_height of node {:?}. Expected {}. Actual {}", + node, + 0f32, + layout.scroll_height() + ); + #[cfg_attr(not(feature = "content_size"), allow(unused_variables))] + let layout @ Layout { size, location, .. } = taffy.layout(node0).unwrap(); + assert_eq!(size.width, 600f32, "width of node {:?}. Expected {}. Actual {}", node0, 600f32, size.width); + assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node0, 10f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0, 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0, 0f32, location.y); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_width(), + 0f32, + "scroll_width of node {:?}. Expected {}. Actual {}", + node0, + 0f32, + layout.scroll_width() + ); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_height(), + 0f32, + "scroll_height of node {:?}. Expected {}. Actual {}", + node0, + 0f32, + layout.scroll_height() + ); + #[cfg_attr(not(feature = "content_size"), allow(unused_variables))] + let layout @ Layout { size, location, .. } = taffy.layout(node00).unwrap(); + assert_eq!(size.width, 600f32, "width of node {:?}. Expected {}. Actual {}", node00, 600f32, size.width); + assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node00, 10f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node00, 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node00, 0f32, location.y); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_width(), + 0f32, + "scroll_width of node {:?}. Expected {}. Actual {}", + node00, + 0f32, + layout.scroll_width() + ); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_height(), + 0f32, + "scroll_height of node {:?}. Expected {}. Actual {}", + node00, + 0f32, + layout.scroll_height() + ); + #[cfg_attr(not(feature = "content_size"), allow(unused_variables))] + let layout @ Layout { size, location, .. } = taffy.layout(node000).unwrap(); + assert_eq!(size.width, 600f32, "width of node {:?}. Expected {}. Actual {}", node000, 600f32, size.width); + assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node000, 10f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node000, 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node000, 0f32, location.y); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_width(), + 0f32, + "scroll_width of node {:?}. Expected {}. Actual {}", + node000, + 0f32, + layout.scroll_width() + ); + #[cfg(feature = "content_size")] + assert_eq!( + layout.scroll_height(), + 0f32, + "scroll_height of node {:?}. Expected {}. Actual {}", + node000, + 0f32, + layout.scroll_height() + ); +} diff --git a/tests/generated/flex/mod.rs b/tests/generated/flex/mod.rs index b2f6d34c4..522bea496 100644 --- a/tests/generated/flex/mod.rs +++ b/tests/generated/flex/mod.rs @@ -186,6 +186,7 @@ mod bevy_issue_9530_reduced; mod bevy_issue_9530_reduced2; mod bevy_issue_9530_reduced3; mod bevy_issue_9530_reduced4; +mod blitz_issue_88; mod border_center_child; mod border_container_match_child; mod border_flex_child;