tawasuyu

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5544Rust 88Markdown 11TOML 91926 Definiciones

Fix `display:none` caching issue (#454)

* Fix compilation with debug feature

* Clear cache when applying hidden layout to a node

d52ab8f8305292875fbbe1b672c12daf63dca3be · por Nico Burns · (hace 3 años) · padre 2b5366e42 · ver el árbol en este commit

Delta semántico · 6

src/compute/mod.rs

src/compute/taffy_tree.rs

tests/relayout.rs

3 archivos · +76 −28

diff --git a/src/compute/mod.rs b/src/compute/mod.rs
index 63f227846..52205ca07 100644
--- a/src/compute/mod.rs
+++ b/src/compute/mod.rs
@@ -24,9 +24,6 @@ pub use self::grid::CssGridAlgorithm;
 #[cfg(feature = "taffy_tree")]
 pub(crate) mod taffy_tree;
 
-#[cfg(any(feature = "debug", feature = "profile"))]
-use crate::util::debug::NODE_LOGGER;
-
 /// A common interface that all Taffy layout algorithms conform to
 pub trait LayoutAlgorithm {
     /// The name of the algorithm (mainly used for debug purposes)
@@ -53,21 +50,6 @@ pub trait LayoutAlgorithm {
     ) -> SizeAndBaselines;
 }
 
-#[cfg(feature = "debug")]
-fn debug_log_node(
-    known_dimensions: Size<Option<f32>>,
-    parent_size: Size<Option<f32>>,
-    available_space: Size<AvailableSpace>,
-    run_mode: RunMode,
-    sizing_mode: SizingMode,
-) {
-    NODE_LOGGER.debug_log(run_mode);
-    NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
-    NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
-    NODE_LOGGER.labelled_debug_log("parent_size", parent_size);
-    NODE_LOGGER.labelled_debug_log("available_space", available_space);
-}
-
 /// The public interface to Taffy's hidden node algorithm implementation
 pub struct HiddenAlgorithm;
 impl LayoutAlgorithm for HiddenAlgorithm {
diff --git a/src/compute/taffy_tree.rs b/src/compute/taffy_tree.rs
index 27eae8319..4c9ed7b3c 100644
--- a/src/compute/taffy_tree.rs
+++ b/src/compute/taffy_tree.rs
@@ -1,6 +1,6 @@
 //! Computation specific for the default `Taffy` tree implementation
 
-use crate::compute::{leaf, HiddenAlgorithm, LayoutAlgorithm};
+use crate::compute::{leaf, LayoutAlgorithm};
 use crate::geometry::{Point, Size};
 use crate::style::{AvailableSpace, Display};
 use crate::tree::{Layout, LayoutTree, NodeId, RunMode, SizeAndBaselines, SizingMode, Taffy, TaffyError};
@@ -12,6 +12,24 @@ use crate::compute::FlexboxAlgorithm;
 #[cfg(feature = "grid")]
 use crate::compute::CssGridAlgorithm;
 
+#[cfg(any(feature = "debug", feature = "profile"))]
+use crate::util::debug::NODE_LOGGER;
+
+#[cfg(feature = "debug")]
+fn debug_log_node(
+    known_dimensions: Size<Option<f32>>,
+    parent_size: Size<Option<f32>>,
+    available_space: Size<AvailableSpace>,
+    run_mode: RunMode,
+    sizing_mode: SizingMode,
+) {
+    NODE_LOGGER.debug_log(run_mode);
+    NODE_LOGGER.labelled_debug_log("sizing_mode", sizing_mode);
+    NODE_LOGGER.labelled_debug_log("known_dimensions", known_dimensions);
+    NODE_LOGGER.labelled_debug_log("parent_size", parent_size);
+    NODE_LOGGER.labelled_debug_log("available_space", available_space);
+}
+
 /// Updates the stored layout of the provided `node` and its children
 pub(crate) fn compute_layout(
     taffy: &mut Taffy,
@@ -125,15 +143,10 @@ fn compute_node_layout(
 
     let display_mode = tree.nodes[node_key].style.display;
     let computed_size_and_baselines = match (display_mode, has_children) {
-        (Display::None, _) => perform_computations::<HiddenAlgorithm>(
-            tree,
-            node,
-            known_dimensions,
-            parent_size,
-            available_space,
-            run_mode,
-            sizing_mode,
-        ),
+        (Display::None, _) => {
+            perform_taffy_tree_hidden_layout(tree, node);
+            SizeAndBaselines { size: Size::ZERO, first_baselines: Point::NONE }
+        }
         #[cfg(feature = "flexbox")]
         (Display::Flex, true) => perform_computations::<FlexboxAlgorithm>(
             tree,
@@ -186,6 +199,24 @@ fn compute_node_layout(
     computed_size_and_baselines
 }
 
+/// Creates a layout for this node and its children, recursively.
+/// Each hidden node has zero size and is placed at the origin
+fn perform_taffy_tree_hidden_layout(tree: &mut Taffy, node: NodeId) {
+    /// Recursive function to apply hidden layout to all descendents
+    fn perform_hidden_layout_inner(tree: &mut Taffy, node: NodeId, order: u32) {
+        let node_key = node.into();
+        *tree.layout_mut(node) = Layout::with_order(order);
+        tree.nodes[node_key].cache.clear();
+        for order in 0..tree.children[node_key].len() {
+            perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
+        }
+    }
+
+    for order in 0..tree.children[node.into()].len() {
+        perform_hidden_layout_inner(tree, tree.child(node, order), order as _);
+    }
+}
+
 /// Rounds the calculated [`Layout`] to exact pixel values
 /// In order to ensure that no gaps in the layout are introduced we:
 ///   - Always round based on the absolute coordinates rather than parent-relative coordinates
diff --git a/tests/relayout.rs b/tests/relayout.rs
index 1f4695127..2575141ec 100644
--- a/tests/relayout.rs
+++ b/tests/relayout.rs
@@ -101,6 +101,41 @@ fn toggle_root_display_none() {
     assert_eq!(layout.size.height, 0.0);
 }
 
+#[test]
+fn toggle_root_display_none_with_children() {
+    use taffy::prelude::*;
+
+    let mut taffy = taffy::Taffy::new();
+
+    let child = taffy
+        .new_leaf(Style { size: Size { width: points(800.0), height: points(100.0) }, ..Default::default() })
+        .unwrap();
+
+    let parent = taffy
+        .new_with_children(
+            Style { size: Size { width: points(800.0), height: points(100.0) }, ..Default::default() },
+            &[child],
+        )
+        .unwrap();
+
+    let root = taffy.new_with_children(Style::default(), &[parent]).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    assert_eq!(taffy.layout(child).unwrap().size.width, 800.0);
+    assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
+
+    taffy.set_style(root, Style { display: Display::None, ..Default::default() }).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    assert_eq!(taffy.layout(child).unwrap().size.width, 0.0);
+    assert_eq!(taffy.layout(child).unwrap().size.height, 0.0);
+
+    taffy.set_style(root, Style::default()).unwrap();
+    taffy.compute_layout(root, Size::MAX_CONTENT).unwrap();
+    assert_eq!(taffy.layout(parent).unwrap().size.width, 800.0);
+    assert_eq!(taffy.layout(parent).unwrap().size.height, 100.0);
+    assert_eq!(taffy.layout(child).unwrap().size.width, 800.0);
+    assert_eq!(taffy.layout(child).unwrap().size.height, 100.0);
+}
+
 #[test]
 fn toggle_flex_child_display_none() {
     let hidden_style = Style {