tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 231Rust 10TOML 3CSS 1348 Definiciones

Call measure function on leaf nodes even if the node does not have context (#598)

563d5dcee7b9138b4c3f865155d036a8b7597e65 · por Nico Burns · (hace 2 años) · padre 77b704eb4 · ver el árbol en este commit

Delta semántico · 10

examples/custom_tree_owned_partial.rs

examples/custom_tree_owned_unsafe.rs

examples/custom_tree_vec.rs

src/compute/leaf.rs

src/tree/taffy_tree.rs

tests/measure.rs

6 archivos · +89 −147

diff --git a/examples/custom_tree_owned_partial.rs b/examples/custom_tree_owned_partial.rs
index 2671afa8a..79f693296 100644
--- a/examples/custom_tree_owned_partial.rs
+++ b/examples/custom_tree_owned_partial.rs
@@ -146,25 +146,17 @@ impl taffy::LayoutPartialTree for Node {
             match node.kind {
                 NodeKind::Flexbox => compute_flexbox_layout(node, node_id, inputs),
                 NodeKind::Grid => compute_grid_layout(node, node_id, inputs),
-                NodeKind::Text => compute_leaf_layout(
-                    inputs,
-                    &node.style,
-                    Some(|known_dimensions, available_space| {
-                        text_measure_function(
-                            known_dimensions,
-                            available_space,
-                            node.text_data.as_ref().unwrap(),
-                            &font_metrics,
-                        )
-                    }),
-                ),
-                NodeKind::Image => compute_leaf_layout(
-                    inputs,
-                    &node.style,
-                    Some(|known_dimensions, _available_space| {
-                        image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
-                    }),
-                ),
+                NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
+                    text_measure_function(
+                        known_dimensions,
+                        available_space,
+                        node.text_data.as_ref().unwrap(),
+                        &font_metrics,
+                    )
+                }),
+                NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
+                    image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
+                }),
             }
         })
     }
diff --git a/examples/custom_tree_owned_unsafe.rs b/examples/custom_tree_owned_unsafe.rs
index 9a3fb1d4a..96f31527f 100644
--- a/examples/custom_tree_owned_unsafe.rs
+++ b/examples/custom_tree_owned_unsafe.rs
@@ -150,25 +150,17 @@ impl LayoutPartialTree for StatelessLayoutTree {
             match node.kind {
                 NodeKind::Flexbox => compute_flexbox_layout(tree, node_id, inputs),
                 NodeKind::Grid => compute_grid_layout(tree, node_id, inputs),
-                NodeKind::Text => compute_leaf_layout(
-                    inputs,
-                    &node.style,
-                    Some(|known_dimensions, available_space| {
-                        text_measure_function(
-                            known_dimensions,
-                            available_space,
-                            node.text_data.as_ref().unwrap(),
-                            &font_metrics,
-                        )
-                    }),
-                ),
-                NodeKind::Image => compute_leaf_layout(
-                    inputs,
-                    &node.style,
-                    Some(|known_dimensions, _available_space| {
-                        image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
-                    }),
-                ),
+                NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
+                    text_measure_function(
+                        known_dimensions,
+                        available_space,
+                        node.text_data.as_ref().unwrap(),
+                        &font_metrics,
+                    )
+                }),
+                NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
+                    image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
+                }),
             }
         })
     }
