tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

Rust 499HTML 238Markdown 7TOML 31234 Definiciones

Migrate measure cache to general layout cache

1ec5ba56eb663ef80c7b1c39d74391a6f45e37eb · por Emil Sjölander · (hace 7 años) · padre 345bb6b17 · ver el árbol en este commit

Delta semántico · 6

src/algo.rs

src/style.rs

3 archivos · +72 −31

diff --git a/src/algo.rs b/src/algo.rs
index 6014c17cb..03e538436 100644
--- a/src/algo.rs
+++ b/src/algo.rs
@@ -11,10 +11,10 @@ use crate::number::*;
 
 use crate::geometry::{Point, Rect, Size};
 
-#[derive(Debug)]
-struct ComputeResult {
-    size: Size<f32>,
-    children: Vec<layout::Node>,
+#[derive(Debug, Clone)]
+pub struct ComputeResult {
+    pub size: Size<f32>,
+    pub children: Vec<layout::Node>,
 }
 
 struct FlexItem<'a> {
@@ -115,35 +115,54 @@ fn compute_internal(
     percent_calc_base: Number,
     perform_layout: bool,
 ) -> ComputeResult {
-    // If this is a leaf node we can skip a lot of this function in some cases
-    if node.children.is_empty() {
-        if node_size.width.is_defined() && node_size.height.is_defined() {
-            return ComputeResult { size: node_size.map(|s| s.or_else(0.0)), children: vec![] };
-        }
-
-        // Measure function can be extremely expensive to call so cache calls to it
-        if let Some(ref measure) = node.measure {
-            if let Some(cache) = node.measure_cache.get() {
+    // First we check if we have a result for the given input
+    {
+        let layout_cache = node.layout_cache.borrow();
+        if layout_cache.is_some() {
+            let cache = layout_cache.as_ref().unwrap();
+            if cache.perform_layout || !perform_layout {
                 let width_compatible = if let Number::Defined(width) = node_size.width {
-                    (width - cache.result.width).abs() < f32::EPSILON
+                    (width - cache.result.size.width).abs() < f32::EPSILON
                 } else {
-                    cache.constraint.width.is_undefined()
+                    cache.node_size.width.is_undefined()
                 };
 
                 let height_compatible = if let Number::Defined(height) = node_size.height {
-                    (height - cache.result.height).abs() < f32::EPSILON
+                    (height - cache.result.size.height).abs() < f32::EPSILON
                 } else {
-                    cache.constraint.height.is_undefined()
+                    cache.node_size.height.is_undefined()
                 };
 
-                if cache.constraint == node_size || (width_compatible && height_compatible) {
-                    return ComputeResult { size: cache.result, children: vec![] };
+                if width_compatible && height_compatible {
+                    return cache.result.clone();
+                }
+
+                if cache.node_size == node_size
+                    && cache.parent_size == parent_size
+                    && cache.percent_calc_base == percent_calc_base
+                {
+                    return cache.result.clone();
                 }
             }
+        }
+    }
+
+    // If this is a leaf node we can skip a lot of this function in some cases
+    if node.children.is_empty() {
+        if node_size.width.is_defined() && node_size.height.is_defined() {
+            return ComputeResult { size: node_size.map(|s| s.or_else(0.0)), children: vec![] };
+        }
 
-            let size = measure(node_size);
-            node.measure_cache.set(Some(MeasureCache { constraint: node_size, result: size }));
-            return ComputeResult { size, children: vec![] };
+        if let Some(ref measure) = node.measure {
+            let result = ComputeResult { size: measure(node_size), children: vec![] };
+            node.layout_cache.replace(Some(LayoutCache {
+                node_size,
+                parent_size,
+                percent_calc_base,
+                perform_layout,
+                result: result.clone(),
+            }));
+            return result;
         }
     }
 
@@ -1005,7 +1024,15 @@ fn compute_internal(
     // We have the container size. If our caller does not care about performing
     // layout we are done now.
     if !perform_layout {
-        return ComputeResult { size: container_size, children: vec![] };
+        let result = ComputeResult { size: container_size, children: vec![] };
+        node.layout_cache.replace(Some(LayoutCache {
+            node_size,
+            parent_size,
+            percent_calc_base,
+            perform_layout,
+            result: result.clone(),
+        }));
+        return result;
     }
 
     // 16. Align all flex lines per align-content.
@@ -1277,5 +1304,14 @@ fn compute_internal(
     children.append(&mut hidden_children);
 
     children.sort_by(|c1, c2| c1.order.cmp(&c2.order));
-    ComputeResult { size: container_size, children }
+
+    let result = ComputeResult { size: container_size, children };
+    node.layout_cache.replace(Some(LayoutCache {
+        node_size,
+        parent_size,
+        percent_calc_base,
+        perform_layout,
+        result: result.clone(),
+    }));
+    result
 }
diff --git a/src/layout.rs b/src/layout.rs
index eba832c68..f21c85861 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -1,6 +1,6 @@
 use crate::geometry::{Point, Size};
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct Node {
     pub(crate) order: u32,
     pub size: Size<f32>,
diff --git a/src/style.rs b/src/style.rs
index 75c9e6b37..2665d0ee5 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -1,3 +1,4 @@
+use crate::algo;
 use crate::geometry::{Rect, Size};
 use crate::number::Number;
 
@@ -193,10 +194,14 @@ impl Default for Size<Dimension> {
 
 type MeasureFunc = Box<Fn(Size<Number>) -> Size<f32>>;
 
-#[derive(Copy, Clone)]
-pub struct MeasureCache {
-    pub constraint: Size<Number>,
-    pub result: Size<f32>,
+#[derive(Debug, Clone)]
+pub struct LayoutCache {
+    pub node_size: Size<Number>,
+    pub parent_size: Size<Number>,
+    pub percent_calc_base: Number,
+    pub perform_layout: bool,
+
+    pub result: algo::ComputeResult,
 }
 
 pub struct Node {
@@ -233,7 +238,7 @@ pub struct Node {
 
     pub children: Vec<Node>,
 
-    pub measure_cache: std::cell::Cell<Option<MeasureCache>>,
+    pub layout_cache: std::cell::RefCell<Option<LayoutCache>>,
 }
 
 impl Default for Node {
@@ -272,7 +277,7 @@ impl Default for Node {
 
             children: vec![],
 
-            measure_cache: std::cell::Cell::new(None),
+            layout_cache: std::cell::RefCell::new(None),
         }
     }
 }