tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 499HTML 245JavaScript 8Markdown 71218 Sutichaykuna

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

cd73db35cfa2b31555a796e7972cd97a45554e17 · ruwaq Nico Burns · (2 wata ñawpaq) · tayta 385a9b803 · kay commitpi sach'ata qhaway

Semántico sayk'uy · 6

src/compute/flexbox.rs

src/compute/mod.rs

tests/generated/flex/blitz_issue_88.rs

tests/generated/flex/mod.rs

5 qillqakuna · +194 −3

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 @@
+<!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="display: block; color: white; width: 600px;">
+  <div style="display: flex; flex-direction: column; justify-content: start;">
+    <div style="display: flex; flex-grow: 1;">
+      <div style="display: block; flex-basis: 0; flex-grow: 1;">
+        HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH&ZeroWidthSpace;HHHH
+      </div>
+    </div>
+  </div>
+</div>
+
+</body>
+</html>
\ 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<crate::TextMeasure> = 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;