diff --git a/examples/custom_tree_vec.rs b/examples/custom_tree_vec.rs
index 78546f258..f3e86568a 100644
--- a/examples/custom_tree_vec.rs
+++ b/examples/custom_tree_vec.rs
@@ -159,25 +159,17 @@ impl taffy::LayoutPartialTree for Tree {
             match node.kind {
                 NodeKind::Flexbox => compute_flexbox_layout(tree, node_id, inputs),
                 NodeKind::Grid => compute_grid_layout(tree, node_id, inputs),
-                NodeKind::Text => compute_leaf_layout(
-                    inputs,
-                    &node.style,
-                    Some(|known_dimensions, available_space| {
-                        text_measure_function(
-                            known_dimensions,
-                            available_space,
-                            node.text_data.as_ref().unwrap(),
-                            &font_metrics,
-                        )
-                    }),
-                ),
-                NodeKind::Image => compute_leaf_layout(
-                    inputs,
-                    &node.style,
-                    Some(|known_dimensions, _available_space| {
-                        image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
-                    }),
-                ),
+                NodeKind::Text => compute_leaf_layout(inputs, &node.style, |known_dimensions, available_space| {
+                    text_measure_function(
+                        known_dimensions,
+                        available_space,
+                        node.text_data.as_ref().unwrap(),
+                        &font_metrics,
+                    )
+                }),
+                NodeKind::Image => compute_leaf_layout(inputs, &node.style, |known_dimensions, _available_space| {
+                    image_measure_function(known_dimensions, node.image_data.as_ref().unwrap())
+                }),
             }
         })
     }
diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs
index d909415dd..c6bc177b7 100644
--- a/src/compute/leaf.rs
+++ b/src/compute/leaf.rs
@@ -14,7 +14,7 @@ use core::unreachable;
 pub fn compute_leaf_layout<MeasureFunction>(
     inputs: LayoutInput,
     style: &Style,
-    measure_function: Option<MeasureFunction>,
+    measure_function: MeasureFunction,
 ) -> LayoutOutput
 where
     MeasureFunction: FnOnce(Size<Option<f32>>, Size<AvailableSpace>) -> Size<f32>,
@@ -80,7 +80,7 @@ where
     debug_log!("max_size ", dbg:node_max_size);
 
     // Return early if both width and height are known
-    if run_mode == RunMode::ComputeSize {
+    if run_mode == RunMode::ComputeSize && has_styles_preventing_being_collapsed_through {
         if let Size { width: Some(width), height: Some(height) } = node_size {
             let size = Size { width, height }
                 .maybe_clamp(node_min_size, node_max_size)
@@ -92,99 +92,65 @@ where
                 first_baselines: Point::NONE,
                 top_margin: CollapsibleMarginSet::ZERO,
                 bottom_margin: CollapsibleMarginSet::ZERO,
-                margins_can_collapse_through: !has_styles_preventing_being_collapsed_through
-                    && size.height == 0.0
-                    && measure_function.is_none(),
+                margins_can_collapse_through: false,
             };
         };
     }
 
