gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 1114HTML 1040Markdown 12TOML 94698 Definiciones

Move to iterators instead of loops to get ready for parrallel layout

519dc4fe01dc39aacb1809de8f2178c62b5967f4 · por Emil Sjölander · (hace 7 años) · padre 84d90de4a · ver el árbol en este commit

Delta semántico · 1

src/algo.rs

1 archivos · +154 −146

diff --git a/src/algo.rs b/src/algo.rs
index 74185fec0..80472b9c7 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -357,13 +357,13 @@ fn compute_internal(
 
     // 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 {
+    flex_items.iter_mut().for_each(|child| {
         // A. If the item has a definite used flex basis, that’s the flex base size.
 
         let flex_basis = child.node.flex_basis.resolve(percent_calc_base_child);
         if flex_basis.is_defined() {
             child.flex_basis = flex_basis.unwrap_or(0.0);
-            continue;
+            return;
         };
 
         // B. If the flex item has an intrinsic aspect ratio,
@@ -374,7 +374,7 @@ fn compute_internal(
         if let Defined(ratio) = child.node.aspect_ratio {
             if node_cross.is_defined() && child.node.flex_basis == style::Dimension::Auto {
                 child.flex_basis = (node_cross * ratio).unwrap_or(0.0);
-                continue;
+                return;
             }
         }
 
@@ -444,12 +444,12 @@ fn compute_internal(
         .size;
 
         child.flex_basis = size.main(node.flex_direction).maybe_max(child.min_main).maybe_min(child.max_main);
-    }
+    });
 
     // The hypothetical main size is the item’s flex base size clamped according to its
     // used min and max main sizes (and flooring the content box size at zero).
 
-    for child in &mut flex_items {
+    flex_items.iter_mut().for_each(|child| {
         child.inner_flex_basis = child.flex_basis
             - (child.padding_main_start + child.padding_main_end + child.border_main_start + child.border_main_end);
 
@@ -479,7 +479,7 @@ fn compute_internal(
 
         child.hypothetical_outer_main_size =
             child.hypothetical_inner_main_size + child.margin_main_start + child.margin_main_end;
-    }
+    });
 
     // 9.3. Main Size Determination
 
@@ -532,7 +532,7 @@ fn compute_internal(
     //
     // 9.7. Resolving Flexible Lengths
 
-    for line in &mut flex_lines {
+    flex_lines.iter_mut().for_each(|line| {
         // 1. Determine the used flex factor. Sum the outer hypothetical main sizes of all
         //    items on the line. If the sum is less than the flex container’s inner main size,
         //    use the flex grow factor for the rest of this algorithm; otherwise, use the
@@ -549,7 +549,7 @@ fn compute_internal(
         //    - If using the flex shrink factor: any item that has a flex base size
         //      smaller than its hypothetical main size
 
-        for child in line.items.iter_mut() {
+        line.items.iter_mut().for_each(|child| {
             // 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_undefined() && is_row {
@@ -580,7 +580,7 @@ fn compute_internal(
             {
                 child.frozen = true;
             }
-        }
+        });
 
         // 3. Calculate initial free space. Sum the outer sizes of all items on the line,
         //    and subtract this from the flex container’s inner main size. For frozen items,
@@ -607,13 +607,13 @@ fn compute_internal(
             let mut frozen: Vec<&mut FlexItem> = vec![];
             let mut unfrozen: Vec<&mut FlexItem> = vec![];
 
-            for child in line.items.iter_mut() {
+            line.items.iter_mut().for_each(|child| {
                 if child.frozen {
                     frozen.push(child);
                 } else {
                     unfrozen.push(child);
                 }
-            }
+            });
 
             if unfrozen.len() == 0 {
                 break;
@@ -688,7 +688,8 @@ fn compute_internal(
             //    If the item’s target main size was made larger by this, it’s a min violation.
 
             let mut total_violation = 0.0;
-            for child in &mut unfrozen {
+
+            unfrozen.iter_mut().for_each(|child| {
                 // 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
@@ -718,7 +719,7 @@ fn compute_internal(
                 total_violation += child.violation;
                 child.target_main_size = clamped;
                 child.outer_target_main_size = child.target_main_size + child.margin_main_start + child.margin_main_end;
-            }
+            });
 
             // e. Freeze over-flexed items. The total violation is the sum of the adjustments
             //    from the previous step ∑(clamped size - unclamped size). If the total violation is:
@@ -745,21 +746,22 @@ fn compute_internal(
 
             // f. Return to the start of this loop.
         }
-    }
+    });
 
     // Not part of the spec from what i can see but seems correct
     let container_main_size = if node_main.is_defined() {
         node_main.unwrap_or(0.0)
     } else {
-        let mut longest_line = f32::MIN;
-
-        for line in &flex_lines {
+        let longest_line = flex_lines.iter().fold(f32::MIN, |acc, line| {
             let length: f32 = line.items.iter().map(|item| item.outer_target_main_size).sum();
-            longest_line = if length > longest_line { length } else { longest_line };
-        }
+            if length > acc {
+                length
+            } else {
+                acc
+            }
+        });
 
         let size = longest_line + padding_main + border_main;
-
         match available_main {
             Defined(val) if flex_lines.len() > 1 && size < val => val,
             _ => size,
@@ -773,8 +775,8 @@ fn compute_internal(
     // 7. Determine the hypothetical cross size of each item by performing layout with the
     //    used main size and the available space, treating auto as fit-content.
 
-    for line in &mut flex_lines {
-        for child in &mut line.items {
+    flex_lines.iter_mut().for_each(|line| {
+        line.items.iter_mut().for_each(|child| {
             let child_cross = child.cross.maybe_max(child.min_cross).maybe_min(child.max_cross);
 
             let size = compute_internal(
@@ -792,8 +794,8 @@ fn compute_internal(
 
             child.hypothetical_outer_cross_size =
                 child.hypothetical_inner_cross_size + child.margin_cross_start + child.margin_cross_end;
-        }
-    }
+        });
+    });
 
     // TODO - probably should move this somewhere else as it doesn't make a ton of sense here but we need it below
     // TODO - This is expensive and should only be done if we really require a baseline. aka, make it lazy
@@ -806,8 +808,8 @@ fn compute_internal(
         }
     };
 
-    for line in &mut flex_lines {
-        for child in &mut line.items {
+    flex_lines.iter_mut().for_each(|line| {
+        line.items.iter_mut().for_each(|child| {
             let result = compute_internal(
                 child.node,
                 if is_row {
@@ -831,8 +833,8 @@ fn compute_internal(
                 y: 0.0,
                 children: result.children,
             });
-        }
-    }
+        });
+    });
 
     // 8. Calculate the cross size of each flex line.
     //    If the flex container is single-line and has a definite cross size, the cross size
@@ -845,7 +847,7 @@ fn compute_internal(
     if flex_lines.len() == 1 && node_cross.is_defined() {
         flex_lines[0].cross_size = (node_cross - padding_cross - border_cross).unwrap_or(0.0);
     } else {
-        for line in &mut flex_lines {
+        flex_lines.iter_mut().for_each(|line| {
             //    1. Collect all the flex items whose inline-axis is parallel to the main-axis, whose
             //       align-self is baseline, and whose cross-axis margins are both non-auto. Find the
             //       largest of the distances between each item’s baseline and its hypothetical outer
@@ -874,7 +876,7 @@ fn compute_internal(
                     }
                 })
                 .fold(0.0, |acc, x| acc.max(x));
-        }
+        });
     }
 
     // 9. Handle 'align-content: stretch'. If the flex container has a definite cross size,
@@ -924,8 +926,10 @@ fn compute_internal(
     //     Note that this step does not affect the main size of the flex item, even if it has an
     //     intrinsic aspect ratio.
 
-    for line in &mut flex_lines {
-        for child in &mut line.items {
+    flex_lines.iter_mut().for_each(|line| {
+        let line_cross_size = line.cross_size;
+
+        line.items.iter_mut().for_each(|child| {
             let is_stretch = child.node.align_self(node) == style::AlignSelf::Stretch;
 
             child.target_cross_size = if is_stretch
@@ -933,7 +937,7 @@ fn compute_internal(
                 && child.node.cross_margin_end(node.flex_direction) != style::Dimension::Auto
                 && child.node.cross_size(node.flex_direction) == style::Dimension::Auto
             {
-                (line.cross_size - child.margin_cross_start - child.margin_cross_end)
+                (line_cross_size - child.margin_cross_start - child.margin_cross_end)
                     .maybe_max(child.min_cross)
                     .maybe_min(child.max_cross)
             } else {
@@ -941,8 +945,8 @@ fn compute_internal(
             };
 
             child.outer_target_cross_size = child.target_cross_size + child.margin_cross_start + child.margin_cross_end;
-        }
-    }
+        });
+    });
 
     // 9.5. Main-Axis Alignment
 
@@ -952,31 +956,31 @@ fn compute_internal(
     //        set all auto margins to zero.
     //     2. Align the items along the main-axis per justify-content.
 
-    for line in &mut flex_lines {
+    flex_lines.iter_mut().for_each(|line| {
         let used_space: f32 = line.items.iter().map(|child| child.outer_target_main_size).sum();
         let free_space = inner_container_main_size - used_space;
         let mut num_auto_margins = 0;
 
-        for child in &mut line.items {
+        line.items.iter_mut().for_each(|child| {
             if child.node.main_margin_start(node.flex_direction) == style::Dimension::Auto {
                 num_auto_margins += 1;
             }
             if child.node.main_margin_end(node.flex_direction) == style::Dimension::Auto {
                 num_auto_margins += 1;
             }
-        }
+        });
 
         if free_space > 0.0 && num_auto_margins > 0 {
             let margin = free_space / num_auto_margins as f32;
 
-            for child in &mut line.items {
+            line.items.iter_mut().for_each(|child| {
                 if child.node.main_margin_start(node.flex_direction) == style::Dimension::Auto {
                     child.margin_main_start = margin;
                 }
                 if child.node.main_margin_end(node.flex_direction) == style::Dimension::Auto {
                     child.margin_main_end = margin;
                 }
-            }
+            });
         } else {
             let num_items = line.items.len();
             let mut is_first = true;
@@ -1031,7 +1035,7 @@ fn compute_internal(
                 line.items.iter_mut().for_each(justify_item);
             }
         }
-    }
+    });
 
     // 9.6. Cross-Axis Alignment
 
@@ -1043,11 +1047,12 @@ fn compute_internal(
     //       is auto, set it to zero. Set the opposite margin so that the outer cross size of the
     //       item equals the cross size of its flex line.
 
-    for line in &mut flex_lines {
+    flex_lines.iter_mut().for_each(|line| {
+        let line_cross_size = line.cross_size;
         let max_baseline: f32 = line.items.iter_mut().map(|child| child.baseline).fold(0.0, |acc, x| acc.max(x));
 
-        for child in &mut line.items {
-            let free_space = line.cross_size - child.outer_target_cross_size;
+        line.items.iter_mut().for_each(|child| {
+            let free_space = line_cross_size - child.outer_target_cross_size;
 
             if child.node.cross_margin_start(node.flex_direction) == style::Dimension::Auto
                 && child.node.cross_margin_end(node.flex_direction) == style::Dimension::Auto
@@ -1101,8 +1106,8 @@ fn compute_internal(
                     }
                 };
             }
-        }
-    }
+        });
+    });
 
     // 15. Determine the flex container’s used cross size:
     //     - If the cross size property is a definite size, use that, clamped by the used
@@ -1265,117 +1270,120 @@ fn compute_internal(
     let container_height = if is_column { container_main_size } else { container_cross_size };
 
     // Before returning we perform absolute layout on all absolutely positioned children
+    let mut absolute_children: Vec<layout::Node> = node
+        .children
+        .iter()
+        .filter(|child| child.position == style::Position::Absolute)
+        .map(|child| {
+            let container_width = container_width.to_number();
+            let container_height = container_height.to_number();
+
+            let start = child.start.resolve(container_width) + child.margin.start.resolve(container_width);
+            let end = child.end.resolve(container_width) + child.margin.end.resolve(container_width);
+            let top = child.top.resolve(container_height) + child.margin.top.resolve(container_height);
+            let bottom = child.bottom.resolve(container_height) + child.margin.bottom.resolve(container_height);
+
+            let (start_main, end_main) = if is_row { (start, end) } else { (top, bottom) };
+            let (start_cross, end_cross) = if is_row { (top, bottom) } else { (start, end) };
+
+            let child_width = child
+                .width
+                .resolve(container_width)
+                .maybe_max(child.min_width.resolve(container_width))
+                .maybe_min(child.max_width.resolve(container_width));
+
+            let child_height = child
+                .height
+                .resolve(container_height)
+                .maybe_max(child.min_height.resolve(container_height))
+                .maybe_min(child.max_height.resolve(container_height));
+
+            let width = if child_width.is_defined() { child_width } else { container_width - start - end };
+            let height = if child_height.is_defined() { child_height } else { container_height - top - bottom };
 
-    let absolute_children: Vec<&style::Node> =
-        node.children.iter().filter(|child| child.position == style::Position::Absolute).collect();
-
-    for child in absolute_children {
-        let container_width = container_width.to_number();
-        let container_height = container_height.to_number();
-
-        let start = child.start.resolve(container_width) + child.margin.start.resolve(container_width);
-        let end = child.end.resolve(container_width) + child.margin.end.resolve(container_width);
-        let top = child.top.resolve(container_height) + child.margin.top.resolve(container_height);
-        let bottom = child.bottom.resolve(container_height) + child.margin.bottom.resolve(container_height);
-
-        let (start_main, end_main) = if is_row { (start, end) } else { (top, bottom) };
-        let (start_cross, end_cross) = if is_row { (top, bottom) } else { (start, end) };
-
-        let child_width = child
-            .width
-            .resolve(container_width)
-            .maybe_max(child.min_width.resolve(container_width))
-            .maybe_min(child.max_width.resolve(container_width));
+            let result = compute_internal(
+                child,
+                width,
+                height,
+                if is_row { container_main_size.to_number() } else { container_cross_size.to_number() },
+                if is_row { container_cross_size.to_number() } else { container_main_size.to_number() },
+                container_width,
+            );
 
-        let child_height = child
-            .height
-            .resolve(container_height)
-            .maybe_max(child.min_height.resolve(container_height))
-            .maybe_min(child.max_height.resolve(container_height));
-
-        let width = if child_width.is_defined() { child_width } else { container_width - start - end };
-        let height = if child_height.is_defined() { child_height } else { container_height - top - bottom };
-
-        let result = compute_internal(
-            child,
-            width,
-            height,
-            if is_row { container_main_size.to_number() } else { container_cross_size.to_number() },
-            if is_row { container_cross_size.to_number() } else { container_main_size.to_number() },
-            container_width,
-        );
-
-        let free_main_space = container_main_size
-            - result
-                .size
-                .main(node.flex_direction)
-                .maybe_max(child.min_main_size(node.flex_direction).resolve(percent_calc_base_child))
-                .maybe_min(child.max_main_size(node.flex_direction).resolve(percent_calc_base_child));
+            let free_main_space = container_main_size
+                - result
+                    .size
+                    .main(node.flex_direction)
+                    .maybe_max(child.min_main_size(node.flex_direction).resolve(percent_calc_base_child))
+                    .maybe_min(child.max_main_size(node.flex_direction).resolve(percent_calc_base_child));
 
-        let free_cross_space = container_cross_size
-            - result
-                .size
-                .cross(node.flex_direction)
-                .maybe_max(child.min_cross_size(node.flex_direction).resolve(percent_calc_base_child))
-                .maybe_min(child.max_cross_size(node.flex_direction).resolve(percent_calc_base_child));
-
-        let offset_main = if start_main.is_defined() {
-            start_main.unwrap_or(0.0) + border_main_start
-        } else if end_main.is_defined() {
-            free_main_space - end_main.unwrap_or(0.0) - border_main_end
-        } else {
-            match node.justify_content {
-                style::JustifyContent::SpaceBetween | style::JustifyContent::FlexStart => {
-                    padding_main_start + border_main_start
+            let free_cross_space = container_cross_size
+                - result
+                    .size
+                    .cross(node.flex_direction)
+                    .maybe_max(child.min_cross_size(node.flex_direction).resolve(percent_calc_base_child))
+                    .maybe_min(child.max_cross_size(node.flex_direction).resolve(percent_calc_base_child));
+
+            let offset_main = if start_main.is_defined() {
+                start_main.unwrap_or(0.0) + border_main_start
+            } else if end_main.is_defined() {
+                free_main_space - end_main.unwrap_or(0.0) - border_main_end
+            } else {
+                match node.justify_content {
+                    style::JustifyContent::SpaceBetween | style::JustifyContent::FlexStart => {
+                        padding_main_start + border_main_start
+                    }
+                    style::JustifyContent::FlexEnd => free_main_space - padding_main_end - border_main_end,
+                    style::JustifyContent::SpaceEvenly
+                    | style::JustifyContent::SpaceAround
+                    | style::JustifyContent::Center => free_main_space / 2.0,
                 }
-                style::JustifyContent::FlexEnd => free_main_space - padding_main_end - border_main_end,
-                style::JustifyContent::SpaceEvenly
-                | style::JustifyContent::SpaceAround
-                | style::JustifyContent::Center => free_main_space / 2.0,
-            }
-        };
+            };
 
-        let offset_cross = if start_cross.is_defined() {
-            start_cross.unwrap_or(0.0) + border_cross_start
-        } else if end_cross.is_defined() {
-            free_cross_space - end_cross.unwrap_or(0.0) - border_cross_end
-        } else {
-            match child.align_self(node) {
-                style::AlignSelf::Auto => 0.0, // Should never happen
-                style::AlignSelf::FlexStart => {
-                    if is_wrap_reverse {
-                        free_cross_space - padding_cross_end - border_cross_end
-                    } else {
-                        padding_cross_start + border_cross_start
+            let offset_cross = if start_cross.is_defined() {
+                start_cross.unwrap_or(0.0) + border_cross_start
+            } else if end_cross.is_defined() {
+                free_cross_space - end_cross.unwrap_or(0.0) - border_cross_end
+            } else {
+                match child.align_self(node) {
+                    style::AlignSelf::Auto => 0.0, // Should never happen
+                    style::AlignSelf::FlexStart => {
+                        if is_wrap_reverse {
+                            free_cross_space - padding_cross_end - border_cross_end
+                        } else {
+                            padding_cross_start + border_cross_start
+                        }
                     }
-                }
-                style::AlignSelf::FlexEnd => {
-                    if is_wrap_reverse {
-                        padding_cross_start + border_cross_start
-                    } else {
-                        free_cross_space - padding_cross_end - border_cross_end
+                    style::AlignSelf::FlexEnd => {
+                        if is_wrap_reverse {
+                            padding_cross_start + border_cross_start
+                        } else {
+                            free_cross_space - padding_cross_end - border_cross_end
+                        }
                     }
-                }
-                style::AlignSelf::Center => free_cross_space / 2.0,
-                style::AlignSelf::Baseline => free_cross_space / 2.0, // Treat as center for now until we have baseline support
-                style::AlignSelf::Stretch => {
-                    if is_wrap_reverse {
-                        free_cross_space - padding_cross_end - border_cross_end
-                    } else {
-                        padding_cross_start + border_cross_start
+                    style::AlignSelf::Center => free_cross_space / 2.0,
+                    style::AlignSelf::Baseline => free_cross_space / 2.0, // Treat as center for now until we have baseline support
+                    style::AlignSelf::Stretch => {
+                        if is_wrap_reverse {
+                            free_cross_space - padding_cross_end - border_cross_end
+                        } else {
+                            padding_cross_start + border_cross_start
+                        }
                     }
                 }
+            };
+
+            layout::Node {
+                width: result.size.width,
+                height: result.size.height,
+                x: if is_row { offset_main } else { offset_cross },
+                y: if is_column { offset_main } else { offset_cross },
+                children: result.children,
             }
-        };
+        })
+        .collect();
 
-        children.push(layout::Node {
-            width: result.size.width,
-            height: result.size.height,
-            x: if is_row { offset_main } else { offset_cross },
-            y: if is_column { offset_main } else { offset_cross },
-            children: result.children,
-        });
-    }
+    children.append(&mut absolute_children);
 
     ComputeResult { size: FlexSize { width: container_width, height: container_height }, children }
 }