tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 709HTML 662Markdown 12TOML 62348 Definitions

Always base percentages off of parent width

1f3e77303ab0d36723ac6931a43c877bd4afb32e · by Emil Sjölander · (7 years ago) · parent e33b58809 · browse the tree at this commit

Semantic delta · 3

src/algo.rs

src/style.rs

2 files · +67 −54

diff --git a/src/algo.rs b/src/algo.rs
index c766c671a..2344599dd 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -94,7 +94,7 @@ struct FlexLine<'a> {
 }
 
 pub fn compute(root: &style::Node) -> layout::Node {
-    let result = compute_internal(root, SizeConstraint::undefined(), SizeConstraint::undefined());
+    let result = compute_internal(root, SizeConstraint::undefined(), SizeConstraint::undefined(), f32::NAN);
 
     round_layout(
         &layout::Node {
@@ -134,6 +134,11 @@ fn compute_internal(
     node: &style::Node,
     width_constraint: SizeConstraint,
     height_constraint: SizeConstraint,
+
+    // This will always be the parent width but we want to make
+    // it explicit what this parameter should be used for. It
+    // should only be used for calculated percentage values.
+    percent_calc_base: f32,
 ) -> ComputeResult {
     // Define some general constants we will need for the remainder
     // of the algorithm.
@@ -145,43 +150,43 @@ fn compute_internal(
     };
 
     let (intrinsic_main_size, intrinsic_cross_size) = (
-        node.main_size(node.flex_direction).resolve(main_constraint.max, f32::NAN),
-        node.cross_size(node.flex_direction).resolve(cross_constraint.max, f32::NAN),
+        node.main_size(node.flex_direction).resolve(percent_calc_base, f32::NAN),
+        node.cross_size(node.flex_direction).resolve(percent_calc_base, f32::NAN),
     );
 
     let (margin_main_start, margin_cross_start) = (
-        node.main_margin_start(node.flex_direction).resolve(main_constraint.max, 0.0),
-        node.cross_margin_start(node.flex_direction).resolve(main_constraint.max, 0.0),
+        node.main_margin_start(node.flex_direction).resolve(percent_calc_base, 0.0),
+        node.cross_margin_start(node.flex_direction).resolve(percent_calc_base, 0.0),
     );
 
     let (margin_main_end, margin_cross_end) = (
-        node.main_margin_end(node.flex_direction).resolve(main_constraint.max, 0.0),
-        node.cross_margin_end(node.flex_direction).resolve(main_constraint.max, 0.0),
+        node.main_margin_end(node.flex_direction).resolve(percent_calc_base, 0.0),
+        node.cross_margin_end(node.flex_direction).resolve(percent_calc_base, 0.0),
     );
 
     let (margin_main, margin_cross) = (margin_main_start + margin_main_end, margin_cross_start + margin_cross_end);
 
     let (padding_main_start, padding_cross_start) = (
-        node.main_padding_start(node.flex_direction).resolve(main_constraint.max, 0.0),
-        node.cross_padding_start(node.flex_direction).resolve(main_constraint.max, 0.0),
+        node.main_padding_start(node.flex_direction).resolve(percent_calc_base, 0.0),
+        node.cross_padding_start(node.flex_direction).resolve(percent_calc_base, 0.0),
     );
 
     let (padding_main_end, padding_cross_end) = (
-        node.main_padding_end(node.flex_direction).resolve(main_constraint.max, 0.0),
-        node.cross_padding_end(node.flex_direction).resolve(main_constraint.max, 0.0),
+        node.main_padding_end(node.flex_direction).resolve(percent_calc_base, 0.0),
+        node.cross_padding_end(node.flex_direction).resolve(percent_calc_base, 0.0),
     );
 
     let (padding_main, padding_cross) =
         (padding_main_start + padding_main_end, padding_cross_start + padding_cross_end);
 
     let (border_main_start, border_cross_start) = (
-        node.main_border_start(node.flex_direction).resolve(main_constraint.max, 0.0),
-        node.cross_border_start(node.flex_direction).resolve(main_constraint.max, 0.0),
+        node.main_border_start(node.flex_direction).resolve(percent_calc_base, 0.0),
+        node.cross_border_start(node.flex_direction).resolve(percent_calc_base, 0.0),
     );
 
     let (border_main_end, border_cross_end) = (
-        node.main_border_end(node.flex_direction).resolve(main_constraint.max, 0.0),
-        node.cross_border_end(node.flex_direction).resolve(main_constraint.max, 0.0),
+        node.main_border_end(node.flex_direction).resolve(percent_calc_base, 0.0),
+        node.cross_border_end(node.flex_direction).resolve(percent_calc_base, 0.0),
     );
 
     let (border_main, border_cross) = (border_main_start + border_main_end, border_cross_start + border_cross_end);
@@ -191,6 +196,8 @@ fn compute_internal(
 
     let wrap_reverse = node.flex_wrap == style::FlexWrap::WrapReverse;
 
+    let percent_calc_base_child = node.width.resolve(percent_calc_base, f32::NAN);
+
     // 9.2. Line Length Determination
 
     // 1. Generate anonymous flex items as described in §4 Flex Items.
@@ -232,12 +239,12 @@ fn compute_internal(
     //    in that dimension and use that value. This might result in an infinite value.
 
     let avaliable_main =
-        node.main_size(node.flex_direction).resolve(main_constraint.max, main_constraint.max - margin_main)
+        node.main_size(node.flex_direction).resolve(percent_calc_base, main_constraint.max - margin_main)
             - padding_main
             - border_main;
 
     let avaliable_cross =
-        node.cross_size(node.flex_direction).resolve(cross_constraint.max, cross_constraint.max - margin_cross)
+        node.cross_size(node.flex_direction).resolve(percent_calc_base, cross_constraint.max - margin_cross)
             - padding_cross
             - border_cross;
 
@@ -245,7 +252,7 @@ fn compute_internal(
     for child in &mut flex_items {
         // A. If the item has a definite used flex basis, that’s the flex base size.
 
-        let flex_basis = child.node.flex_basis.resolve(avaliable_main, f32::NAN);
+        let flex_basis = child.node.flex_basis.resolve(percent_calc_base_child, f32::NAN);
         if flex_basis.is_finite() {
             child.flex_basis = flex_basis;
             continue;
@@ -257,7 +264,7 @@ fn compute_internal(
         //    cross size and the flex item’s intrinsic aspect ratio.
 
         if let Some(ratio) = child.node.aspect_ratio {
-            let cross_size = child.node.cross_size(node.flex_direction).resolve(avaliable_cross, f32::NAN);
+            let cross_size = child.node.cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::NAN);
 
             if intrinsic_cross_size.is_finite() && child.node.flex_basis == style::Dimension::Auto {
                 child.flex_basis = ratio * cross_size;
@@ -276,6 +283,7 @@ fn compute_internal(
                 child.node,
                 if node.flex_direction.is_row() { main_constraint } else { SizeConstraint::undefined() },
                 if node.flex_direction.is_column() { main_constraint } else { SizeConstraint::undefined() },
+                percent_calc_base_child,
             ).size;
             child.flex_basis = size.main(node.flex_direction);
             continue;
@@ -288,7 +296,7 @@ fn compute_internal(
         //    is the item’s max-content main size.
 
         if avaliable_main.is_nan() {
-            let size = compute_internal(child.node, SizeConstraint::undefined(), SizeConstraint::undefined()).size;
+            let size = compute_internal(child.node, SizeConstraint::undefined(), SizeConstraint::undefined(), percent_calc_base_child).size;
             child.flex_basis = size.main(node.flex_direction);
             continue;
         }
@@ -312,6 +320,7 @@ fn compute_internal(
             } else {
                 SizeConstraint::at_most(avaliable_cross)
             },
+            percent_calc_base_child,
         ).size;
         child.flex_basis = size.main(node.flex_direction);
     }
@@ -320,21 +329,21 @@ fn compute_internal(
     // used min and max main sizes (and flooring the content box size at zero).
 
     for child in &mut flex_items {
-        let padding_start = child.node.main_padding_start(node.flex_direction).resolve(avaliable_main, 0.0);
-        let padding_end = child.node.main_padding_end(node.flex_direction).resolve(avaliable_main, 0.0);
-        let border_start = child.node.main_border_start(node.flex_direction).resolve(avaliable_main, 0.0);
-        let border_end = child.node.main_border_end(node.flex_direction).resolve(avaliable_main, 0.0);
+        let padding_start = child.node.main_padding_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+        let padding_end = child.node.main_padding_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+        let border_start = child.node.main_border_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
+        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);
 
         child.hypothetical_inner_main_size = child
             .flex_basis
-            .max(child.node.min_main_size(node.flex_direction).resolve(avaliable_main, f32::MIN))
-            .min(child.node.max_main_size(node.flex_direction).resolve(avaliable_main, f32::MAX))
+            .max(child.node.min_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MIN))
+            .min(child.node.max_main_size(node.flex_direction).resolve(percent_calc_base_child, f32::MAX))
             .max(0.0);
 
         child.hypothetical_outer_main_size = child.hypothetical_inner_main_size
-            + child.node.main_margin_start(node.flex_direction).resolve(avaliable_main, 0.0)
-            + child.node.main_margin_end(node.flex_direction).resolve(avaliable_main, 0.0);
+            + 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);
     }
 
     // 9.3. Main Size Determination
@@ -422,8 +431,8 @@ fn compute_internal(
             .items
             .iter()
             .map(|child| {
-                child.node.main_margin_start(node.flex_direction).resolve(avaliable_main, 0.0)
-                    + child.node.main_margin_end(node.flex_direction).resolve(avaliable_main, 0.0)
+                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)
                     + if child.frozen { child.target_main_size } else { child.flex_basis }
             }).sum();
 
@@ -458,8 +467,8 @@ fn compute_internal(
 
             let used_space: f32 = Iterator::chain(frozen.iter(), unfrozen.iter())
                 .map(|child| {
-                    child.node.main_margin_start(node.flex_direction).resolve(avaliable_main, 0.0)
-                        + child.node.main_margin_end(node.flex_direction).resolve(avaliable_main, 0.0)
+                    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)
                         + if child.frozen { child.target_main_size } else { child.flex_basis }
                 }).sum();
 
@@ -517,8 +526,8 @@ 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(avaliable_main, f32::MAX);
-                let min = child.node.min_main_size(node.flex_direction).resolve(avaliable_main, f32::MIN).max(0.0);
+                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
@@ -594,17 +603,18 @@ fn compute_internal(
                 } else {
                     SizeConstraint::between(cross_constraint.min, avaliable_cross)
                 },
+                percent_calc_base_child,
             ).size;
 
             child.hypothetical_inner_cross_size = size
                 .cross(node.flex_direction)
-                .max(child.node.min_cross_size(node.flex_direction).resolve(avaliable_cross, f32::MIN))
-                .min(child.node.max_cross_size(node.flex_direction).resolve(avaliable_cross, f32::MAX))
+                .max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::MIN))
+                .min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::MAX))
                 .max(0.0);
 
             child.hypothetical_outer_cross_size = child.hypothetical_inner_cross_size
-                + child.node.cross_margin_start(node.flex_direction).resolve(avaliable_cross, 0.0)
-                + child.node.cross_margin_end(node.flex_direction).resolve(avaliable_cross, 0.0);
+                + child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
+                + child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
         }
     }
 
@@ -694,8 +704,8 @@ fn compute_internal(
             {
                 child.target_cross_size = line
                     .cross_size
-                    .min(child.node.max_cross_size(node.flex_direction).resolve(avaliable_cross, f32::MAX))
-                    .max(child.node.min_cross_size(node.flex_direction).resolve(avaliable_cross, f32::MIN));
+                    .min(child.node.max_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::MAX))
+                    .max(child.node.min_cross_size(node.flex_direction).resolve(percent_calc_base_child, f32::MIN));
             } else {
                 child.target_cross_size = child.hypothetical_inner_cross_size;
             }
@@ -714,6 +724,7 @@ fn compute_internal(
                     } else {
                         SizeConstraint::exactly(child.target_cross_size)
                     },
+                    percent_calc_base_child,
                 );
             }
         }