-    if let Some(measure_function) = measure_function {
-        // Compute available space
-        let available_space = Size {
-            width: known_dimensions
-                .width
-                .map(AvailableSpace::from)
-                .unwrap_or(available_space.width)
-                .maybe_sub(margin.horizontal_axis_sum())
-                .maybe_set(known_dimensions.width)
-                .maybe_set(node_size.width)
-                .maybe_set(node_max_size.width)
-                .map_definite_value(|size| {
-                    size.maybe_clamp(node_min_size.width, node_max_size.width) - content_box_inset.horizontal_axis_sum()
-                }),
-            height: known_dimensions
-                .height
-                .map(AvailableSpace::from)
-                .unwrap_or(available_space.height)
-                .maybe_sub(margin.vertical_axis_sum())
-                .maybe_set(known_dimensions.height)
-                .maybe_set(node_size.height)
-                .maybe_set(node_max_size.height)
-                .map_definite_value(|size| {
-                    size.maybe_clamp(node_min_size.height, node_max_size.height) - content_box_inset.vertical_axis_sum()
-                }),
-        };
-
-        // Measure node
-        let measured_size = measure_function(
-            match run_mode {
-                RunMode::ComputeSize => known_dimensions,
-                RunMode::PerformLayout => Size::NONE,
-                RunMode::PerformHiddenLayout => unreachable!(),
-            },
-            available_space,
-        );
-        let clamped_size = known_dimensions
-            .or(node_size)
-            .unwrap_or(measured_size + content_box_inset.sum_axes())
-            .maybe_clamp(node_min_size, node_max_size);
-        let size = Size {
-            width: clamped_size.width,
-            height: f32_max(clamped_size.height, aspect_ratio.map(|ratio| clamped_size.width / ratio).unwrap_or(0.0)),
-        };
-        let size = size.maybe_max(padding_border.sum_axes().map(Some));
-
-        return LayoutOutput {
-            size,
-            #[cfg(feature = "content_size")]
-            content_size: measured_size + padding.sum_axes(),
-            first_baselines: Point::NONE,
-            top_margin: CollapsibleMarginSet::ZERO,
-            bottom_margin: CollapsibleMarginSet::ZERO,
-            margins_can_collapse_through: !has_styles_preventing_being_collapsed_through
-                && size.height == 0.0
-                && measured_size.height == 0.0,
-        };
-    }
-
-    let size = Size {
-        width: node_size
+    // Compute available space
+    let available_space = Size {
+        width: known_dimensions
             .width
-            // .unwrap_or(0.0) + padding.horizontal_axis_sum() + border.horizontal_axis_sum(), // content-box
-            .unwrap_or(content_box_inset.horizontal_axis_sum()) // border-box
-            .maybe_clamp(node_min_size.width, node_max_size.width)
-            .maybe_max(padding_border.horizontal_axis_sum().into()),
-        height: node_size
+            .map(AvailableSpace::from)
+            .unwrap_or(available_space.width)
+            .maybe_sub(margin.horizontal_axis_sum())
+            .maybe_set(known_dimensions.width)
+            .maybe_set(node_size.width)
+            .maybe_set(node_max_size.width)
+            .map_definite_value(|size| {
+                size.maybe_clamp(node_min_size.width, node_max_size.width) - content_box_inset.horizontal_axis_sum()
+            }),
+        height: known_dimensions
             .height
-            // .unwrap_or(0.0) + padding.vertical_axis_sum() + border.vertical_axis_sum(), // content-box
-            .unwrap_or(content_box_inset.vertical_axis_sum()) // border-box
-            .maybe_clamp(node_min_size.height, node_max_size.height)
-            .maybe_max(padding_border.vertical_axis_sum().into()),
+            .map(AvailableSpace::from)
+            .unwrap_or(available_space.height)
+            .maybe_sub(margin.vertical_axis_sum())
+            .maybe_set(known_dimensions.height)
+            .maybe_set(node_size.height)
+            .maybe_set(node_max_size.height)
+            .map_definite_value(|size| {
+                size.maybe_clamp(node_min_size.height, node_max_size.height) - content_box_inset.vertical_axis_sum()
+            }),
     };
 
+    // Measure node
+    let measured_size = measure_function(
+        match run_mode {
+            RunMode::ComputeSize => known_dimensions,
+            RunMode::PerformLayout => Size::NONE,
+            RunMode::PerformHiddenLayout => unreachable!(),
+        },
+        available_space,
+    );
+    let clamped_size = known_dimensions
+        .or(node_size)
+        .unwrap_or(measured_size + content_box_inset.sum_axes())
+        .maybe_clamp(node_min_size, node_max_size);
     let size = Size {
-        width: f32_max(size.width, aspect_ratio.map(|ratio| size.height * ratio).unwrap_or(0.0)),
-        height: f32_max(size.height, aspect_ratio.map(|ratio| size.width / ratio).unwrap_or(0.0)),
+        width: clamped_size.width,
+        height: f32_max(clamped_size.height, aspect_ratio.map(|ratio| clamped_size.width / ratio).unwrap_or(0.0)),
     };
+    let size = size.maybe_max(padding_border.sum_axes().map(Some));
 
     LayoutOutput {
         size,
         #[cfg(feature = "content_size")]
-        content_size: padding.sum_axes(),
+        content_size: measured_size + padding.sum_axes(),
         first_baselines: Point::NONE,
         top_margin: CollapsibleMarginSet::ZERO,
         bottom_margin: CollapsibleMarginSet::ZERO,
-        margins_can_collapse_through: !has_styles_preventing_being_collapsed_through && size.height == 0.0,
+        margins_can_collapse_through: !has_styles_preventing_being_collapsed_through
+            && size.height == 0.0
+            && measured_size.height == 0.0,
     }
 }
