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

Invalid ui node size when creating tree with 4-level depth #7976

Closed
jkb0o opened this issue Mar 8, 2023 · 14 comments · Fixed by DioxusLabs/taffy#383
Closed

Invalid ui node size when creating tree with 4-level depth #7976

jkb0o opened this issue Mar 8, 2023 · 14 comments · Fixed by DioxusLabs/taffy#383
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets C-Bug An unexpected or incorrect behavior
Milestone

Comments

@jkb0o
Copy link
Contributor

jkb0o commented Mar 8, 2023

Bevy version

0.10, 38a08d9

Relevant system information

rustc 1.67.1
AdapterInfo { name: "Apple M1",  device_type: IntegratedGpu, backend: Metal }

What you did

I create multiple nested ui nodes with depth level at least 4 and provide to them different style params (padding, margin and size):

commands.spawn(NodeBundle {
    background_color: Color::WHITE.into(),
    style: Style {
        // top-level margin affects the invalid behaviour, uncomment to see
        // margin: UiRect::all(Val::Px(20.)),
        size: Size::all(Val::Px(200.)),
        align_content: AlignContent::FlexStart,
        ..default()
    },
    ..default()
}).with_children(|parent| {
    for _ in 0..4 {
        parent.spawn(NodeBundle {
            background_color: Color::RED.into(),
            style: Style {
                min_size: Size::all(Val::Px(40.)),
                margin: UiRect::all(Val::Px(5.0)),
                padding: UiRect::all(Val::Px(5.0)),
                ..default()
            },
            ..default()
        }).with_children(|parent| {
            parent.spawn(NodeBundle {
                background_color: Color::GREEN.into(),
                style: Style {
                    size: Size::all(Val::Percent(100.)),
                    padding: UiRect::all(Val::Px(5.0)),
                    ..default()
                },
                ..default()
            })
            
            //  Uncoment this to see the invalid behaviour:

            // .with_children(|parent| {
            //     parent.spawn(NodeBundle {
            //         ..default()
            //     });
            // })
            ;
        });
    }
});

ui_height_0_10.zip

What went wrong

Adding additional child nodes (uncomment the code) makes the parent nodes too big:

3 levels of nodes (expected):
3-level-depth

4 level of nodes (invalid):
4-level-depth

Additional information

Changing the top-level margin affects the invalid behaviour (nodes goes bit smaller).

@jkb0o jkb0o added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Mar 8, 2023
@mockersf mockersf added this to the 0.10.1 milestone Mar 8, 2023
@mockersf mockersf added A-UI Graphical user interfaces, styles, layouts, and widgets and removed S-Needs-Triage This issue needs to be labelled labels Mar 8, 2023
@nicoburns
Copy link
Contributor

nicoburns commented Mar 8, 2023

Transliterating this into HTML, I actually get something much closer to the "invalid" behaviour in Chrome (with or without the 4th nested node). In chrome the margin makes no difference other than adding some spacing around the edge:

Screenshot 2023-03-08 at 17 25 01

HTML repro:

<div id="test-root" style="display: flex;width: 200px; height: 200px; align-content: start;margin: 20px">
  <div style="display: flex;min-width: 40px;min-height:40px;margin:5px;padding:5px;background-color:red">
    <div style="display: flex;width:100%;height:100%;padding:5px;background-color:green">
      <div></div>
    </div>
  </div>
  <div style="display: flex;min-width: 40px;min-height:40px;margin:5px;padding:5px;background-color:red">
    <div style="display: flex;width:100%;height:100%;padding:5px;background-color:green">
      <div></div>
    </div>
  </div>
  <div style="display: flex;min-width: 40px;min-height:40px;margin:5px;padding:5px;background-color:red">
    <div style="display: flex;width:100%;height:100%;padding:5px;background-color:green">
      <div></div>
    </div>
  </div>
  <div style="display: flex;min-width: 40px;min-height:40px;margin:5px;padding:5px;background-color:red">
    <div style="display: flex;width:100%;height:100%;padding:5px;background-color:green">
      <div></div>
    </div>
  </div>
