tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1077HTML 1008Markdown 12TOML 83209 Definiciones

Block stretch sizing fixes (#674)

* Block nodes should not stretch-fit themselves (stretch-fit sizing should
always be applied by the parent node)

* Stretch fit the root node if it is block display

9651a18b7da88204741018545edd13eda8fb2b53 · por Nico Burns · (hace 2 años) · padre 3230c91f2 · ver el árbol en este commit

Delta semántico · 2

src/compute/block.rs

src/compute/mod.rs

2 archivos · +51 −12

diff --git a/src/compute/block.rs b/src/compute/block.rs
index ea89f639c..fe6e54200 100644
--- a/src/compute/block.rs
+++ b/src/compute/block.rs
@@ -58,12 +58,11 @@ struct BlockItem {
 
 /// Computes the layout of [`LayoutPartialTree`] according to the block layout algorithm
 pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
-    let LayoutInput { known_dimensions, parent_size, available_space, run_mode, .. } = inputs;
+    let LayoutInput { known_dimensions, parent_size, run_mode, .. } = inputs;
     let style = tree.get_style(node_id);
 
     // Pull these out earlier to avoid borrowing issues
     let aspect_ratio = style.aspect_ratio;
-    let margin = style.margin.resolve_or_zero(parent_size.width);
     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 padding = style.padding.resolve_or_zero(parent_size.width);
@@ -81,15 +80,8 @@ pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId,
         _ => None,
     });
 
-    // Block nodes automatically stretch fit their width to fit available space if available space is definite
-    let available_space_based_size =
-        Size { width: available_space.width.into_option().maybe_sub(margin.horizontal_axis_sum()), height: None };
-
-    let styled_based_known_dimensions = known_dimensions
-        .or(min_max_definite_size)
-        .or(clamped_style_size)
-        .or(available_space_based_size)
-        .maybe_max(padding_border_size);
+    let styled_based_known_dimensions =
+        known_dimensions.or(min_max_definite_size).or(clamped_style_size).maybe_max(padding_border_size);
 
     // Short-circuit layout if the container's size is fully determined by the container's size and the run mode
     // is ComputeSize (and thus the container's size is all that we're interested in)
@@ -362,6 +354,8 @@ fn perform_final_layout_on_in_flow_children(
             let known_dimensions = item
                 .size
                 .map_width(|width| {
+                    // TODO: Allow stretch-sizing to be conditional, as there are exceptions.
+                    // e.g. Table children of blocks do not stretch fit
                     Some(
                         width
                             .unwrap_or(container_inner_width - item_non_auto_x_margin_sum)
diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index d9e787d50..b2279ddad 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -52,13 +52,58 @@ use crate::tree::{
 use crate::util::debug::{debug_log, debug_log_node, debug_pop_node, debug_push_node};
 use crate::util::sys::round;
 use crate::util::ResolveOrZero;
+use crate::{Display, MaybeMath, MaybeResolve};
 
 /// Compute layout for the root node in the tree
 pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, available_space: Size<AvailableSpace>) {
+    let mut known_dimensions = Size::NONE;
+
+    #[cfg(feature = "block_layout")]
+    {
+        let parent_size = available_space.into_options();
+        let style = tree.get_style(root);
+
+        if style.display == Display::Block {
+            // Pull these out earlier to avoid borrowing issues
+            let aspect_ratio = style.aspect_ratio;
+            let margin = style.margin.resolve_or_zero(parent_size.width);
+            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 padding = style.padding.resolve_or_zero(parent_size.width);
+            let border = style.border.resolve_or_zero(parent_size.width);
+            let padding_border_size = (padding + border).sum_axes();
+            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,
+            });
+
+            // Block nodes automatically stretch fit their width to fit available space if available space is definite
+            let available_space_based_size = Size {
+                width: available_space.width.into_option().maybe_sub(margin.horizontal_axis_sum()),
+                height: None,
+            };
+
+            let styled_based_known_dimensions = known_dimensions
+                .or(min_max_definite_size)
+                .or(clamped_style_size)
+                .or(available_space_based_size)
+                .maybe_max(padding_border_size);
+
+            known_dimensions = styled_based_known_dimensions;
+        }
+    }
+
     // Recursively compute node layout
     let output = tree.perform_child_layout(
         root,
-        Size::NONE,
+        known_dimensions,
         available_space.into_options(),
         available_space,
         SizingMode::InherentSize,