Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare for 0.3.13 release #525

Merged
merged 10 commits into from
Aug 14, 2023
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "taffy"
version = "0.3.12"
version = "0.3.13"
authors = [
"Alice Cecile <alice.i.cecile@gmail.com>",
"Johnathan Kelley <jkelleyrtp@gmail.com>",
Expand All @@ -19,13 +19,13 @@ num-traits = { version = "0.2", default-features = false }
rand = { version = "0.8.5", optional = true }
serde = { version = "1.0", optional = true, features = ["serde_derive"] }
slotmap = "1.0.6"
grid = { version = "0.9.0", optional = true }
grid = { version = "0.10.0", default-features = false, optional = true }

[features]
default = ["std", "grid"]
grid = ["alloc", "dep:grid"]
alloc = []
std = ["num-traits/std"]
std = ["num-traits/std", "grid?/std"]
serde = ["dep:serde"]
random = ["dep:rand"]
yoga_benchmark = []
Expand Down
22 changes: 22 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Release Notes

## 0.3.13

### Fixes

- Fix rounding accumulation bug (#521) (Fixes #501 and bevyengine/bevy#8911)
- Flexbox: pass correct cross-axis available space when computing an item's intrinsic main size (#522)(Fixes bevyengine/bevy#9350)
- Flexbox: Subtract child margin not parent margin when computing stretch-alignment known size
- Grid: Make CSS Grid algorithm correctly apply max width/height and available space when it is the root node (#491)
- Grid: Fix CSS Grid "auto track" / placement bugs #481
- Fix divide by zero when using grid_auto_rows/grid_auto_columns with zero negative implicit tracks
- Fix over counting of tracks (leading to incorrect container heights) when auto-placing in grids that contain negative implicit tracks.
- Fix axis conflation in auto-placement code when grid_auto_flow is column
- Fix assignment of auto track sizes when initializing negative implicit tracks
- Leaf: Apply margins to leaf nodes when computing available space for measure functions
- Leaf: Reserve space for padding/borders in nodes with measure functions (#497)

**NOTE: This has the potential to break layouts relying on the old behaviour.** However, such layouts would be relying on a style having no effect, so it is judged that such layouts are unlikely to exist in the wild. If this turns out not to be true then this fix will be reverted on the 0.3.x branch.

### Dependencies

- Upgrade `grid` to `0.10`. This eliminates the transitive dependency on `no-std-compat`.

## 0.3.12

### Fixes
Expand Down
116 changes: 74 additions & 42 deletions scripts/gentest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,47 @@ use quote::{format_ident, quote};
use serde_json::Value;
use syn::Ident;

macro_rules! dim_quoted_renamed {
($obj:ident, $in_name:ident, $out_name:ident, $value_mapper:ident, $default:expr) => {
let $out_name = match $obj.get(stringify!($in_name)) {
Some(Value::Object(ref value)) => {
let dim = $value_mapper(value);
quote!($out_name: #dim,)
}
_ => {
let dim = $default;
quote!($out_name: #dim,)
}
};
};
}

macro_rules! dim_quoted {
($obj:ident, $dim_name:ident, $value_mapper: ident, $default:expr) => {
dim_quoted_renamed!($obj, $dim_name, $dim_name, $value_mapper, $default)
};
}

macro_rules! edges_quoted {
($style:ident, $val:ident, $value_mapper:ident, $default_value: expr) => {
let $val = match $style[stringify!($val)] {
Value::Object(ref value) => {
dim_quoted!(value, left, $value_mapper, $default_value);
dim_quoted!(value, right, $value_mapper, $default_value);
dim_quoted!(value, top, $value_mapper, $default_value);
dim_quoted!(value, bottom, $value_mapper, $default_value);

let edges = quote!(taffy::geometry::Rect {
#left #right #top #bottom
});

quote!($val: #edges,)
},
_ => quote!(),
};
};
}

#[tokio::main]
async fn main() {
env_logger::init();
Expand Down Expand Up @@ -127,6 +168,20 @@ fn generate_test(name: impl AsRef<str>, description: &Value) -> TokenStream {

let set_rounding_mode = if use_rounding { quote!() } else { quote!(taffy.disable_rounding();) };

// Compute available space
let viewport = &description["viewport"];
let available_space = if viewport["width"]["unit"] == "max-content" && viewport["height"]["unit"] == "max-content" {
quote!(taffy::geometry::Size::MAX_CONTENT)
} else {
dim_quoted!(viewport, width, generate_available_space, quote!(taffy::style::AvailableSpace::MAX_CONTENT));
dim_quoted!(viewport, height, generate_available_space, quote!(taffy::style::AvailableSpace::MAX_CONTENT));
quote!(
taffy::geometry::Size {
#width #height
}
)
};

quote!(
#[test]
fn #name() {
Expand All @@ -136,7 +191,7 @@ fn generate_test(name: impl AsRef<str>, description: &Value) -> TokenStream {
let mut taffy = taffy::Taffy::new();
#set_rounding_mode
#node_description
taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap();
taffy.compute_layout(node, #available_space).unwrap();

println!("\nComputed tree:");
taffy::debug::print_tree(&taffy, node);
Expand Down Expand Up @@ -191,47 +246,6 @@ fn generate_assertions(ident: &str, node: &Value, use_rounding: bool) -> TokenSt
}
}

macro_rules! dim_quoted_renamed {
($obj:ident, $in_name:ident, $out_name:ident, $value_mapper:ident, $default:expr) => {
let $out_name = match $obj.get(stringify!($in_name)) {
Some(Value::Object(ref value)) => {
let dim = $value_mapper(value);
quote!($out_name: #dim,)
}
_ => {
let dim = $default;
quote!($out_name: #dim,)
}
};
};
}

macro_rules! dim_quoted {
($obj:ident, $dim_name:ident, $value_mapper: ident, $default:expr) => {
dim_quoted_renamed!($obj, $dim_name, $dim_name, $value_mapper, $default)
};
}

macro_rules! edges_quoted {
($style:ident, $val:ident, $value_mapper:ident, $default_value: expr) => {
let $val = match $style[stringify!($val)] {
Value::Object(ref value) => {
dim_quoted!(value, left, $value_mapper, $default_value);
dim_quoted!(value, right, $value_mapper, $default_value);
dim_quoted!(value, top, $value_mapper, $default_value);
dim_quoted!(value, bottom, $value_mapper, $default_value);

let edges = quote!(taffy::geometry::Rect {
#left #right #top #bottom
});

quote!($val: #edges,)
},
_ => quote!(),
};
};
}

fn generate_node(ident: &str, node: &Value) -> TokenStream {
let style = &node["style"];

Expand Down Expand Up @@ -660,6 +674,24 @@ fn generate_dimension(dimen: &serde_json::Map<String, Value>) -> TokenStream {
}
}

fn generate_available_space(dimen: &serde_json::Map<String, Value>) -> TokenStream {
let unit = dimen.get("unit").unwrap();
let value = || dimen.get("value").unwrap().as_f64().unwrap() as f32;

match unit {
Value::String(ref unit) => match unit.as_ref() {
"max-content" => quote!(taffy::style::AvailableSpace::MaxContent),
"min-content" => quote!(taffy::style::AvailableSpace::MaxContent),
"points" => {
let value = value();
quote!(taffy::style::AvailableSpace::Definite(#value))
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}

fn generate_grid_auto_flow(auto_flow: &serde_json::Map<String, Value>) -> TokenStream {
let direction = auto_flow.get("direction").unwrap().as_str().unwrap();
let algorithm = auto_flow.get("algorithm").unwrap().as_str().unwrap();
Expand Down
28 changes: 18 additions & 10 deletions scripts/gentest/test_base_style.css
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@

/* The font "silkscreen" subsetted to only contain the"H" (capital h) glyph
The "H" glyph in this font happens to be exactly 10 pixels wide by 14 high
Furthermore, we can use a line-height of 0.71428571428 to scale the height to 10 pixels
/* The Ahem font. See: https://github.com/Kozea/Ahem
The "X" glyph in this font happens to be exactly 10 pixels wide by 10 high

By combining H's with zero-width space characters (&#8203;) we can reliably set an elements
By combining X's with zero-width space characters (&#8203;) we can reliably set an elements
min-content and max-content sizes.
*/
@font-face {
font-family: 'silkscreen-h';
src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOAABAAAAAAB7wAAAMkAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP0ZGVE0cGh4GVgCCWggoCWQRCAqBZIFjCw4AATYCJAMYBCAFhAgHRQxTG5IGAC4GnDLLNaI4Ih4+4mqyRg9HHA8fX6MqHp72+9+vvWfOXEdEkkaIJglvYpJJhEbI4o0QLSQ8tJ/ez/fn9/eeN4h3Sl/w0L7uB5CWVVeaGMPcBJ633fsTGVBiIcZj6bwqRjr/xwv9r0t5/9KdBfjyxtcttVqp2BpQ5igTsIwHKEClWemU7qWRJxTUvMlUEGFYTu6MiB4KAT+fp/dg+5v9Fv69218CBMZYBKQQOqEiEXk09nVq/s6XeKGtjZ/YGaTvuOsU8iDXv/GnFcEbKGugCQSgoGAFApzQKrBCmx3AUF9KE2vo188/xL88/d//tz8HAgCiEYBIJJqaQGH+cAUj836+xIwmiKdguu3lmr40xRRttVIHO9vba0mbR4MOy0bNii8ytRLxqinknInaInQ5/fyRo50El0++w51kOyRDQbdLiMP9JaQ7ndb6ImiT0iv8w9zYdBmYv0UBQkyZDRoYo2IJsAKAiqdaACFqHddRN6mnHNuQ1xoZxagOY6ibXWetv11yO7O8lNrMNr/YtP2GLBIM+xS27eNenffMPGrd71AqqStRoU7XEGjzf4SiWL7W1joeDmyy35U6kk1Hw1JyFFqXJYz6vaKF/UPjTYGsxZIgaOLfZSQfyPCjxejHY90mIBDM3vrQeXa2+LVrsW3mZzN9onlv0ZcgKGv+G/lfRwME063FM+sBMbP03UqzskBpxvIcqW+nHpxmAGDshSLqAEdAjLCAHWnsEopVMqjW2UVnh0M0C9zhiwk/+IqeEXzTFbu13w3E4Yl+FMuyKQ9LCUL8csB9bl9eLPMpwHKJgjRmMTEvLUUufpyCgjiMKi0nzCUqIS4vIAfDUqz1cJKPTefqCrvV87VoxnEZqOgQF58CRKEoDGFiQBg4hNjYhJj4l0Ng1adXbsD8Qm8ULUC3oeIOPrmyBGGh1yt5hDi40xlH52nomGIchmVkdMjyhaI87eSvdMkqisrJwRJagGndGDN+IzKKYlPa2tVb1UyE0Vm8E6WDQ+0fisnRquQDfePRqLVMer19ufM5pj3RRNRTJ2E/0i2NeZW75H150GioP1GlAAA=) format('woff2');
font-family: 'ahem';
src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgABAAAAAAXYAA0AAAAAKjgAAAWAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP0ZGVE0cGh4GYACEUhEQCrUAlzALg3AAATYCJAOHVgQgBYZQB4RFG5AYFeOYFbBxgM3u/5P9f53AyfVjdayDrHio6Mo1sl6KByXlCXnIVzSV5fT5TQ6ZXYT2USiITV79J77MWg5EBsol7qDhyo33x8P3c+Gf+142my1jCuTYlRUqFhJYETii8Z2qKkDFIPmzBIAMunuOxJGJPs+89lYS9Ec0RfnM0Mq1cEQnuxeTQGhm4JhuxBMZ4EBHEV1vjc4Fu7x5fMIF6JSO/8U5lc0B0A3VCXQhbYfk///VdNbjMwXYa1vASnF+7bd0/afj0z/RstqGAQUSRwFlCwcaZ1maalGAqYWaZhAIp0HbGFGhQp8R+fesEPDRAacNrm2GQQH4Yj1KJ9ANA5CE8LtQICHlL+OkliLdSodxIjppPDY1MknRAfZzqZd6AcCqaTlzdf8x5brZybVnteg9V2ZJ49QC2eMMgyGWIKTLKGIyFpirpdLdeHud1wBDLIvtcTo9TZ/me3U/MBAgQ0eIFMUoWdJlcnQ5uufoPjIjC7IjN6Mfo7/jfuP+/TE16K420VkXY0osJTGepPeBfUGBAxKT+N7qR/I7o/n99ma5sMfNpdn8778f/+vxxa27wV3/rnfXvivdpe6Ct5PbIVzANRzDEWzDBsxAAoyguwJ99HOvD8EOipKwViRk7A2KVtmuOl107da9R8/bQOaB8A+ceQBEmFDGhVTaWOdDnOZl3fbjvO7n/X4ty4uyqpu264dxmhfL1Xqz3e0Px9P5cr3dH09CoxWTnllYVtPY0NTS3Nre2dHV3dvT1z84PDQyNjo1OT1zxkBjCEe8OM274BCfdYFX5surkXt1+7j7ZhMBcoN4bXi/9v5gFx8jFerSxZW9/eOTg8Pxt/kyIJ/cIA5DO/tXSabE7IzcvPyc4hLEFaquXFjfdpW8vrEZ3tlaQ8gqSS/RyOAPiO/xC/kVxV1ADRIIhPayEkwZPFmF/VHetd2z3NS91a3du+zl1aO36LEDX4L21P96y+5f+qv+8ss34XX05bPtoNb3U1j23Ox8QHjXnz+Jjeh7z5m/VV3zl6+r2zXg/GWuUUk90q+Y/EuCia9U+V/Hi3vKH2k91NA5kbZXA39cAiZjp55uyKLoEGfIKFRxhpIecY6yOq5TYVC8ppYB8S2VqpTkXnoX6q1H6pPvU6bX9MyANJGem5xm0wtV2uR6qUxbj/iQDUm7DXkVyeQAoxApohs55BkYMxBARTYKQGkjUUiYlrTXGBSTjPdZNEwhsv5GiIu2WLutqCjOzBiNUCJVG2QEcri6wGFxMxBSkWAxQFvbyOdIvmgOfP2RUPAtqClwBVkbyNVkJIhXG06ZEQlFppEZcsCo8Jgh54qFAIdogE8JK7bbCCWduZxmZpdZQNvw9obxRlBsXOEYyGiQrvayDC6imNOoxRAvSK5Oi0j9dkxmgftX5lagZSZaGPpMFCeJmRL5zynRq5RLsUtvhRAgXnS+tgl8l86WDo2N/RgrP+RBKOZDEZsI70NJdph0Qz+iBDQi/djb/kBEiiz/cnqnqnR01U13PfTUS299vCeRyuQKpUqt0er0BiMAQjCCYjhBUjTDcrwgmswWq83ucLrcHq/PDw0DCwePgIiEjIKKho6BiYWNg4uHT0BIRExCSkZOQUlFrVuKmsaE1yMtK5OIgjTrjY4lcfn2w8JHbwX4F1X059e/pIota3ohaeVD26K3btOebTt2vTM4su9AH5w/DvuOnTD59C0DkZmVnY1DPRo3Fw8vP5+AoA8hEWFRYkQblyATK57Cqx+TDvRrGMk6dO/KtRt3Ltyq0tTS1bNqWMeaREtpStbNmhkzi/HLCwr40MIpLMfGzWOQwrZ5C2lFGe2oolOu9ndsWTO1zQnXTp7cFzWnznij+LuUYlVenjzayBbkk89aAgA=) format('woff2');
font-weight: normal;
font-style: normal;
}
Expand All @@ -32,11 +31,20 @@ body > * {
border-color: red;
}

.viewport {
display: flex;
align-items: start;
justify-content: start;
/* Defaults: can be overriden in individual tests */
width: max-content;
height: max-content;
}

#test-root {
font-family: silkscreen-h;
line-height: 0.71428571428;
font-size: 14px;
color: white;
font-family: ahem;
line-height: 1;
font-size: 10px;
color: green;
}

div {
Expand Down
16 changes: 16 additions & 0 deletions scripts/gentest/test_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ class TrackSizingParser {

}

function parseViewportConstraint(e) {
if (e.parentNode.classList.contains('viewport')) {
return {
width: parseDimension(e.parentNode.style.width || 'max-content'),
height: parseDimension(e.parentNode.style.height || 'max-content'),
}
} else {
return {
width: { unit: 'max-content' },
height: { unit: 'max-content' },
}
}
}

function parseRepetition(input) {
if (input === "auto-fill") return { unit: 'auto-fill' };
if (input === "auto-fit") return { unit: 'auto-fit' };
Expand Down Expand Up @@ -283,6 +297,8 @@ function describeElement(e) {
// Whether the test should enable rounding
useRounding: e.getAttribute("data-test-rounding") !== "false",

viewport: parseViewportConstraint(e),

children: Array.from(e.children).map(c => describeElement(c)),
}
}
Expand Down
40 changes: 31 additions & 9 deletions src/compute/flexbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,17 +265,24 @@ fn compute_preliminary(

// If container size is undefined, determine the container's main size
// and then re-resolve gaps based on newly determined size
#[cfg(feature = "debug")]
NODE_LOGGER.log("determine_container_main_size");
let original_gap = constants.gap;
if let Some(inner_main_size) = constants.node_inner_size.main(constants.dir) {
let outer_main_size = inner_main_size + constants.padding_border.main_axis_sum(constants.dir);
constants.inner_container_size.set_main(constants.dir, inner_main_size);
constants.container_size.set_main(constants.dir, outer_main_size);
} else {
// Sets constants.container_size and constants.outer_container_size
determine_container_main_size(tree, available_space.main(constants.dir), &mut flex_lines, &mut constants);
determine_container_main_size(tree, available_space, &mut flex_lines, &mut constants);
constants.node_inner_size.set_main(constants.dir, Some(constants.inner_container_size.main(constants.dir)));
constants.node_outer_size.set_main(constants.dir, Some(constants.container_size.main(constants.dir)));

#[cfg(feature = "debug")]
NODE_LOGGER.labelled_debug_log("constants.node_outer_size", constants.node_outer_size);
#[cfg(feature = "debug")]
NODE_LOGGER.labelled_debug_log("constants.node_inner_size", constants.node_inner_size);

// Re-resolve percentage gaps
let style = tree.style(node);
let inner_container_size = constants.inner_container_size.main(constants.dir);
Expand Down Expand Up @@ -352,7 +359,7 @@ fn compute_preliminary(
// 15. Determine the flex container’s used cross size.
#[cfg(feature = "debug")]
NODE_LOGGER.log("determine_container_cross_size");
let total_line_cross_size = determine_container_cross_size(&mut flex_lines, known_dimensions, &mut constants);
let total_line_cross_size = determine_container_cross_size(&flex_lines, known_dimensions, &mut constants);

// We have the container size.
// If our caller does not care about performing layout we are done now.
Expand Down Expand Up @@ -655,7 +662,7 @@ fn determine_flex_base_size(
.cross(dir)
.into_option()
.maybe_clamp(child_min_cross, child_max_cross)
.maybe_sub(constants.margin.cross_axis_sum(dir)),
.maybe_sub(child.margin.cross_axis_sum(dir)),
);
}
ckd
Expand Down Expand Up @@ -809,14 +816,15 @@ fn collect_flex_lines<'a>(
/// Determine the container's main size (if not already known)
fn determine_container_main_size(
tree: &mut impl LayoutTree,
main_axis_available_space: AvailableSpace,
available_space: Size<AvailableSpace>,
lines: &mut Vec<FlexLine<'_>>,
constants: &mut AlgoConstants,
) {
let dir = constants.dir;
let main_padding_border = constants.padding_border.main_axis_sum(constants.dir);

let outer_main_size: f32 = constants.node_outer_size.main(constants.dir).unwrap_or_else(|| {
match main_axis_available_space {
match available_space.main(dir) {
AvailableSpace::Definite(main_axis_available_space) => {
let longest_line_length: f32 = lines
.iter()
Expand Down Expand Up @@ -902,14 +910,28 @@ fn determine_container_main_size(
// Else compute the min- or -max content size and apply the full formula for computing the
// min- or max- content contributuon
_ => {
// Parent size for child sizing
let cross_axis_parent_size = constants.node_inner_size.cross(dir);

// Available space for child sizing
let cross_axis_margin_sum = constants.margin.cross_axis_sum(dir);
let child_min_cross = item.min_size.cross(dir).maybe_add(cross_axis_margin_sum);
let child_max_cross = item.max_size.cross(dir).maybe_add(cross_axis_margin_sum);
let cross_axis_available_space: AvailableSpace = available_space
.cross(dir)
.map_definite_value(|val| cross_axis_parent_size.unwrap_or(val))
.maybe_clamp(child_min_cross, child_max_cross);

let child_available_space = available_space.with_cross(dir, cross_axis_available_space);

// Either the min- or max- content size depending on which constraint we are sizing under.
// TODO: Optimise by using already computed values where available
let content_main_size = GenericAlgorithm::measure_size(
tree,
item.node,
Size::NONE,
constants.node_inner_size,
Size { width: main_axis_available_space, height: main_axis_available_space },
child_available_space,
SizingMode::InherentSize,
)
.main(constants.dir)
Expand Down Expand Up @@ -1436,7 +1458,7 @@ fn handle_align_content_stretch(flex_lines: &mut [FlexLine], node_size: Size<Opt
///
/// **Note that this step does not affect the main size of the flex item, even if it has an intrinsic aspect ratio**.
#[inline]
fn determine_used_cross_size(tree: &mut impl LayoutTree, flex_lines: &mut [FlexLine], constants: &AlgoConstants) {
fn determine_used_cross_size(tree: &impl LayoutTree, flex_lines: &mut [FlexLine], constants: &AlgoConstants) {
for line in flex_lines {
let line_cross_size = line.cross_size;

Expand Down Expand Up @@ -1595,7 +1617,7 @@ fn resolve_cross_axis_auto_margins(flex_lines: &mut [FlexLine], constants: &Algo
/// if neither of the item's cross-axis margins are `auto`.
#[inline]
fn align_flex_items_along_cross_axis(
child: &mut FlexItem,
child: &FlexItem,
free_space: f32,
max_baseline: f32,
constants: &AlgoConstants,
Expand Down Expand Up @@ -1653,7 +1675,7 @@ fn align_flex_items_along_cross_axis(
#[inline]
#[must_use]
fn determine_container_cross_size(
flex_lines: &mut [FlexLine],
flex_lines: &[FlexLine],
node_size: Size<Option<f32>>,
constants: &mut AlgoConstants,
) -> f32 {
Expand Down
Loading