tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1077HTML 1008Markdown 12TOML 83209 Definiciones

Fix flexbox children being floored by padding/border

86ba2ffa6a0566fe04e83d5ceab798ba272888f0 · por Nico Burns · (hace 3 años) · padre bae7a8e8c · ver el árbol en este commit

Delta semántico · 4

src/compute/flexbox.rs

1 archivos · +56 −38

diff --git a/src/compute/flexbox.rs b/src/compute/flexbox.rs
index ba88eb606..25456cade 100644
--- a/src/compute/flexbox.rs
+++ b/src/compute/flexbox.rs
@@ -687,15 +687,15 @@ 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 padding_border_axes_sums = (child.padding + child.border).sum_axes().map(Some);
+        let hypothetical_inner_min_main =
+            child.min_size.main(constants.dir).maybe_max(padding_border_axes_sums.main(constants.dir));
+        let hypothetical_inner_size =
+            child.flex_basis.maybe_clamp(hypothetical_inner_min_main, child.max_size.main(constants.dir));
+        let hypothetical_outer_size = hypothetical_inner_size + child.margin.main_axis_sum(constants.dir);
+
+        child.hypothetical_inner_size.set_main(constants.dir, hypothetical_inner_size);
+        child.hypothetical_outer_size.set_main(constants.dir, hypothetical_outer_size);
 
         let min_content_size = GenericAlgorithm::measure_size(
             tree,
@@ -709,7 +709,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
         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);
+        child.resolved_minimum_size =
+            child.min_size.unwrap_or(clamped_min_content_size).maybe_max(padding_border_axes_sums);
     }
 }
 
@@ -810,7 +811,10 @@ fn determine_container_main_size(
                         let total_target_size = line
                             .items
                             .iter()
-                            .map(|child| child.flex_basis + child.margin.main_axis_sum(constants.dir))
+                            .map(|child| {
+                                let padding_border_sum = (child.padding + child.border).main_axis_sum(constants.dir);
+                                (child.flex_basis + child.margin.main_axis_sum(constants.dir)).max(padding_border_sum)
+                            })
                             .sum::<f32>();
                         total_target_size + line_main_axis_gap
                     })
@@ -831,7 +835,10 @@ fn determine_container_main_size(
                         let total_target_size = line
                             .items
                             .iter()
-                            .map(|child| child.flex_basis + child.margin.main_axis_sum(constants.dir))
+                            .map(|child| {
+                                let padding_border_sum = (child.padding + child.border).main_axis_sum(constants.dir);
+                                (child.flex_basis + child.margin.main_axis_sum(constants.dir)).max(padding_border_sum)
+                            })
                             .sum::<f32>();
                         total_target_size + line_main_axis_gap
                     })
@@ -852,21 +859,27 @@ fn determine_container_main_size(
                         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 resolved_min = item.resolved_minimum_size.main(constants.dir);
+                        let min_main_size = style_min
+                            .maybe_max(flex_basis_min)
+                            .or(flex_basis_min)
+                            .unwrap_or(resolved_min)
+                            .max(resolved_min);
+                        let max_main_size =
+                            style_max.maybe_min(flex_basis_max).or(flex_basis_max).unwrap_or(f32::INFINITY);
 
                         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 => {
+                            (min, Some(pref), 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),
+                            (min, _, max) if max <= min => min + 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.
+                                // TODO: Optimise by using already computed values where available
                                 let content_main_size = GenericAlgorithm::measure_size(
                                     tree,
                                     item.node,
@@ -891,9 +904,14 @@ fn determine_container_main_size(
                                 // 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)
+                                    content_main_size
+                                        .maybe_clamp(style_min, style_max)
+                                        .max(constants.padding_border.main_axis_sum(constants.dir))
                                 } else {
-                                    content_main_size.max(item.flex_basis).maybe_clamp(style_min, style_max)
+                                    content_main_size
+                                        .max(item.flex_basis)
+                                        .maybe_clamp(style_min, style_max)
+                                        .max(constants.padding_border.main_axis_sum(constants.dir))
                                 }
                             }
                         };
@@ -1162,13 +1180,15 @@ fn determine_hypothetical_cross_size(
     available_space: Size<AvailableSpace>,
 ) {
     for child in line.items.iter_mut() {
+        let padding_border_sum = (child.padding + child.border).cross_axis_sum(constants.dir);
+
         let child_cross = child
             .size
             .cross(constants.dir)
-            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir));
+            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir))
+            .maybe_max(padding_border_sum);
 
-        child.hypothetical_inner_size.set_cross(
-            constants.dir,
+        let child_inner_cross = child_cross.unwrap_or_else(|| {
             GenericAlgorithm::measure_size(
                 tree,
                 child.node,
@@ -1192,13 +1212,13 @@ fn determine_hypothetical_cross_size(
                 SizingMode::ContentSize,
             )
             .cross(constants.dir)
-            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir)),
-        );
+            .maybe_clamp(child.min_size.cross(constants.dir), child.max_size.cross(constants.dir))
+            .max(padding_border_sum)
+        });
+        let child_outer_cross = child_inner_cross + child.margin.cross_axis_sum(constants.dir);
 
-        child.hypothetical_outer_size.set_cross(
-            constants.dir,
-            child.hypothetical_inner_size.cross(constants.dir) + child.margin.cross_axis_sum(constants.dir),
-        );
+        child.hypothetical_inner_size.set_cross(constants.dir, child_inner_cross);
+        child.hypothetical_outer_size.set_cross(constants.dir, child_outer_cross);
     }
 }
 
@@ -1600,17 +1620,15 @@ fn determine_container_cross_size(
     let total_cross_axis_gap = sum_axis_gaps(constants.gap.cross(constants.dir), flex_lines.len());
     let total_line_cross_size: f32 = flex_lines.iter().map(|line| line.cross_size).sum::<f32>();
 
-    constants.container_size.set_cross(
-        constants.dir,
-        node_size.cross(constants.dir).unwrap_or(
-            total_line_cross_size + total_cross_axis_gap + constants.padding_border.cross_axis_sum(constants.dir),
-        ),
-    );
+    let padding_border_sum = constants.padding_border.cross_axis_sum(constants.dir);
+    let outer_container_size = node_size
+        .cross(constants.dir)
+        .unwrap_or(total_line_cross_size + total_cross_axis_gap + padding_border_sum)
+        .max(padding_border_sum);
+    let inner_container_size = outer_container_size - padding_border_sum;
 
-    constants.inner_container_size.set_cross(
-        constants.dir,
-        constants.container_size.cross(constants.dir) - constants.padding_border.cross_axis_sum(constants.dir),
-    );
+    constants.container_size.set_cross(constants.dir, outer_container_size);
+    constants.inner_container_size.set_cross(constants.dir, inner_container_size);
 
     total_line_cross_size
 }