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/taffy_tree.rs
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 {