Restore and fix gentest (#145)
* fix gentest
* regenerate tests
* fix doc comment (default value)
* simplify rounding
* do not take minimum size for flex-basis
* revert deleted files
* rename
* document fixes
* update doc on gentest
39cd0fcbbda7cd38cc6316e7339b1f3aed29e99f · por François · (hace 4 años) · padre c8f05e995 · ver el árbol en este commit
Delta semántico · 30
scripts/gentest/src/main.rs
scripts/gentest/test_helper.js
tests/generated/min_height.rs
tests/generated/min_width.rs
tests/generated/percentage_flex_basis_cross_min_height.rs
tests/generated/rounding_flex_basis_flex_grow_row_prime_number_width.rs
tests/generated/rounding_flex_basis_flex_grow_row_width_of_100.rs
tests/generated/rounding_flex_basis_overrides_main_size.rs
tests/generated/rounding_fractial_input_1.rs
tests/generated/rounding_fractial_input_2.rs
tests/generated/rounding_fractial_input_3.rs
tests/generated/rounding_fractial_input_4.rs
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f8afcda55..6f2b9c57f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -19,15 +19,14 @@ If you'd like to help on a consistent basis or are interested in project managem
Flexbox layouts are tested by validating that layouts written in this crate perform the same as in Chrome.
This is done by rendering an equivalent layout in HTML and then generating a Rust test case which asserts that the resulting layout is the same when run through our layout engine.
-You can run these tests without setting up a webdriver environment but if you are looking to add any test case you will need to install [chromedriver](http://chromedriver.chromium.org).
+You can run these tests without setting up a webdriver environment but if you are looking to add any test case you will need to install [chromedriver](http://chromedriver.chromium.org) and [Chrome](https://www.google.com/chrome/).
If you are developing on macOS this is easy to do through brew.
```bash
-brew tap homebrew/cask
-brew cask install chromedriver
+brew install chromedriver
```
-Once you have chromedriver installed and available in `PATH` you can re-generate all tests by running `cargo run --package gentest`.
+Once you have chromedriver installed and available in `PATH` you can re-generate all tests by running `cargo run --package gentest`. You should not manually update the tests in `tests/generated`. Instead, fix the script in `scripts/gentest/` and re-generate them. This can happen after a refactor. It can be helpful to commit the updated tests in a dedicated commit so that they can be easier to ignore during review.
To add a new test case add another HTML file to `/test_fixtures` following the current tests as a template for new tests.
diff --git a/Cargo.toml b/Cargo.toml
index 6f94af9a0..7faadc303 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,3 +44,6 @@ harness = false
name = "complex"
path = "benches/complex.rs"
harness = false
+
+[workspace]
+members = ["scripts/gentest"]
diff --git a/RELEASES.md b/RELEASES.md
index 5905c5f68..6b2c60724 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -14,7 +14,8 @@
### 0.2.0 Fixed
-- Nothing yet
+- fixed rounding of fractional values to follow latest Chrome - values are now rounded the same regardless of their position
+- fixed computing free space when using both `flex-grow` and a minimum size
### 0.2.0 Removed
diff --git a/scripts/gentest/Cargo.toml b/scripts/gentest/Cargo.toml
new file mode 100644
index 000000000..9070e7863
--- /dev/null
+++ b/scripts/gentest/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "gentest"
+version = "0.1.0"
+authors = ["Emil Sjölander <emil@visly.app>"]
+edition = "2018"
+
+[dependencies]
+env_logger = "0.9.0"
+fantoccini = "0.19.0"
+json = "0.12.0"
+log = "0.4"
+proc-macro2 = "1.0.6"
+quote = "1.0.2"
+serde_json = "1"
+syn = "1.0.7"
+tokio = { version = "1.18", features = [ "full" ] }
diff --git a/scripts/gentest/src/main.rs b/scripts/gentest/src/main.rs
new file mode 100644
index 000000000..7019b5a67
--- /dev/null
+++ b/scripts/gentest/src/main.rs
@@ -0,0 +1,482 @@
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+use fantoccini::{Client, ClientBuilder};
+use json;
+use log::*;
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::Ident;
+
+#[tokio::main]
+async fn main() {
+ env_logger::init();
+ // this requires being run by cargo, which is iffy
+ let root_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
+ let repo_root = root_dir.parent().and_then(Path::parent).unwrap();
+
+ let fixtures_root = repo_root.join("test_fixtures");
+ let fixtures = fs::read_dir(fixtures_root).unwrap();
+
+ info!("reading test fixtures from disk");
+ let mut fixtures: Vec<_> = fixtures
+ .into_iter()
+ .filter_map(|a| a.ok())
+ .filter(|f| f.path().is_file() && f.path().extension().map(|p| p == "html").unwrap_or(false))
+ .map(|f| {
+ let fixture_path = f.path().to_path_buf();
+ let name = fixture_path.file_stem().unwrap().to_str().unwrap().to_string();
+ (name, fixture_path)
+ })
+ .collect();
+ fixtures.sort_unstable_by_key(|f| f.0.clone());
+
+ info!("starting webdriver instance");
+ let webdriver_url = "http://localhost:4444";
+ let mut webdriver_handle = Command::new("chromedriver").arg("--port=4444").spawn().unwrap();
+
+ // this is silly, but it works
+ std::thread::sleep(std::time::Duration::from_secs(1));
+
+ let mut caps = serde_json::map::Map::new();
+ let chrome_opts = serde_json::json!({ "args": ["--headless", "--disable-gpu"] });
+ caps.insert("goog:chromeOptions".to_string(), chrome_opts.clone());
+
+ info!("spawning webdriver client and collecting test descriptions");
+ let client = ClientBuilder::native().capabilities(caps.clone()).connect(webdriver_url).await.unwrap();
+
+ let mut test_descs = vec![];
+ for (name, fixture_path) in fixtures {
+ test_descs.push(test_root_element(client.clone(), name, fixture_path).await);
+ }
+
+ info!("killing webdriver instance...");
+ webdriver_handle.kill().unwrap();
+
+ info!("generating test sources and concatenating...");
+
+ let bench_descs: Vec<_> = test_descs
+ .iter()
+ .map(|(name, description)| {
+ debug!("generating bench contents for {}", &name);
+ (name.clone(), generate_bench(description))
+ })
+ .collect();
+
+ let test_descs: Vec<_> = test_descs
+ .iter()
+ .map(|(name, description)| {
+ debug!("generating test contents for {}", &name);
+ (name.clone(), generate_test(name, description))
+ })
+ .collect();
+
+ let benchmarks: Vec<_> = test_descs
+ .iter()
+ .map(|(name, _)| {
+ let bench_mod = Ident::new(name, Span::call_site());
+ quote!(#bench_mod::compute())
+ })
+ .collect();
+
+ let test_mods = test_descs
+ .iter()
+ .map(|(name, _)| {
+ let name = Ident::new(name, Span::call_site());
+ quote!(mod #name;)
+ })
+ .fold(quote!(), |a, b| quote!(#a #b));
+
+ for (name, bench_body) in bench_descs {
+ let mut bench_filename = repo_root.join("benches").join("generated").join(&name);
+ bench_filename.set_extension("rs");
+ debug!("writing {} to disk...", &name);
+ fs::write(bench_filename, bench_body.to_string()).unwrap();
+ }
+
+ for (name, test_body) in test_descs {
+ let mut test_filename = repo_root.join("tests").join("generated").join(&name);
+ test_filename.set_extension("rs");
+ debug!("writing {} to disk...", &name);
+ fs::write(test_filename, test_body.to_string()).unwrap();
+ }
+
+ let bench_mods = quote!(
+ use criterion::{criterion_group, criterion_main, Criterion};
+
+ #test_mods
+
+ fn benchmark(c: &mut Criterion) {
+ c.bench_function("generated benchmarks", |b| {
+ b.iter(|| { #(#benchmarks;)* })
+ });
+ }
+
+ criterion_group!(benches, benchmark);
+ criterion_main!(benches);
+ );
+
+ info!("writing generated test file to disk...");
+ fs::write(repo_root.join("benches").join("generated").join("mod.rs"), bench_mods.to_string()).unwrap();
+ fs::write(repo_root.join("tests").join("generated").join("mod.rs"), test_mods.to_string()).unwrap();
+
+ info!("formatting the source directory");
+ Command::new("cargo").arg("fmt").current_dir(repo_root).status().unwrap();
+}
+
+async fn test_root_element(client: Client, name: String, fixture_path: impl AsRef<Path>) -> (String, json::JsonValue) {
+ let fixture_path = fixture_path.as_ref();
+
+ let url = format!("file://{}", fixture_path.display());
+
+ client.goto(&url).await.unwrap();
+ let description = client
+ .execute("return JSON.stringify(describeElement(document.getElementById('test-root')))", vec![])
+ .await
+ .unwrap();
+ let description_string = description.as_str().unwrap();
+ let description = json::parse(description_string).unwrap();
+ (name, description)
+}
+
+fn generate_bench(description: &json::JsonValue) -> TokenStream {
+ let node_description = generate_node("node", &description);
+
+ quote!(
+ pub fn compute() {
+ let mut taffy = taffy::Taffy::new();
+ #node_description
+ taffy.compute_layout(node, taffy::geometry::Size::undefined()).unwrap();
+ }
+ )
+}
+
+fn generate_test(name: impl AsRef<str>, description: &json::JsonValue) -> TokenStream {
+ let name = name.as_ref();
+ let name = Ident::new(name, Span::call_site());
+ let node_description = generate_node("node", &description);
+ let assertions = generate_assertions("node", &description);
+
+ quote!(
+ #[test]
+ fn #name() {
+ let mut taffy = taffy::Taffy::new();
+ #node_description
+ taffy.compute_layout(node, taffy::geometry::Size::undefined()).unwrap();
+ #assertions
+ }
+ )
+}
+
+fn generate_assertions(ident: &str, node: &json::JsonValue) -> TokenStream {
+ let layout = &node["layout"];
+
+ let read_f32 = |s: &str| layout[s].as_f32().unwrap();
+ let width = read_f32("width");
+ let height = read_f32("height");
+ let x = read_f32("x");
+ let y = read_f32("y");
+
+ let children = {
+ let mut c = Vec::new();
+ match node["children"] {
+ json::JsonValue::Array(ref value) => {
+ for i in 0..value.len() {
+ let child = &value[i];
+ c.push(generate_assertions(&format!("{}{}", ident, i), child));
+ }
+ }
+ _ => (),
+ };
+ c.into_iter().fold(quote!(), |a, b| quote!(#a #b))
+ };
+
+ let ident = Ident::new(ident, Span::call_site());
+
+ quote!(
+ assert_eq!(taffy.layout(#ident).unwrap().size.width, #width);
+ assert_eq!(taffy.layout(#ident).unwrap().size.height, #height);
+ assert_eq!(taffy.layout(#ident).unwrap().location.x, #x);
+ assert_eq!(taffy.layout(#ident).unwrap().location.y, #y);
+
+ #children
+ )
+}
+
+fn generate_node(ident: &str, node: &json::JsonValue) -> TokenStream {
+ let style = &node["style"];
+
+ let display = match style["display"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "none" => quote!(display: taffy::style::Display::None,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let position_type = match style["position_type"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "absolute" => quote!(position_type: taffy::style::PositionType::Absolute,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let direction = match style["direction"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "rtl" => quote!(direction: taffy::style::Direction::RTL,),
+ "ltr" => quote!(direction: taffy::style::Direction::LTR,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let flex_direction = match style["flexDirection"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "row-reverse" => quote!(flex_direction: taffy::style::FlexDirection::RowReverse,),
+ "column" => quote!(flex_direction: taffy::style::FlexDirection::Column,),
+ "column-reverse" => quote!(flex_direction: taffy::style::FlexDirection::ColumnReverse,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let flex_wrap = match style["flexWrap"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "wrap" => quote!(flex_wrap: taffy::style::FlexWrap::Wrap,),
+ "wrap-reverse" => quote!(flex_wrap: taffy::style::FlexWrap::WrapReverse,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let overflow = match style["overflow"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "hidden" => quote!(overflow: taffy::style::Overflow::Hidden,),
+ "scroll" => quote!(overflow: taffy::style::Overflow::Scroll,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let align_items = match style["alignItems"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "flex-start" => quote!(align_items: taffy::style::AlignItems::FlexStart,),
+ "flex-end" => quote!(align_items: taffy::style::AlignItems::FlexEnd,),
+ "center" => quote!(align_items: taffy::style::AlignItems::Center,),
+ "baseline" => quote!(align_items: taffy::style::AlignItems::Baseline,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let align_self = match style["alignSelf"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "flex-start" => quote!(align_self: taffy::style::AlignSelf::FlexStart,),
+ "flex-end" => quote!(align_self: taffy::style::AlignSelf::FlexEnd,),
+ "center" => quote!(align_self: taffy::style::AlignSelf::Center,),
+ "baseline" => quote!(align_self: taffy::style::AlignSelf::Baseline,),
+ "stretch" => quote!(align_self: taffy::style::AlignSelf::Stretch,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let align_content = match style["alignContent"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "flex-start" => quote!(align_content: taffy::style::AlignContent::FlexStart,),
+ "flex-end" => quote!(align_content: taffy::style::AlignContent::FlexEnd,),
+ "center" => quote!(align_content: taffy::style::AlignContent::Center,),
+ "space-between" => quote!(align_content: taffy::style::AlignContent::SpaceBetween,),
+ "space-around" => quote!(align_content: taffy::style::AlignContent::SpaceAround,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let justify_content = match style["justifyContent"] {
+ json::JsonValue::Short(ref value) => match value.as_ref() {
+ "flex-end" => quote!(justify_content: taffy::style::JustifyContent::FlexEnd,),
+ "center" => quote!(justify_content: taffy::style::JustifyContent::Center,),
+ "space-between" => quote!(justify_content: taffy::style::JustifyContent::SpaceBetween,),
+ "space-around" => quote!(justify_content: taffy::style::JustifyContent::SpaceAround,),
+ "space-evenly" => quote!(justify_content: taffy::style::JustifyContent::SpaceEvenly,),
+ _ => quote!(),
+ },
+ _ => quote!(),
+ };
+
+ let flex_grow = match style["flexGrow"] {
+ json::JsonValue::Number(value) => {
+ let value: f32 = value.into();
+ quote!(flex_grow: #value,)
+ }
+ _ => quote!(),
+ };
+
+ let flex_shrink = match style["flexShrink"] {
+ json::JsonValue::Number(value) => {
+ let value: f32 = value.into();
+ quote!(flex_shrink: #value,)
+ }
+ _ => quote!(),
+ };
+
+ let flex_basis = match style["flexBasis"] {
+ json::JsonValue::Object(ref value) => {
+ let value = generate_dimension(value);
+ quote!(flex_basis: #value,)
+ }
+ _ => quote!(),
+ };
+
+ let size = match style["size"] {
+ json::JsonValue::Object(ref value) => {
+ let size = generate_size(value);
+ quote!(size: #size,)
+ }
+ _ => quote!(),
+ };
+
+ let min_size = match style["min_size"] {
+ json::JsonValue::Object(ref value) => {
+ let min_size = generate_size(value);
+ quote!(min_size: #min_size,)
+ }
+ _ => quote!(),
+ };
+
+ let max_size = match style["max_size"] {
+ json::JsonValue::Object(ref value) => {
+ let max_size = generate_size(value);
+ quote!(max_size: #max_size,)
+ }
+ _ => quote!(),
+ };
+
+ macro_rules! edges_quoted {
+ ($style:ident, $val:ident) => {
+ let $val = match $style[stringify!($val)] {
+ json::JsonValue::Object(ref value) => {
+ let edges = generate_edges(value);
+ quote!($val: #edges,)
+ },
+ _ => quote!(),
+ };
+ };
+ }
+
+ edges_quoted!(style, margin);
+ edges_quoted!(style, padding);
+ edges_quoted!(style, position);
+ edges_quoted!(style, border);
+
+ let (children_body, children) = match node["children"] {
+ json::JsonValue::Array(ref value) => {
+ if value.len() > 0 {
+ let body = value
+ .iter()
+ .enumerate()
+ .map(|(i, child)| generate_node(&format!("{}{}", ident, i), child))
+ .collect();
+ let idents = value
+ .iter()
+ .enumerate()
+ .map(|(i, _)| Ident::new(&format!("{}{}", ident, i), Span::call_site()))
+ .collect::<Vec<_>>();
+ (body, quote!(&[#(#idents),*]))
+ } else {
+ (quote!(), quote!(&[]))
+ }
+ }
+ _ => (quote!(), quote!()),
+ };
+
+ let ident = Ident::new(&format!("{}", ident), Span::call_site());
+
+ quote!(
+ #children_body
+ let #ident = taffy.new_with_children(
+ taffy::style::FlexboxLayout {
+ #display
+ #direction
+ #position_type
+ #flex_direction
+ #flex_wrap
+ #overflow
+ #align_items
+ #align_self
+ #align_content
+ #justify_content
+ #flex_grow
+ #flex_shrink
+ #flex_basis
+ #size
+ #min_size
+ #max_size
+ #margin
+ #padding
+ #position
+ #border
+ ..Default::default()
+ },
+ #children
+ ).unwrap();)
+}
+
+macro_rules! dim_quoted {
+ ($obj:ident, $dim_name:ident) => {
+ let $dim_name = match $obj.get(stringify!($dim_name)) {
+ Some(json::JsonValue::Object(ref value)) => {
+ let dim = generate_dimension(value);
+ quote!($dim_name: #dim,)
+ }
+ _ => quote!(),
+ };
+ };
+}
+
+fn generate_size(size: &json::object::Object) -> TokenStream {
+ dim_quoted!(size, width);
+ dim_quoted!(size, height);
+ quote!(
+ taffy::geometry::Size {
+ #width #height
+ ..Default::default()
+ }
+ )
+}
+
+fn generate_dimension(dimen: &json::object::Object) -> TokenStream {
+ let unit = dimen.get("unit").unwrap();
+ let value = || dimen.get("value").unwrap().as_f32().unwrap();
+
+ match unit {
+ json::JsonValue::Short(ref unit) => match unit.as_ref() {
+ "auto" => quote!(taffy::style::Dimension::Auto),
+ "points" => {
+ let value = value();
+ quote!(taffy::style::Dimension::Points(#value))
+ }
+ "percent" => {
+ let value = value();
+ quote!(taffy::style::Dimension::Percent(#value))
+ }
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
+ }
+}
+
+fn generate_edges(dimen: &json::object::Object) -> TokenStream {
+ dim_quoted!(dimen, start);
+ dim_quoted!(dimen, end);
+ dim_quoted!(dimen, top);
+ dim_quoted!(dimen, bottom);
+
+ quote!(taffy::geometry::Rect {
+ #start #end #top #bottom
+ ..Default::default()
+ })
+}
diff --git a/scripts/gentest/test_base_style.css b/scripts/gentest/test_base_style.css
new file mode 100644
index 000000000..d9c038e3a
--- /dev/null
+++ b/scripts/gentest/test_base_style.css
@@ -0,0 +1,45 @@
+body {
+ padding: 0;
+ margin: 0;
+}
+
+div, span, img {
+ box-sizing: border-box;
+ position: relative;
+ border: 0 solid black;
+ margin: 0;
+ padding: 0;
+ display: flex;
+}
+
+body > * {
+ position: absolute;
+}
+
+div {
+ background-color: #222;
+}
+
+div > div {
+ background-color: #444;
+}
+
+div > div > div {
+ background-color: #666;
+}
+
+div > div > div > div {
+ background-color: #888;
+}
+
+div > div > div > div > div {
+ background-color: #aaa;
+}
+
+div > div > div > div > div > div {
+ background-color: #ccc;
+}
+
+div > div > div > div > div > div > div {
+ background-color: #eee;
+}
\ No newline at end of file
diff --git a/scripts/gentest/test_helper.js b/scripts/gentest/test_helper.js
new file mode 100644
index 000000000..4baf07b1d
--- /dev/null
+++ b/scripts/gentest/test_helper.js
@@ -0,0 +1,143 @@
+function define_element_prop(property, getter) {
+ if (!(property in Element.prototype)) {
+ Object.defineProperty(Element.prototype, property, {
+ get: function() {
+ return getter(this);
+ }
+ });
+ }
+}
+
+define_element_prop("__stretch_description__", (e) => {
+ return JSON.stringify(describeElement(e));
+});
+
+function parseDimension(input) {
+ if (input.endsWith("px")) {
+ return {
+ unit: 'points',
+ value: Number(input.replace('px',''))
+ };
+ } else if (input.endsWith("%")) {
+ return {
+ unit: 'percent',
+ value: Number(input.replace('%','')) / 100
+ };
+ } else {
+ return input == "auto" ? {unit: "auto"} : undefined;
+ }
+}
+
+function parseNumber(input) {
+ if (input === "" || isNaN(input)) {
+ return undefined;
+ } else {
+ return Number(input);
+ }
+}
+
+function parseEnum(input) {
+ if (input) {
+ return input;
+ } else {
+ return undefined;
+ }
+}
+
+function parseEdges(edges) {
+ var start = parseDimension(edges.start);
+ var end = parseDimension(edges.end);
+ var top = parseDimension(edges.top);
+ var bottom = parseDimension(edges.bottom);
+
+ if (start === undefined && end === undefined && top === undefined && bottom === undefined) {
+ return undefined;
+ }
+
+ return {
+ start: start,
+ end: end,
+ top: top,
+ bottom: bottom
+ };
+}
+
+function parseSize(size) {
+ var width = parseDimension(size.width);
+ var height = parseDimension(size.height);
+
+ if (width === undefined && height === undefined) {
+ return undefined;
+ }
+
+ return {
+ width: width,
+ height: height,
+ };
+}
+
+function describeElement(e) {
+ return {
+ style: {
+ display: parseEnum(e.style.display),
+
+ position_type: parseEnum(e.style.position),
+ direction: parseEnum(e.style.direction),
+ flexDirection: parseEnum(e.style.flexDirection),
+
+ flexWrap: parseEnum(e.style.flexWrap),
+ overflow: parseEnum(e.style.overflow),
+
+ alignItems: parseEnum(e.style.alignItems),
+ alignSelf: parseEnum(e.style.alignSelf),
+ alignContent: parseEnum(e.style.alignContent),
+
+ justifyContent: parseEnum(e.style.justifyContent),
+
+ flexGrow: parseNumber(e.style.flexGrow),
+ flexShrink: parseNumber(e.style.flexShrink),
+ flexBasis: parseDimension(e.style.flexBasis),
+
+ size: parseSize({width: e.style.width, height: e.style.height}),
+ min_size: parseSize({width: e.style.minWidth, height: e.style.minHeight}),
+ max_size: parseSize({width: e.style.maxWidth, height: e.style.maxHeight}),
+
+ margin: parseEdges({
+ start: e.style.marginLeft,
+ end: e.style.marginRight,
+ top: e.style.marginTop,
+ bottom: e.style.marginBottom,
+ }),
+
+ padding: parseEdges({
+ start: e.style.paddingLeft,
+ end: e.style.paddingRight,
+ top: e.style.paddingTop,
+ bottom: e.style.paddingBottom,
+ }),
+
+ border: parseEdges({
+ start: e.style.borderLeftWidth,
+ end: e.style.borderRightWidth,
+ top: e.style.borderTopWidth,
+ bottom: e.style.borderBottomWidth,
+ }),
+
+ position: parseEdges({
+ start: e.style.left,
+ end: e.style.right,
+ top: e.style.top,
+ bottom: e.style.bottom,
+ }),
+ },
+
+ layout: {
+ width: e.offsetWidth,
+ height: e.offsetHeight,
+ x: e.offsetLeft + e.parentNode.clientLeft,
+ y: e.offsetTop + e.parentNode.clientTop,
+ },
+
+ children: Array.from(e.children).map(c => describeElement(c)),
+ }
+}
diff --git a/src/flexbox.rs b/src/flexbox.rs
index c579547d2..661ad37c3 100644
--- a/src/flexbox.rs
+++ b/src/flexbox.rs
@@ -151,8 +151,8 @@ impl Forest {
layout.location.x = round(layout.location.x);
layout.location.y = round(layout.location.y);
- layout.size.width = round(abs_x + layout.size.width) - round(abs_x);
- layout.size.height = round(abs_y + layout.size.height) - round(abs_y);
+ layout.size.width = round(layout.size.width);
+ layout.size.height = round(layout.size.height);
for child in &children[root] {
Self::round_layout(nodes, children, *child, abs_x, abs_y);
@@ -418,15 +418,14 @@ impl Forest {
.compute_preliminary(
child.node,
Size {
- width: width.maybe_max(child.min_size.width).maybe_min(child.max_size.width),
- height: height.maybe_max(child.min_size.height).maybe_min(child.max_size.height),
+ width: width.maybe_min(child.max_size.width),
+ height: height.maybe_min(child.max_size.height),
},
available_space,
false,
true,
)
.main(constants.dir)
- .maybe_max(child.min_size.main(constants.dir))
.maybe_min(child.max_size.main(constants.dir));
}
diff --git a/src/style.rs b/src/style.rs
index 2cd8e7740..fdab50f61 100644
--- a/src/style.rs
+++ b/src/style.rs
@@ -344,7 +344,7 @@ pub struct FlexboxLayout {
pub border: Rect<Dimension>,
/// The relative rate at which this item grows when it is expanding to fill space
///
- /// 1.0 is the default value, and this value must be positive.
+ /// 0.0 is the default value, and this value must be positive.
pub flex_grow: f32,
/// The relative rate at which this item shrinks when it is contracting to fit into space
///
diff --git a/tests/generated/min_height.rs b/tests/generated/min_height.rs
index 986204bdb..77fdd9471 100644
--- a/tests/generated/min_height.rs
+++ b/tests/generated/min_height.rs
@@ -36,11 +36,11 @@ fn min_height() {
assert_eq!(taffy.layout(node).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node0).unwrap().size.width, 100f32);
- assert_eq!(taffy.layout(node0).unwrap().size.height, 80f32);
+ assert_eq!(taffy.layout(node0).unwrap().size.height, 60f32);
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node1).unwrap().size.width, 100f32);
- assert_eq!(taffy.layout(node1).unwrap().size.height, 20f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.height, 40f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 0f32);
- assert_eq!(taffy.layout(node1).unwrap().location.y, 80f32);
+ assert_eq!(taffy.layout(node1).unwrap().location.y, 60f32);
}
diff --git a/tests/generated/min_width.rs b/tests/generated/min_width.rs
index eed19829c..83b877818 100644
--- a/tests/generated/min_width.rs
+++ b/tests/generated/min_width.rs
@@ -31,12 +31,12 @@ fn min_width() {
assert_eq!(taffy.layout(node).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node).unwrap().location.y, 0f32);
- assert_eq!(taffy.layout(node0).unwrap().size.width, 80f32);
+ assert_eq!(taffy.layout(node0).unwrap().size.width, 60f32);
assert_eq!(taffy.layout(node0).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
- assert_eq!(taffy.layout(node1).unwrap().size.width, 20f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.width, 40f32);
assert_eq!(taffy.layout(node1).unwrap().size.height, 100f32);
- assert_eq!(taffy.layout(node1).unwrap().location.x, 80f32);
+ assert_eq!(taffy.layout(node1).unwrap().location.x, 60f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 0f32);
}
diff --git a/tests/generated/percentage_flex_basis_cross_min_height.rs b/tests/generated/percentage_flex_basis_cross_min_height.rs
index 1ae5cff41..7dbb75119 100644
--- a/tests/generated/percentage_flex_basis_cross_min_height.rs
+++ b/tests/generated/percentage_flex_basis_cross_min_height.rs
@@ -47,11 +47,11 @@ fn percentage_flex_basis_cross_min_height() {
assert_eq!(taffy.layout(node).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node0).unwrap().size.width, 200f32);
- assert_eq!(taffy.layout(node0).unwrap().size.height, 280f32);
+ assert_eq!(taffy.layout(node0).unwrap().size.height, 240f32);
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node1).unwrap().size.width, 200f32);
- assert_eq!(taffy.layout(node1).unwrap().size.height, 120f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.height, 160f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 0f32);
- assert_eq!(taffy.layout(node1).unwrap().location.y, 280f32);
+ assert_eq!(taffy.layout(node1).unwrap().location.y, 240f32);
}
diff --git a/tests/generated/rounding_flex_basis_flex_grow_row_prime_number_width.rs b/tests/generated/rounding_flex_basis_flex_grow_row_prime_number_width.rs
index e97ea6e62..75ed48a30 100644
--- a/tests/generated/rounding_flex_basis_flex_grow_row_prime_number_width.rs
+++ b/tests/generated/rounding_flex_basis_flex_grow_row_prime_number_width.rs
@@ -33,7 +33,7 @@ fn rounding_flex_basis_flex_grow_row_prime_number_width() {
assert_eq!(taffy.layout(node0).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
- assert_eq!(taffy.layout(node1).unwrap().size.width, 22f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.width, 23f32);
assert_eq!(taffy.layout(node1).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 23f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 0f32);
@@ -41,7 +41,7 @@ fn rounding_flex_basis_flex_grow_row_prime_number_width() {
assert_eq!(taffy.layout(node2).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node2).unwrap().location.x, 45f32);
assert_eq!(taffy.layout(node2).unwrap().location.y, 0f32);
- assert_eq!(taffy.layout(node3).unwrap().size.width, 22f32);
+ assert_eq!(taffy.layout(node3).unwrap().size.width, 23f32);
assert_eq!(taffy.layout(node3).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node3).unwrap().location.x, 68f32);
assert_eq!(taffy.layout(node3).unwrap().location.y, 0f32);
diff --git a/tests/generated/rounding_flex_basis_flex_grow_row_width_of_100.rs b/tests/generated/rounding_flex_basis_flex_grow_row_width_of_100.rs
index e8afb1b67..eadb3f2bc 100644
--- a/tests/generated/rounding_flex_basis_flex_grow_row_width_of_100.rs
+++ b/tests/generated/rounding_flex_basis_flex_grow_row_width_of_100.rs
@@ -29,7 +29,7 @@ fn rounding_flex_basis_flex_grow_row_width_of_100() {
assert_eq!(taffy.layout(node0).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
- assert_eq!(taffy.layout(node1).unwrap().size.width, 34f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.width, 33f32);
assert_eq!(taffy.layout(node1).unwrap().size.height, 100f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 33f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 0f32);
diff --git a/tests/generated/rounding_flex_basis_overrides_main_size.rs b/tests/generated/rounding_flex_basis_overrides_main_size.rs
index 00f7eae83..5274b9683 100644
--- a/tests/generated/rounding_flex_basis_overrides_main_size.rs
+++ b/tests/generated/rounding_flex_basis_overrides_main_size.rs
@@ -56,7 +56,7 @@ fn rounding_flex_basis_overrides_main_size() {
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node1).unwrap().size.width, 100f32);
- assert_eq!(taffy.layout(node1).unwrap().size.height, 25f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.height, 24f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 64f32);
assert_eq!(taffy.layout(node2).unwrap().size.width, 100f32);
diff --git a/tests/generated/rounding_fractial_input_1.rs b/tests/generated/rounding_fractial_input_1.rs
index 551f51a6d..46600499a 100644
--- a/tests/generated/rounding_fractial_input_1.rs
+++ b/tests/generated/rounding_fractial_input_1.rs
@@ -56,7 +56,7 @@ fn rounding_fractial_input_1() {
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node1).unwrap().size.width, 100f32);
- assert_eq!(taffy.layout(node1).unwrap().size.height, 25f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.height, 24f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 64f32);
assert_eq!(taffy.layout(node2).unwrap().size.width, 100f32);
diff --git a/tests/generated/rounding_fractial_input_2.rs b/tests/generated/rounding_fractial_input_2.rs
index 091b1b0ac..d4186021e 100644
--- a/tests/generated/rounding_fractial_input_2.rs
+++ b/tests/generated/rounding_fractial_input_2.rs
@@ -56,7 +56,7 @@ fn rounding_fractial_input_2() {
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node1).unwrap().size.width, 100f32);
- assert_eq!(taffy.layout(node1).unwrap().size.height, 24f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.height, 25f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 65f32);
assert_eq!(taffy.layout(node2).unwrap().size.width, 100f32);
diff --git a/tests/generated/rounding_fractial_input_3.rs b/tests/generated/rounding_fractial_input_3.rs
index 8e5c4cb99..4855300d8 100644
--- a/tests/generated/rounding_fractial_input_3.rs
+++ b/tests/generated/rounding_fractial_input_3.rs
@@ -56,7 +56,7 @@ fn rounding_fractial_input_3() {
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node1).unwrap().size.width, 100f32);
- assert_eq!(taffy.layout(node1).unwrap().size.height, 25f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.height, 24f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 64f32);
assert_eq!(taffy.layout(node2).unwrap().size.width, 100f32);
diff --git a/tests/generated/rounding_fractial_input_4.rs b/tests/generated/rounding_fractial_input_4.rs
index 49673dfa3..ea6aa826c 100644
--- a/tests/generated/rounding_fractial_input_4.rs
+++ b/tests/generated/rounding_fractial_input_4.rs
@@ -56,7 +56,7 @@ fn rounding_fractial_input_4() {
assert_eq!(taffy.layout(node0).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node0).unwrap().location.y, 0f32);
assert_eq!(taffy.layout(node1).unwrap().size.width, 100f32);
- assert_eq!(taffy.layout(node1).unwrap().size.height, 25f32);
+ assert_eq!(taffy.layout(node1).unwrap().size.height, 24f32);
assert_eq!(taffy.layout(node1).unwrap().location.x, 0f32);
assert_eq!(taffy.layout(node1).unwrap().location.y, 64f32);
assert_eq!(taffy.layout(node2).unwrap().size.width, 100f32);