@@ -760,9 +771,9 @@ fn compute_internal(
 
                 for child in &mut line.items {
                     child.main_margin_start =
-                        child.node.main_margin_start(node.flex_direction).resolve(container_main_size, 0.0);
+                        child.node.main_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
                     child.main_margin_end =
-                        child.node.main_margin_end(node.flex_direction).resolve(container_main_size, 0.0);
+                        child.node.main_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
 
                     child.offset_main = match node.justify_content {
                         style::JustifyContent::FlexStart => 0.0,
@@ -821,9 +832,9 @@ fn compute_internal(
                     child.cross_margin_end = free_space;
                 } else {
                     child.cross_margin_start =
-                        child.node.cross_margin_start(node.flex_direction).resolve(line.cross_size, 0.0);
+                        child.node.cross_margin_start(node.flex_direction).resolve(percent_calc_base_child, 0.0);
                     child.cross_margin_end =
-                        child.node.cross_margin_end(node.flex_direction).resolve(line.cross_size, 0.0);
+                        child.node.cross_margin_end(node.flex_direction).resolve(percent_calc_base_child, 0.0);
 
                     // 14. Align all flex items along the cross-axis per align-self, if neither of the item’s
                     //     cross-axis margins are auto.
@@ -934,14 +945,15 @@ fn compute_internal(
                         } else {
                             SizeConstraint::exactly(child.target_cross_size)
                         },
+                        percent_calc_base_child,
                     );
 
                     let offset_main = {
                         total_offset_main
                             + child.offset_main
                             + child.main_margin_start
-                            + (child.node.main_start(node.flex_direction).resolve(container_main_size, 0.0)
-                                - child.node.main_end(node.flex_direction).resolve(container_main_size, 0.0))
+                            + (child.node.main_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
+                                - child.node.main_end(node.flex_direction).resolve(percent_calc_base_child, 0.0))
                     };
 
                     let offset_cross = {
@@ -949,8 +961,8 @@ fn compute_internal(
                             + child.offset_cross
                             + line.offset_cross
                             + child.cross_margin_start
-                            + (child.node.cross_start(node.flex_direction).resolve(container_main_size, 0.0)
-                                - child.node.cross_end(node.flex_direction).resolve(container_main_size, 0.0))
+                            + (child.node.cross_start(node.flex_direction).resolve(percent_calc_base_child, 0.0)
+                                - child.node.cross_end(node.flex_direction).resolve(percent_calc_base_child, 0.0))
                     };
 
                     children.push(layout::Node {
@@ -988,16 +1000,16 @@ fn compute_internal(
         node.children.iter().filter(|child| child.position == style::Position::Absolute).collect();
 
     for child in absolute_children {
-        let start_main = child.main_start(node.flex_direction).resolve(container_main_size, f32::NAN);
-        let end_main = child.main_end(node.flex_direction).resolve(container_main_size, f32::NAN);
+        let start_main = child.main_start(node.flex_direction).resolve(percent_calc_base_child, f32::NAN);
+        let end_main = child.main_end(node.flex_direction).resolve(percent_calc_base_child, f32::NAN);
         let main = if start_main.is_finite() && end_main.is_finite() {
             container_main_size - start_main - end_main
         } else {
             f32::NAN
         };
 
-        let start_cross = child.cross_start(node.flex_direction).resolve(container_cross_size, f32::NAN);
-        let end_cross = child.cross_end(node.flex_direction).resolve(container_cross_size, f32::NAN);
+        let start_cross = child.cross_start(node.flex_direction).resolve(percent_calc_base_child, f32::NAN);
+        let end_cross = child.cross_end(node.flex_direction).resolve(percent_calc_base_child, f32::NAN);
         let cross = if start_cross.is_finite() && end_cross.is_finite() {
             container_cross_size - start_cross - end_cross
         } else {
@@ -1012,6 +1024,7 @@ fn compute_internal(
             } else {
                 SizeConstraint::exactly(cross)
             },
+            percent_calc_base_child,
         );
 
         let offset_main = if start_main.is_finite() {
diff --git a/src/style.rs b/src/style.rs
index a71a8d70c..3dd781c64 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -162,10 +162,10 @@ impl Default for Dimension {
 }
 
 impl Dimension {
-    pub(crate) fn resolve(&self, parent_size: f32, auto_size: f32) -> f32 {
+    pub(crate) fn resolve(&self, parent_width: f32, auto_size: f32) -> f32 {
         match self {
             Dimension::Points(points) => *points,
-            Dimension::Percent(percent) if parent_size.is_finite() => percent * parent_size,
+            Dimension::Percent(percent) if parent_width.is_finite() => percent * parent_width,
             _ => auto_size,
         }
     }