</div>

@ickshonpe
Copy link
Contributor

ickshonpe commented Mar 8, 2023

I think the second image is correct (or at least closer), and the first one is fixed by #7946.

@jkb0o
Copy link
Contributor Author

jkb0o commented Mar 8, 2023

@nicoburns Well, I ok with both behaviours if it solid, e.g. doesn't depend on the depth of tree.

@jkb0o
Copy link
Contributor Author

jkb0o commented Mar 8, 2023

@ickshonpe the issue created for the latest bevy, the version after the fix you noticed.

@nicoburns
Copy link
Contributor

nicoburns commented Mar 8, 2023

As @jkb0o said, this is running against main, so it can't be #7946. I actually think there are at least two bugs here:

  1. The 3 level behaviour is incorrect: the nodes should be tall like in the 4 level version. This is presumably because Taffy's leaf algorithm (which is used for nodes with no children) is not resolving percentages correctly or something like that.

  2. The nodes in 4 level version seem to be overflowing their container, which they don't in chrome. I'm getting a gentest failure for this so it's definitely not quite right.

@ickshonpe
Copy link
Contributor

ickshonpe commented Mar 8, 2023

Weird, I'm seeing it in main now. In 0.9.1, you consistently get four long rects like the HTML example.

@nicoburns
Copy link
Contributor

nicoburns commented Mar 8, 2023

Chrome dev tools solve the mystery of bug 2:

Screenshot 2023-03-08 at 18 05 02

Taffy wasn't ignoring align_content when flex-wrap was set to nowrap (the default).

(@jkb0o if you want to do alignment for a single-line flex container you want align-items not align-content).

@ickshonpe
Copy link
Contributor

ickshonpe commented Mar 8, 2023

Maybe we should remove AlignContent from Style and change FlexWrap to:

pub enum FlexWrap {
    /// Single line, will overflow if needed.
    NoWrap,
    /// Multiple lines, if needed.
    Wrap(AlignContent),
    /// Same as [`FlexWrap::Wrap`] but new lines will appear before the previous one.
    WrapReverse(AlignContent),
}

or something similar.

@nicoburns
Copy link
Contributor

nicoburns commented Mar 8, 2023

I think that will just be confusing as the API will no longer match CSS. Also, it won't work very well with CSS Grid which also uses AlignContent but not FlexWrap. What I think we ought to do is move towards providing the same kind of lints as Chrome DevTools do above (ideally in some kind of devtools of our own).

nicoburns added a commit to DioxusLabs/taffy that referenced this issue Mar 8, 2023
* Add tests for bevyengine/bevy#7976

* Simplify code in compute_constants

* Ignore align_contents if flex_wrap is set to no_wrap

* Remove commented out code
@ickshonpe
Copy link
Contributor

Yeah, some sort of visual inspection tool would be great.

@nicoburns
Copy link
Contributor

@jkb0o Taffy v0.3.6 has been released which includes a fix for this issue. You should be able to get it by running cargo update :)

@jkb0o
Copy link
Contributor Author

jkb0o commented Mar 8, 2023

Cool, thanks! Got the same behaviour for all variants now!
Screenshot 2023-03-08 at 20 40 49

@jkb0o jkb0o closed this as completed Mar 8, 2023
@ickshonpe
Copy link
Contributor

ickshonpe commented Mar 8, 2023

This still seems wrong:

use taffy::prelude::*;

