Skip to content

Commit

Permalink
Upgrade to Taffy 0.4 (#10690)
Browse files Browse the repository at this point in the history
# Objective

- Enables support for `Display::Block`
- Enables support for `Overflow::Hidden`
- Allows for cleaner integration with text, image and other content
layout.
- Unblocks #8104
- Unlocks the possibility of Bevy creating a custom layout tree over
which Taffy operates.
- Enables #8808 / #10193 to remove a Mutex around the font system.

## Todo

- [x] ~Fix rendering of text/images to account for padding/border on
nodes (should size/position to content box rather than border box)~ In
order get this into a mergeable state this PR instead zeroes out
padding/border when syncing leaf node styles into Taffy to preserve the
existing behaviour. #6879 can
be fixed in a followup PR.

## Solution

- Update the version of Taffy
- Update code to work with the new version

Note: Taffy 0.4 has not yet been released. This PR is being created in
advance of the release to ensure that there are no blockers to upgrading
once the release occurs.

---

## Changelog

- Bevy now supports the `Display::Block` and `Overflow::Hidden` styles.
  • Loading branch information
nicoburns authored Apr 30, 2024
1 parent 9973f0c commit 96b9d0a
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 123 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ bevy_window = { path = "../bevy_window", version = "0.14.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.14.0-dev" }

# other
taffy = { version = "0.3.10" }
taffy = { version = "0.4" }
serde = { version = "1", features = ["derive"], optional = true }
bytemuck = { version = "1.5", features = ["derive"] }
thiserror = "1.0.0"
Expand Down
108 changes: 70 additions & 38 deletions crates/bevy_ui/src/layout/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use taffy::style_helpers;
use crate::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, GridAutoFlow,
GridPlacement, GridTrack, GridTrackRepetition, JustifyContent, JustifyItems, JustifySelf,
MaxTrackSizingFunction, MinTrackSizingFunction, PositionType, RepeatedGridTrack, Style, UiRect,
Val,
MaxTrackSizingFunction, MinTrackSizingFunction, OverflowAxis, PositionType, RepeatedGridTrack,
Style, UiRect, Val,
};

use super::LayoutContext;
Expand All @@ -18,31 +18,31 @@ impl Val {
Val::Auto => taffy::style::LengthPercentageAuto::Auto,
Val::Percent(value) => taffy::style::LengthPercentageAuto::Percent(value / 100.),
Val::Px(value) => {
taffy::style::LengthPercentageAuto::Points(context.scale_factor * value)
taffy::style::LengthPercentageAuto::Length(context.scale_factor * value)
}
Val::VMin(value) => {
taffy::style::LengthPercentageAuto::Points(context.min_size * value / 100.)
taffy::style::LengthPercentageAuto::Length(context.min_size * value / 100.)
}
Val::VMax(value) => {
taffy::style::LengthPercentageAuto::Points(context.max_size * value / 100.)
taffy::style::LengthPercentageAuto::Length(context.max_size * value / 100.)
}
Val::Vw(value) => {
taffy::style::LengthPercentageAuto::Points(context.physical_size.x * value / 100.)
taffy::style::LengthPercentageAuto::Length(context.physical_size.x * value / 100.)
}
Val::Vh(value) => {
taffy::style::LengthPercentageAuto::Points(context.physical_size.y * value / 100.)
taffy::style::LengthPercentageAuto::Length(context.physical_size.y * value / 100.)
}
}
}

fn into_length_percentage(self, context: &LayoutContext) -> taffy::style::LengthPercentage {
match self.into_length_percentage_auto(context) {
taffy::style::LengthPercentageAuto::Auto => taffy::style::LengthPercentage::Points(0.0),
taffy::style::LengthPercentageAuto::Auto => taffy::style::LengthPercentage::Length(0.0),
taffy::style::LengthPercentageAuto::Percent(value) => {
taffy::style::LengthPercentage::Percent(value)
}
taffy::style::LengthPercentageAuto::Points(value) => {
taffy::style::LengthPercentage::Points(value)
taffy::style::LengthPercentageAuto::Length(value) => {
taffy::style::LengthPercentage::Length(value)
}
}
}
Expand All @@ -63,9 +63,18 @@ impl UiRect {
}
}

