tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 501HTML 254C 19JavaScript 81414 Sutichaykuna

Fix annoying issues with flex basis as compared to webkit output

58ca60fdf727554f7eb7649d434c64a9e87e8664 · ruwaq Emil Sjölander · (7 wata ñawpaq) · tayta 36643d46b · kay commitpi sach'ata qhaway

Semántico sayk'uy · 1

src/algo.rs

1 qillqakuna · +90 −34

diff --git a/src/algo.rs b/src/algo.rs
index fe4889e98..adfc2fecd 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -247,6 +247,7 @@ fn compute_internal(
         base - padding_cross - border_cross
     };
 
+    // TODO - this does not follow spec. See commented out code below
     // 3. Determine the flex base size and hypothetical main size of each item:
     for child in &mut flex_items {
         // A. If the item has a definite used flex basis, that’s the flex base size.
@@ -255,7 +256,7 @@ fn compute_internal(
         if flex_basis.is_finite() {
             child.flex_basis = flex_basis;
             continue;
-        }
+        };
 
         // B. If the flex item has an intrinsic aspect ratio,
         //    a used flex basis of content, and a definite cross size,
@@ -292,28 +293,28 @@ fn compute_internal(
         //    for a box in an orthogonal flow [CSS3-WRITING-MODES]. The flex base size
         //    is the item’s max-content main size.
 
-        if available_main.is_nan() {
-            let size = compute_internal(
-                child.node,
-                child
-                    .node
-                    .width
-                    .resolve(percent_calc_base_child, f32::NAN)
-                    .max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
-                    .min(child.node.max_width.resolve(percent_calc_base_child, f32::NAN)),
-                child
-                    .node
-                    .height
-                    .resolve(percent_calc_base_child, f32::NAN)
-                    .max(child.node.min_height.resolve(percent_calc_base_child, f32::NAN))
-                    .min(child.node.max_height.resolve(percent_calc_base_child, f32::NAN)),
-                if node.flex_direction.is_row() { available_main } else { available_cross },
-                if node.flex_direction.is_row() { available_cross } else { available_main },
-                percent_calc_base_child,
-            ).size;
-            child.flex_basis = size.main(node.flex_direction);
-            continue;
-        }
+        // if available_main.is_nan() {
+        //     let size = compute_internal(
+        //         child.node,
+        //         child
+        //             .node
+        //             .width
+        //             .resolve(percent_calc_base_child, f32::NAN)
+        //             .max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
+        //             .min(child.node.max_width.resolve(percent_calc_base_child, f32::NAN)),
+        //         child
+        //             .node
+        //             .height
+        //             .resolve(percent_calc_base_child, f32::NAN)
+        //             .max(child.node.min_height.resolve(percent_calc_base_child, f32::NAN))
+        //             .min(child.node.max_height.resolve(percent_calc_base_child, f32::NAN)),
+        //         if node.flex_direction.is_row() { available_main } else { available_cross },
+        //         if node.flex_direction.is_row() { available_cross } else { available_main },
+        //         percent_calc_base_child,
+        //     ).size;
+        //     child.flex_basis = size.main(node.flex_direction);
+        //     continue;
+        // }
 
         // E. Otherwise, size the item into the available space using its used flex basis
         //    in place of its main size, treating a value of content as max-content.
@@ -353,9 +354,28 @@ fn compute_internal(
         let border_end = child.node.main_border_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
         child.inner_flex_basis = child.flex_basis - (padding_start + padding_end + border_start + border_end);
 
+        // TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
+        // The following logic was developed not from the spec but by trail and error looking into how
+        // webkit handled various scenarios. Can probably be solved better by passing in
+        // min-content max-content constraints fromt the top
+        let min_main = if node.flex_direction.is_row() {
+            compute_internal(
+                child.node,
+                f32::NAN,
+                f32::NAN,
+                if node.flex_direction.is_row() { available_main } else { available_cross },
+                if node.flex_direction.is_row() { available_cross } else { available_main },
+                percent_calc_base_child,
+            ).size
+            .width
+            .min(child.node.width.resolve(percent_calc_base_child, f32::MAX))
+        } else {
+            child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MIN)
+        };
+
         child.hypothetical_inner_main_size = child
             .flex_basis
-            .max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MIN))
+            .max(min_main)
             .min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MAX))
             .max(0.0);
 
@@ -431,9 +451,35 @@ fn compute_internal(
         //      smaller than its hypothetical main size
 
         for child in line.items.iter_mut() {
+            // TODO - This is not found by reading the spec. Maybe this can be done in some other place
+            // instead. This was found by trail and error fixing tests to align with webkit output.
+            if node_inner_main.is_nan() && node.flex_direction.is_row() {
+                child.target_main_size = compute_internal(
+                    child.node,
+                    child
+                        .node
+                        .width
+                        .resolve(percent_calc_base_child, f32::NAN)
+                        .max(child.node.min_width.resolve(percent_calc_base_child, f32::NAN))
+                        .min(child.node.max_width.resolve(percent_calc_base_child, f32::NAN)),
+                    child
+                        .node
+                        .height
+                        .resolve(percent_calc_base_child, f32::NAN)
+                        .max(child.node.min_height.resolve(percent_calc_base_child, f32::NAN))
+                        .min(child.node.max_height.resolve(percent_calc_base_child, f32::NAN)),
+                    if node.flex_direction.is_row() { available_main } else { available_cross },
+                    if node.flex_direction.is_row() { available_cross } else { available_main },
+                    percent_calc_base_child,
+                ).size
+                .main(node.flex_direction);
+            } else {
+                child.target_main_size = child.hypothetical_inner_main_size;
+            }
+
             // TODO this should really only be set inside the if-statement below but
             // that casues the target_main_size to never be set for some items
-            child.target_main_size = child.hypothetical_inner_main_size;
+
             child.outer_target_main_size = child.target_main_size
                 + child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
                 + child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
@@ -549,18 +595,28 @@ fn compute_internal(
 
             let mut total_violation = 0.0;
             for child in &mut unfrozen {
-                let max = child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MAX);
-                let min =
-                    child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MIN).max(0.0);
-
-                let clamped = if child.target_main_size > max {
-                    max
-                } else if child.target_main_size < min {
-                    min
+                // TODO - not really spec abiding but needs to be done somewhere. probably somewhere else though.
+                // The following logic was developed not from the spec but by trail and error looking into how
+                // webkit handled various scenarios. Can probably be solved better by passing in
+                // min-content max-content constraints fromt the top
+                let min_main = if node.flex_direction.is_row() {
+                    compute_internal(
+                        child.node,
+                        f32::NAN,
+                        f32::NAN,
+                        if node.flex_direction.is_row() { available_main } else { available_cross },
+                        if node.flex_direction.is_row() { available_cross } else { available_main },
+                        percent_calc_base_child,
+                    ).size
+                    .width
+                    .min(child.node.width.resolve(percent_calc_base_child, f32::MAX))
                 } else {
-                    child.target_main_size
+                    child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MIN)
                 };
 
+                let max_main = child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MAX);
+
+                let clamped = child.target_main_size.min(max_main).max(min_main);
                 child.violation = clamped - child.target_main_size;
                 total_violation += child.violation;
                 child.target_main_size = clamped;