fn main() {
    
    let p = Style {
        size: Size {
            width: points(20.),
            height: points(20.),
        },
        padding: Rect {
            left: points(5.),
            right: points(5.),
            top: points(5.),
            bottom: points(5.),
        },
        ..Default::default()
    };

    let c = Style {
        min_size: Size {
            width: percent(1.),
            height: auto(),
        },
        padding: Rect {
            left: points(5.),
            right: points(5.),
            top: points(5.),
            bottom: points(5.),
        },
        ..Default::default()
    };
    
    let mut taffy = Taffy::new();
    let child = taffy.new_leaf(c).unwrap();
    let parent = taffy.new_with_children(p, &[child]).unwrap();

    taffy.compute_layout(
            parent, 
            Size { width: AvailableSpace::Definite(100.0),  height: AvailableSpace::Definite(100.0) }
        )
        .ok();

    println!("{:#?}", taffy.layout(parent));
    println!("{:#?}", taffy.layout(child));
}

result:

Ok(
    Layout {
        order: 0,
        size: Size {
            width: 20.0,
            height: 20.0,
        },
        location: Point {
            x: 0.0,
            y: 0.0,
        },
    },
)
Ok(
    Layout {
        order: 0,
        size: Size {
            width: 10.0,
            height: 10.0,
        },
        location: Point {
            x: 5.0,
            y: 5.0,
        },
    },
)

The inner node has a size of 10x10, despite having a min-width of 100% which should resolve to a 20 unit width?

Recreated using CSS in chrome and edge, the inner child has a size of 20x10

<style>
    .g1 {
        display: flex;
        background: red;
        width: 20;
        height: 20;
        padding: 5 5 5 5;
    }
    
    .g2 {
        display: flex;
        background: green;
        min-width: 100%;
        padding: 5 5 5 5;
    }
</style>

<div class="root"> 
    <div class="g1">
        <div class="g2"></div> 
    </div>
</div>

output:

Capture_7976

Capture_7976_2

@nicoburns
Copy link
Contributor

@ickshonpe That HTML is invalid. You need to specify 20px not just 20 and you need to specify 5px not just 5. You can see in the Chrome devtools that the styles are not being applied:

Screenshot 2023-03-08 at 20 13 16

Correcting the HTML to:

<div id="test-root" style="width:20px;height:20px;padding:5px"> 
  <div style="min-width: 100%;padding:5px"></div> 
</div>

I get an inner size of 10px x 10px in Chrome. And turning this HTML into a Taffy gentest, it passes.