pub fn from_style(context: &LayoutContext, style: &Style) -> taffy::style::Style {
pub fn from_style(
context: &LayoutContext,
style: &Style,
ignore_padding_and_border: bool,
) -> taffy::style::Style {
taffy::style::Style {
display: style.display.into(),
overflow: taffy::Point {
x: style.overflow.x.into(),
y: style.overflow.y.into(),
},
scrollbar_width: 0.0,
position: style.position_type.into(),
flex_direction: style.flex_direction.into(),
flex_wrap: style.flex_wrap.into(),
Expand All @@ -75,7 +84,7 @@ pub fn from_style(context: &LayoutContext, style: &Style) -> taffy::style::Style
justify_self: style.justify_self.into(),
align_content: style.align_content.into(),
justify_content: style.justify_content.into(),
inset: taffy::prelude::Rect {
inset: taffy::Rect {
left: style.left.into_length_percentage_auto(context),
right: style.right.into_length_percentage_auto(context),
top: style.top.into_length_percentage_auto(context),
Expand All @@ -84,29 +93,41 @@ pub fn from_style(context: &LayoutContext, style: &Style) -> taffy::style::Style
margin: style
.margin
.map_to_taffy_rect(|m| m.into_length_percentage_auto(context)),
padding: style
.padding
.map_to_taffy_rect(|m| m.into_length_percentage(context)),
border: style
.border
.map_to_taffy_rect(|m| m.into_length_percentage(context)),
// Ignore padding for leaf nodes as it isn't implemented in the rendering engine.
// TODO: Implement rendering of padding for leaf nodes
padding: if ignore_padding_and_border {
taffy::Rect::zero()
} else {
style
.padding
.map_to_taffy_rect(|m| m.into_length_percentage(context))
},
// Ignore border for leaf nodes as it isn't implemented in the rendering engine.
// TODO: Implement rendering of border for leaf nodes
border: if ignore_padding_and_border {
taffy::Rect::zero()
} else {
style
.border
.map_to_taffy_rect(|m| m.into_length_percentage(context))
},
flex_grow: style.flex_grow,
flex_shrink: style.flex_shrink,
flex_basis: style.flex_basis.into_dimension(context),
size: taffy::prelude::Size {
size: taffy::Size {
width: style.width.into_dimension(context),
height: style.height.into_dimension(context),
},
min_size: taffy::prelude::Size {
min_size: taffy::Size {
width: style.min_width.into_dimension(context),
height: style.min_height.into_dimension(context),
},
max_size: taffy::prelude::Size {
max_size: taffy::Size {
width: style.max_width.into_dimension(context),
height: style.max_height.into_dimension(context),
},
aspect_ratio: style.aspect_ratio,
gap: taffy::prelude::Size {
gap: taffy::Size {
width: style.column_gap.into_length_percentage(context),
height: style.row_gap.into_length_percentage(context),
},
Expand Down Expand Up @@ -231,11 +252,22 @@ impl From<Display> for taffy::style::Display {
match value {
Display::Flex => taffy::style::Display::Flex,
Display::Grid => taffy::style::Display::Grid,
Display::Block => taffy::style::Display::Block,
Display::None => taffy::style::Display::None,
}
}
}

impl From<OverflowAxis> for taffy::style::Overflow {
fn from(value: OverflowAxis) -> Self {
match value {
OverflowAxis::Visible => taffy::style::Overflow::Visible,
OverflowAxis::Clip => taffy::style::Overflow::Clip,
OverflowAxis::Hidden => taffy::style::Overflow::Hidden,
}
}
}

impl From<FlexDirection> for taffy::style::FlexDirection {
fn from(value: FlexDirection) -> Self {
match value {
Expand Down Expand Up @@ -489,7 +521,7 @@ mod tests {
grid_row: GridPlacement::span(3),
};
let viewport_values = LayoutContext::new(1.0, bevy_math::Vec2::new(800., 600.));
let taffy_style = from_style(&viewport_values, &bevy_style);
let taffy_style = from_style(&viewport_values, &bevy_style, false);
assert_eq!(taffy_style.display, taffy::style::Display::Flex);
assert_eq!(taffy_style.position, taffy::style::Position::Absolute);
assert_eq!(
Expand All @@ -502,7 +534,7 @@ mod tests {
);
assert_eq!(
taffy_style.inset.top,
taffy::style::LengthPercentageAuto::Points(12.)
taffy::style::LengthPercentageAuto::Length(12.)
);
assert_eq!(
taffy_style.inset.bottom,
Expand Down Expand Up @@ -537,7 +569,7 @@ mod tests {
);
assert_eq!(
taffy_style.margin.right,
taffy::style::LengthPercentageAuto::Points(10.)
taffy::style::LengthPercentageAuto::Length(10.)
);
assert_eq!(
taffy_style.margin.top,
Expand All @@ -553,7 +585,7 @@ mod tests {
);
assert_eq!(
taffy_style.padding.right,
taffy::style::LengthPercentage::Points(21.)
taffy::style::LengthPercentage::Length(21.)
);
assert_eq!(
taffy_style.padding.top,
Expand All @@ -565,7 +597,7 @@ mod tests {
);
assert_eq!(
taffy_style.border.left,
taffy::style::LengthPercentage::Points(14.)
taffy::style::LengthPercentage::Length(14.)
);
assert_eq!(
taffy_style.border.right,
Expand Down Expand Up @@ -594,18 +626,18 @@ mod tests {
);
assert_eq!(
taffy_style.grid_template_rows,
vec![sh::points(10.0), sh::percent(0.5), sh::fr(1.0)]
vec![sh::length(10.0), sh::percent(0.5), sh::fr(1.0)]
);
assert_eq!(
taffy_style.grid_template_columns,
vec![sh::repeat(5, vec![sh::points(10.0)])]
vec![sh::repeat(5, vec![sh::length(10.0)])]
);
assert_eq!(
taffy_style.grid_auto_rows,
vec![
sh::fit_content(taffy::style::LengthPercentage::Points(10.0)),
sh::fit_content(taffy::style::LengthPercentage::Length(10.0)),
sh::fit_content(taffy::style::LengthPercentage::Percent(0.25)),
sh::minmax(sh::points(0.0), sh::fr(2.0)),
sh::minmax(sh::length(0.0), sh::fr(2.0)),
]
);
assert_eq!(
Expand All @@ -627,17 +659,17 @@ mod tests {
use taffy::style::LengthPercentage;
let context = LayoutContext::new(2.0, bevy_math::Vec2::new(800., 600.));
let cases = [
(Val::Auto, LengthPercentage::Points(0.)),
(Val::Auto, LengthPercentage::Length(0.)),
(Val::Percent(1.), LengthPercentage::Percent(0.01)),
(Val::Px(1.), LengthPercentage::Points(2.)),
(Val::Vw(1.), LengthPercentage::Points(8.)),
(Val::Vh(1.), LengthPercentage::Points(6.)),
(Val::VMin(2.), LengthPercentage::Points(12.)),
(Val::VMax(2.), LengthPercentage::Points(16.)),
(Val::Px(1.), LengthPercentage::Length(2.)),
(Val::Vw(1.), LengthPercentage::Length(8.)),
(Val::Vh(1.), LengthPercentage::Length(6.)),
(Val::VMin(2.), LengthPercentage::Length(12.)),
(Val::VMax(2.), LengthPercentage::Length(16.)),
];
for (val, length) in cases {
assert!(match (val.into_length_percentage(&context), length) {
(LengthPercentage::Points(a), LengthPercentage::Points(b))
(LengthPercentage::Length(a), LengthPercentage::Length(b))
| (LengthPercentage::Percent(a), LengthPercentage::Percent(b)) =>
(a - b).abs() < 0.0001,
_ => false,
Expand Down
14 changes: 7 additions & 7 deletions crates/bevy_ui/src/layout/debug.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fmt::Write;

use taffy::prelude::Node;
use taffy::tree::LayoutTree;
use taffy::{NodeId, TraversePartialTree};

use bevy_ecs::prelude::Entity;
use bevy_utils::HashMap;
Expand All @@ -10,7 +9,7 @@ use crate::layout::ui_surface::UiSurface;

/// Prints a debug representation of the computed layout of the UI layout tree for each window.
pub fn print_ui_layout_tree(ui_surface: &UiSurface) {
let taffy_to_entity: HashMap<Node, Entity> = ui_surface
let taffy_to_entity: HashMap<NodeId, Entity> = ui_surface
.entity_to_taffy
.iter()
.map(|(entity, node)| (*node, *entity))
Expand All @@ -35,9 +34,9 @@ pub fn print_ui_layout_tree(ui_surface: &UiSurface) {
/// Recursively navigates the layout tree printing each node's information.
fn print_node(
ui_surface: &UiSurface,
taffy_to_entity: &HashMap<Node, Entity>,
taffy_to_entity: &HashMap<NodeId, Entity>,
entity: Entity,
node: Node,
node: NodeId,
has_sibling: bool,
lines_string: String,
acc: &mut String,
Expand All @@ -46,13 +45,14 @@ fn print_node(
let layout = tree.layout(node).unwrap();
let style = tree.style(node).unwrap();

let num_children = tree.child_count(node).unwrap();
let num_children = tree.child_count(node);

let display_variant = match (num_children, style.display) {
(_, taffy::style::Display::None) => "NONE",
(0, _) => "LEAF",
(_, taffy::style::Display::Flex) => "FLEX",
(_, taffy::style::Display::Grid) => "GRID",
(_, taffy::style::Display::Block) => "BLOCK",
};

let fork_string = if has_sibling {
Expand All @@ -70,7 +70,7 @@ fn print_node(
y = layout.location.y,
width = layout.size.width,
height = layout.size.height,
measured = if tree.needs_measure(node) { "measured" } else { "" }
measured = if tree.get_node_context(node).is_some() { "measured" } else { "" }
).ok();
let bar = if has_sibling { "│ " } else { " " };
let new_string = lines_string + bar;
Expand Down
Loading

0 comments on commit 96b9d0a

Please sign in to comment.