diff --git a/src/tree/taffy_tree.rs b/src/tree/taffy_tree.rs
index 681328ec9..876058edc 100644
--- a/src/tree/taffy_tree.rs
+++ b/src/tree/taffy_tree.rs
@@ -92,8 +92,8 @@ struct NodeData {
     /// These may be rounded or unrounded depending on what the `use_rounding` config setting is set to.
     pub(crate) final_layout: Layout,
 
-    /// Should we try and measure this node?
-    pub(crate) needs_measure: bool,
+    /// Whether the node has context data associated with it or not
+    pub(crate) has_context: bool,
 
     /// The cached results of the layout computation
     pub(crate) cache: Cache,
@@ -108,7 +108,7 @@ impl NodeData {
             cache: Cache::new(),
             unrounded_layout: Layout::new(),
             final_layout: Layout::new(),
-            needs_measure: false,
+            has_context: false,
         }
     }
 
@@ -317,11 +317,11 @@ where
                 (_, false) => {
                     let node_key = node.into();
                     let style = &tree.taffy.nodes[node_key].style;
-                    let needs_measure = tree.taffy.nodes[node_key].needs_measure;
-                    let measure_function = needs_measure.then_some(|known_dimensions, available_space| {
-                        let node_context = tree.taffy.node_context_data.get_mut(node_key);
+                    let has_context = tree.taffy.nodes[node_key].has_context;
+                    let node_context = has_context.then(|| tree.taffy.node_context_data.get_mut(node_key)).flatten();
+                    let measure_function = |known_dimensions, available_space| {
                         (tree.measure_function)(known_dimensions, available_space, node, node_context)
-                    });
+                    };
                     compute_leaf_layout(inputs, style, measure_function)
                 }
             }
@@ -393,7 +393,7 @@ impl<NodeContext> TaffyTree<NodeContext> {
     /// Creates and adds a new leaf node with a supplied context
     pub fn new_leaf_with_context(&mut self, layout: Style, context: NodeContext) -> TaffyResult<NodeId> {
         let mut data = NodeData::new(layout);
-        data.needs_measure = true;
+        data.has_context = true;
 
         let id = self.nodes.insert(data);
         self.node_context_data.insert(id, context);
@@ -454,10 +454,10 @@ impl<NodeContext> TaffyTree<NodeContext> {
     pub fn set_node_context(&mut self, node: NodeId, measure: Option<NodeContext>) -> TaffyResult<()> {
         let key = node.into();
         if let Some(measure) = measure {
-            self.nodes[key].needs_measure = true;
+            self.nodes[key].has_context = true;
             self.node_context_data.insert(key, measure);
         } else {
-            self.nodes[key].needs_measure = false;
+            self.nodes[key].has_context = false;
             self.node_context_data.remove(key);
         }
 
diff --git a/tests/measure.rs b/tests/measure.rs
index 01d3461b2..be0afcab9 100644
--- a/tests/measure.rs
+++ b/tests/measure.rs
@@ -30,7 +30,7 @@ mod measure {
         _node_id: NodeId,
         node_context: Option<&mut AspectRatioMeasure>,
     ) -> taffy::geometry::Size<f32> {
-        let node_context = node_context.unwrap();
+        let Some(node_context) = node_context else { return Size::ZERO };
         let width = known_dimensions.width.unwrap_or(node_context.width);
         let height = known_dimensions.height.unwrap_or(width * node_context.height_ratio);
         Size { width, height }