I would encourage you to make use of Taffy's gentest infrastructure yourself. If you install chromedriver and create a test file (by duplicating an existing one) in the test_fixtures directory of Taffy's repo, the you can:

  • Open it in Chrome, taking advantage of the base stylesheet that the tests include.
  • Run cargo gentest followed by cargo test to compare Taffy's output to Chrome's (if the output doesn't match then the newly generated test will fail)

More details in https://github.com/DioxusLabs/taffy/blob/main/CONTRIBUTING.md

nicoburns added a commit to DioxusLabs/taffy that referenced this issue Apr 19, 2023
* Fix layout of direct flex children with `display:none` set (#380)

* Add test for toggling display:none

* Add test for toggling display:none on a flexbox child

* Fix layout direct flex children with `display:none` set

* Add test for toggling display:none on flexbox container

* Fix setting display:none on a grid child (#382)

* Prepare for 0.3.5 release (#381)

* Prepare for 0.3.5 release

* Add grid PR to release notes

* Ignore align_content in non-wrapping flexbox containers (#383)

* Add tests for bevyengine/bevy#7976

* Simplify code in compute_constants

* Ignore align_contents if flex_wrap is set to no_wrap

* Remove commented out code

* Prepare for v0.3.6 release (#384)

* Use mutable slice rather mutable vec parameter

* Reduce style accesses (#386)

* Use cached flex_grow and flex_shrink values when resolving flexible lengths

* Cache auto margins on FlexItem struct

* Use constants.is_wrap instead of re-resolving style

* Use cached align_content value rather than re-resolving style

* Cache justify_content style in AlgoConstants

* Add failing tests for borders flooring node size

* Add failing tests for padding flooring node size

* Fix divide by zero in main size determination

* Add seperate leaf and flexbox tests for padding/border flooring node size

* Fix padding/border flooring leaf node size

* Fix flexbox children being floored by padding/border

* Combine padding and border tests + make edge dimensions uneven

* Add padding/border floor absolute child size

* Add padding/border floor node size tests for grid

* Add grid container test for padding/border flooring node size

* Fix padding/border flooring size of absolutely positioned children

* Rename grid padding/border tests so that they are all located together

* Make padding/border floor node size for grid children

* Make padding/border floor node size for grid containers

* Apply aspect ratio to leaf nodes whose size is determined by padding/border sum

* Add test for padding/border not affecting flex basis

* Convert flex basis determination to use break from block

* Add test for flex-basis 0 with flex grow

* Floor flex-basis limits by preferred size style value when determining flex container main size

* Floor outer flex-basis by padding_border sum (floors inner flex-basis at 0)

* Remove commented out code

* Add missing 0

* Test cases for bevyengine/bevy#8017 and Taffy #387

* Prevent percentage sizes from contributing a flex item's min-content size

* Prepare for 0.3.7 release (#389)

* Prepare for 0.3.7 release

* Fix duplicate content in the changelog

* Fix markdown lint

* Upgrade to better Github Actions for faster and better maintained CI (#390)

* Use taiki-e/install-action for installing cargo-deny

* Update CI to use dtolnay/rust-toolchain action

* Enable CI for 0.3.x branch

* Fix documentation CI

* Dummy Cargo.toml change

* Add fully reduced test case for #387 (#391)

* Fix wrapping nodes generating an incorrect min-content size (#395)

* Add tests for bevyengine/bevy#8082

* Debug log parent size

* Pass correct cross-axis parent_size/available_space when computing a flex item's min-content contribution

* Prepare for 0.3.8 release (#396)

* Don't allow cached results to be used for sizings with greater available space (#397)

* Don't allow cached results to be used for sizings with greater available space

* Update caching tests to use tree 100 nodes deep (relax permitted measure count to 7)

* Prepare for 0.3.9 release (#398)

* Prepare for 0.3.9 release

* Add bevyengine/bevy#8124 to release notes

* Allow multiple syn versions

* Tree creation benchmarks (#401)

* Add tree creation benchmarks

* Rename allocation benchmark to tree_creation

* Update rstest requirement from 0.16.0 to 0.17.0 (#402)

Updates the requirements on [rstest](https://github.com/la10736/rstest) to permit the latest version.
- [Release notes](https://github.com/la10736/rstest/releases)
- [Changelog](https://github.com/la10736/rstest/blob/master/CHANGELOG.md)
- [Commits](la10736/rstest@0.16.0...0.17.0)

---
updated-dependencies:
- dependency-name: rstest
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update syn requirement from 1.0.7 to 2.0.4 (#403)

Updates the requirements on [syn](https://github.com/dtolnay/syn) to permit the latest version.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](dtolnay/syn@1.0.7...2.0.4)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix: available space in the presence of a min width (#407)

* Add `with_main` and `with_cross` methods to Size

* Add test for min_width > available_space

* Clamp available cross space by min/max height when computing flex basis

* Clamp available cross space by min/max size when computing hypothetical cross size

* Bump measure func call counts to 8

* Prepare for 0.3.10 release (#411)

* Fix import lints (#416)

(cherry picked from commit 5522573)

* Add caching to CI (#418)

* Optimise flexbox layouts with min/max sizes (#413)

* Remove 2-pass min/max code path + implement main size min/max clamping within determine_container_main_size method

* Fix typo in flex_grow_within_constrained_min_max_column test

* Implement cross-size min/max clamping inline in algorithm

* Remove debug log

* Remove commented code

* Prepare for 0.3.11 release (#419)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andreas Weibye <13300393+Weibye@users.noreply.github.com>
Co-authored-by: TimJentzsch <commits@timjen.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets C-Bug An unexpected or incorrect behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants