Unexpected Yoga calculation results when using min/max sizes for top/bottom or left/right nodes #674

Open
opened 2017-11-25 14:43:42 -08:00 by SpinyOwl · 6 comments
SpinyOwl commented 2017-11-25 14:43:42 -08:00 (Migrated from github.com)

Report

Issues and Steps to Reproduce

I've tried to create three rows and three columns on second row.
All rows should be stretched to root node size.
All columns (in second row) should stretch to row size.
Left and right columns should have different min/max width.
Top and bottom row should have different min/max height.

Expected Behavior

There should not be empty space between stretched nodes.

Actual Behavior

There is empty space between stretched nodes.
animation

Link to Code

I am using java bindings and here is code:

    private Vector2f minTop = new Vector2f(200, 20);
    private Vector2f minBottom = new Vector2f(200, 20);
    private Vector2f minLeft = new Vector2f(100, 20);
    private Vector2f minRight = new Vector2f(120, 20);
    private Vector2f minCenter = new Vector2f(50, 50);

    private Vector2f maxTop = new Vector2f(Float.MAX_VALUE, 120);
    private Vector2f maxBottom = new Vector2f(Float.MAX_VALUE, 80);
    private Vector2f maxLeft = new Vector2f(300, Float.MAX_VALUE);
    private Vector2f maxRight = new Vector2f(200, Float.MAX_VALUE);
    private Vector2f maxCenter = new Vector2f(Float.MAX_VALUE, Float.MAX_VALUE);

    private Vector4f midRow = new Vector4f();
    private Vector4f top = new Vector4f();
    private Vector4f bottom = new Vector4f();
    private Vector4f left = new Vector4f();
    private Vector4f center = new Vector4f();
    private Vector4f right = new Vector4f();

    private Vector2f size = new Vector2f();

    protected void update() {
        long rootNode = Yoga.YGNodeNew();

        long mNode = Yoga.YGNodeNew();

        long tNode = Yoga.YGNodeNew();
        long lNode = Yoga.YGNodeNew();
        long cNode = Yoga.YGNodeNew();
        long rNode = Yoga.YGNodeNew();
        long bNode = Yoga.YGNodeNew();

        Yoga.YGNodeInsertChild(rootNode, tNode, 0);
        Yoga.YGNodeInsertChild(rootNode, mNode, 1);
        Yoga.YGNodeInsertChild(rootNode, bNode, 2);

        Yoga.YGNodeInsertChild(mNode, lNode, 0);
        Yoga.YGNodeInsertChild(mNode, cNode, 1);
        Yoga.YGNodeInsertChild(mNode, rNode, 2);

        Yoga.YGNodeStyleSetFlexDirection(rootNode, Yoga.YGFlexDirectionColumn);
        Yoga.YGNodeStyleSetAlignItems(rootNode, Yoga.YGAlignStretch);
        Yoga.YGNodeStyleSetJustifyContent(rootNode, Yoga.YGJustifySpaceBetween);

        Yoga.YGNodeStyleSetFlexDirection(mNode, Yoga.YGFlexDirectionRow);
        Yoga.YGNodeStyleSetAlignItems(mNode, Yoga.YGAlignStretch);
        Yoga.YGNodeStyleSetJustifyContent(mNode, Yoga.YGJustifySpaceBetween);

        float midMaxOfMin = Math.max(Math.max(minLeft.y, minCenter.y), minRight.y);
        Yoga.YGNodeStyleSetMinHeight(mNode, midMaxOfMin);
        Yoga.YGNodeStyleSetMaxHeight(mNode, Float.MAX_VALUE);

        Yoga.YGNodeStyleSetWidth(mNode, size.x);

        Yoga.YGNodeStyleSetFlexGrow(mNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(mNode, 1);

        Yoga.YGNodeStyleSetMaxWidth(tNode, maxTop.x);
        Yoga.YGNodeStyleSetMaxHeight(tNode, maxTop.y);
        Yoga.YGNodeStyleSetMinWidth(tNode, minTop.x);
        Yoga.YGNodeStyleSetMinHeight(tNode, minTop.y);
        Yoga.YGNodeStyleSetFlexGrow(tNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(tNode, 1);
        Yoga.YGNodeStyleSetWidth(tNode, size.x);

        Yoga.YGNodeStyleSetMaxWidth(bNode, maxBottom.x);
        Yoga.YGNodeStyleSetMaxHeight(bNode, maxBottom.y);
        Yoga.YGNodeStyleSetMinWidth(bNode, minBottom.x);
        Yoga.YGNodeStyleSetMinHeight(bNode, minBottom.y);
        Yoga.YGNodeStyleSetFlexGrow(bNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(bNode, 1);
        Yoga.YGNodeStyleSetWidth(bNode, size.x);

        Yoga.YGNodeStyleSetMaxWidth(lNode, maxLeft.x);
        Yoga.YGNodeStyleSetMaxHeight(lNode, maxLeft.y);
        Yoga.YGNodeStyleSetMinWidth(lNode, minLeft.x);
        Yoga.YGNodeStyleSetMinHeight(lNode, minLeft.y);
        Yoga.YGNodeStyleSetFlexGrow(lNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(lNode, 1);
        Yoga.YGNodeStyleSetMinHeight(lNode, midMaxOfMin);

        Yoga.YGNodeStyleSetMaxWidth(cNode, maxCenter.x);
        Yoga.YGNodeStyleSetMaxHeight(cNode, maxCenter.y);
        Yoga.YGNodeStyleSetMinWidth(cNode, minCenter.x);
        Yoga.YGNodeStyleSetMinHeight(cNode, minCenter.y);
        Yoga.YGNodeStyleSetFlexGrow(cNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(cNode, 1);
        Yoga.YGNodeStyleSetMinHeight(cNode, midMaxOfMin);

        Yoga.YGNodeStyleSetMaxWidth(rNode, maxRight.x);
        Yoga.YGNodeStyleSetMaxHeight(rNode, maxRight.y);
        Yoga.YGNodeStyleSetMinWidth(rNode, minRight.x);
        Yoga.YGNodeStyleSetMinHeight(rNode, minRight.y);
        Yoga.YGNodeStyleSetFlexGrow(rNode, 1);
        Yoga.YGNodeStyleSetFlexShrink(rNode, 1);
        Yoga.YGNodeStyleSetMinHeight(rNode, midMaxOfMin);

        Yoga.nYGNodeCalculateLayout(rootNode, size.x, size.y, Yoga.YGDirectionLTR);

        Vector2f d = new Vector2f(Yoga.YGNodeLayoutGetLeft(mNode), Yoga.YGNodeLayoutGetTop(mNode));

        midRow.set(Yoga.YGNodeLayoutGetLeft(mNode), Yoga.YGNodeLayoutGetTop(mNode), Yoga.YGNodeLayoutGetWidth(mNode), Yoga.YGNodeLayoutGetHeight(mNode));
        top.set(Yoga.YGNodeLayoutGetLeft(tNode), Yoga.YGNodeLayoutGetTop(tNode), Yoga.YGNodeLayoutGetWidth(tNode), Yoga.YGNodeLayoutGetHeight(tNode));
        bottom.set(Yoga.YGNodeLayoutGetLeft(bNode), Yoga.YGNodeLayoutGetTop(bNode), Yoga.YGNodeLayoutGetWidth(bNode), Yoga.YGNodeLayoutGetHeight(bNode));
        left.set(Yoga.YGNodeLayoutGetLeft(lNode) + d.x, Yoga.YGNodeLayoutGetTop(lNode) + d.y, Yoga.YGNodeLayoutGetWidth(lNode), Yoga.YGNodeLayoutGetHeight(lNode));
        right.set(Yoga.YGNodeLayoutGetLeft(rNode) + d.x, Yoga.YGNodeLayoutGetTop(rNode) + d.y, Yoga.YGNodeLayoutGetWidth(rNode), Yoga.YGNodeLayoutGetHeight(rNode));
        center.set(Yoga.YGNodeLayoutGetLeft(cNode) + d.x, Yoga.YGNodeLayoutGetTop(cNode) + d.y, Yoga.YGNodeLayoutGetWidth(cNode), Yoga.YGNodeLayoutGetHeight(cNode));

        Yoga.YGNodeFree(rootNode);
        Yoga.YGNodeFree(mNode);
        Yoga.YGNodeFree(tNode);
        Yoga.YGNodeFree(lNode);
        Yoga.YGNodeFree(cNode);
        Yoga.YGNodeFree(rNode);
        Yoga.YGNodeFree(bNode);
}
# Report - [x] I have searched [existing issues](https://github.com/facebook/yoga/issues) and this is not a duplicate # Issues and Steps to Reproduce I've tried to create three rows and three columns on second row. All rows should be stretched to root node size. All columns (in second row) should stretch to row size. Left and right columns should have different min/max width. Top and bottom row should have different min/max height. # Expected Behavior There should not be empty space between stretched nodes. # Actual Behavior There is empty space between stretched nodes. ![animation](https://user-images.githubusercontent.com/6692636/33235505-7e6246d2-d24a-11e7-829f-5a6a404870be.gif) # Link to Code I am using java bindings and here is code: ```java private Vector2f minTop = new Vector2f(200, 20); private Vector2f minBottom = new Vector2f(200, 20); private Vector2f minLeft = new Vector2f(100, 20); private Vector2f minRight = new Vector2f(120, 20); private Vector2f minCenter = new Vector2f(50, 50); private Vector2f maxTop = new Vector2f(Float.MAX_VALUE, 120); private Vector2f maxBottom = new Vector2f(Float.MAX_VALUE, 80); private Vector2f maxLeft = new Vector2f(300, Float.MAX_VALUE); private Vector2f maxRight = new Vector2f(200, Float.MAX_VALUE); private Vector2f maxCenter = new Vector2f(Float.MAX_VALUE, Float.MAX_VALUE); private Vector4f midRow = new Vector4f(); private Vector4f top = new Vector4f(); private Vector4f bottom = new Vector4f(); private Vector4f left = new Vector4f(); private Vector4f center = new Vector4f(); private Vector4f right = new Vector4f(); private Vector2f size = new Vector2f(); protected void update() { long rootNode = Yoga.YGNodeNew(); long mNode = Yoga.YGNodeNew(); long tNode = Yoga.YGNodeNew(); long lNode = Yoga.YGNodeNew(); long cNode = Yoga.YGNodeNew(); long rNode = Yoga.YGNodeNew(); long bNode = Yoga.YGNodeNew(); Yoga.YGNodeInsertChild(rootNode, tNode, 0); Yoga.YGNodeInsertChild(rootNode, mNode, 1); Yoga.YGNodeInsertChild(rootNode, bNode, 2); Yoga.YGNodeInsertChild(mNode, lNode, 0); Yoga.YGNodeInsertChild(mNode, cNode, 1); Yoga.YGNodeInsertChild(mNode, rNode, 2); Yoga.YGNodeStyleSetFlexDirection(rootNode, Yoga.YGFlexDirectionColumn); Yoga.YGNodeStyleSetAlignItems(rootNode, Yoga.YGAlignStretch); Yoga.YGNodeStyleSetJustifyContent(rootNode, Yoga.YGJustifySpaceBetween); Yoga.YGNodeStyleSetFlexDirection(mNode, Yoga.YGFlexDirectionRow); Yoga.YGNodeStyleSetAlignItems(mNode, Yoga.YGAlignStretch); Yoga.YGNodeStyleSetJustifyContent(mNode, Yoga.YGJustifySpaceBetween); float midMaxOfMin = Math.max(Math.max(minLeft.y, minCenter.y), minRight.y); Yoga.YGNodeStyleSetMinHeight(mNode, midMaxOfMin); Yoga.YGNodeStyleSetMaxHeight(mNode, Float.MAX_VALUE); Yoga.YGNodeStyleSetWidth(mNode, size.x); Yoga.YGNodeStyleSetFlexGrow(mNode, 1); Yoga.YGNodeStyleSetFlexShrink(mNode, 1); Yoga.YGNodeStyleSetMaxWidth(tNode, maxTop.x); Yoga.YGNodeStyleSetMaxHeight(tNode, maxTop.y); Yoga.YGNodeStyleSetMinWidth(tNode, minTop.x); Yoga.YGNodeStyleSetMinHeight(tNode, minTop.y); Yoga.YGNodeStyleSetFlexGrow(tNode, 1); Yoga.YGNodeStyleSetFlexShrink(tNode, 1); Yoga.YGNodeStyleSetWidth(tNode, size.x); Yoga.YGNodeStyleSetMaxWidth(bNode, maxBottom.x); Yoga.YGNodeStyleSetMaxHeight(bNode, maxBottom.y); Yoga.YGNodeStyleSetMinWidth(bNode, minBottom.x); Yoga.YGNodeStyleSetMinHeight(bNode, minBottom.y); Yoga.YGNodeStyleSetFlexGrow(bNode, 1); Yoga.YGNodeStyleSetFlexShrink(bNode, 1); Yoga.YGNodeStyleSetWidth(bNode, size.x); Yoga.YGNodeStyleSetMaxWidth(lNode, maxLeft.x); Yoga.YGNodeStyleSetMaxHeight(lNode, maxLeft.y); Yoga.YGNodeStyleSetMinWidth(lNode, minLeft.x); Yoga.YGNodeStyleSetMinHeight(lNode, minLeft.y); Yoga.YGNodeStyleSetFlexGrow(lNode, 1); Yoga.YGNodeStyleSetFlexShrink(lNode, 1); Yoga.YGNodeStyleSetMinHeight(lNode, midMaxOfMin); Yoga.YGNodeStyleSetMaxWidth(cNode, maxCenter.x); Yoga.YGNodeStyleSetMaxHeight(cNode, maxCenter.y); Yoga.YGNodeStyleSetMinWidth(cNode, minCenter.x); Yoga.YGNodeStyleSetMinHeight(cNode, minCenter.y); Yoga.YGNodeStyleSetFlexGrow(cNode, 1); Yoga.YGNodeStyleSetFlexShrink(cNode, 1); Yoga.YGNodeStyleSetMinHeight(cNode, midMaxOfMin); Yoga.YGNodeStyleSetMaxWidth(rNode, maxRight.x); Yoga.YGNodeStyleSetMaxHeight(rNode, maxRight.y); Yoga.YGNodeStyleSetMinWidth(rNode, minRight.x); Yoga.YGNodeStyleSetMinHeight(rNode, minRight.y); Yoga.YGNodeStyleSetFlexGrow(rNode, 1); Yoga.YGNodeStyleSetFlexShrink(rNode, 1); Yoga.YGNodeStyleSetMinHeight(rNode, midMaxOfMin); Yoga.nYGNodeCalculateLayout(rootNode, size.x, size.y, Yoga.YGDirectionLTR); Vector2f d = new Vector2f(Yoga.YGNodeLayoutGetLeft(mNode), Yoga.YGNodeLayoutGetTop(mNode)); midRow.set(Yoga.YGNodeLayoutGetLeft(mNode), Yoga.YGNodeLayoutGetTop(mNode), Yoga.YGNodeLayoutGetWidth(mNode), Yoga.YGNodeLayoutGetHeight(mNode)); top.set(Yoga.YGNodeLayoutGetLeft(tNode), Yoga.YGNodeLayoutGetTop(tNode), Yoga.YGNodeLayoutGetWidth(tNode), Yoga.YGNodeLayoutGetHeight(tNode)); bottom.set(Yoga.YGNodeLayoutGetLeft(bNode), Yoga.YGNodeLayoutGetTop(bNode), Yoga.YGNodeLayoutGetWidth(bNode), Yoga.YGNodeLayoutGetHeight(bNode)); left.set(Yoga.YGNodeLayoutGetLeft(lNode) + d.x, Yoga.YGNodeLayoutGetTop(lNode) + d.y, Yoga.YGNodeLayoutGetWidth(lNode), Yoga.YGNodeLayoutGetHeight(lNode)); right.set(Yoga.YGNodeLayoutGetLeft(rNode) + d.x, Yoga.YGNodeLayoutGetTop(rNode) + d.y, Yoga.YGNodeLayoutGetWidth(rNode), Yoga.YGNodeLayoutGetHeight(rNode)); center.set(Yoga.YGNodeLayoutGetLeft(cNode) + d.x, Yoga.YGNodeLayoutGetTop(cNode) + d.y, Yoga.YGNodeLayoutGetWidth(cNode), Yoga.YGNodeLayoutGetHeight(cNode)); Yoga.YGNodeFree(rootNode); Yoga.YGNodeFree(mNode); Yoga.YGNodeFree(tNode); Yoga.YGNodeFree(lNode); Yoga.YGNodeFree(cNode); Yoga.YGNodeFree(rNode); Yoga.YGNodeFree(bNode); } ```
woehrl01 commented 2017-11-26 08:06:34 -08:00 (Migrated from github.com)

@ShchAlexander I tried to reproduce but it works for me. Is the following html the correct "extract"? Your example is not that easy to follow:

<div id="test" style="height: 380px; width: 860px;">
  <div style="flex-direction: column; align-items: stretch; justify-content: space-between; ">
      <div style="max-width: 99999px; max-height: 120px; min-width: 200px; min-height: 20px; flex-grow: 1; flex-shrink: 1; width: 800px;"></div>
      <div style="flex-direction: row; align-items: stretch; justify-content: space-between; min-height: 120px; width: 800px; flex-grow: 1; flex-shrink: 1;" >
        <div style="max-width: 300px; max-height: 99999px; min-width: 100px; min-height: 120px; flex-grow: 1; flex-shrink: 1;"></div>
        <div style="max-width: 99999px; max-height: 99999px; min-width: 50px; min-height: 120px; flex-grow: 1; flex-shrink: 1;"></div>
        <div style="max-width: 200; max-height: 99999px; min-width: 120px; min-height: 120px; flex-grow: 1; flex-shrink: 1"></div>
      </div>
      <div style="max-width: 99999px; max-height: 90px; min-width: 200px; min-height: 20px; flex-grow: 1; flex-shrink: 1; width: 800px;"></div>
    </div>
</div>
@ShchAlexander I tried to reproduce but it works for me. Is the following html the correct "extract"? Your example is not that easy to follow: ```html <div id="test" style="height: 380px; width: 860px;"> <div style="flex-direction: column; align-items: stretch; justify-content: space-between; "> <div style="max-width: 99999px; max-height: 120px; min-width: 200px; min-height: 20px; flex-grow: 1; flex-shrink: 1; width: 800px;"></div> <div style="flex-direction: row; align-items: stretch; justify-content: space-between; min-height: 120px; width: 800px; flex-grow: 1; flex-shrink: 1;" > <div style="max-width: 300px; max-height: 99999px; min-width: 100px; min-height: 120px; flex-grow: 1; flex-shrink: 1;"></div> <div style="max-width: 99999px; max-height: 99999px; min-width: 50px; min-height: 120px; flex-grow: 1; flex-shrink: 1;"></div> <div style="max-width: 200; max-height: 99999px; min-width: 120px; min-height: 120px; flex-grow: 1; flex-shrink: 1"></div> </div> <div style="max-width: 99999px; max-height: 90px; min-width: 200px; min-height: 20px; flex-grow: 1; flex-shrink: 1; width: 800px;"></div> </div> </div> ```
SpinyOwl commented 2017-11-26 11:37:24 -08:00 (Migrated from github.com)

It's reproducible only in C and Java...

It's reproducible only in C and Java...
woehrl01 commented 2017-11-26 11:39:17 -08:00 (Migrated from github.com)

Of course. I'll use our gentest for a repo so we'll have a test for the future. The input is html. Could you please verify that the html matches your desired layout?

Of course. I'll use our gentest for a repo so we'll have a test for the future. The input is html. Could you please verify that the html matches your desired layout?
woehrl01 commented 2017-11-26 12:02:33 -08:00 (Migrated from github.com)

@ShchAlexander I fiddled a bit around, and got a repo. Thanks for the report. I'll have a look in the next days.

A minimal repo is:

<div id="test" style="height: 440px; width: 860px;flex-direction: column; ">
  <div style="max-height: 120px; min-height: 20px; flex-grow: 1;"></div>
  <div style="min-height: 120px; flex-grow: 1;" ></div>
  <div style="max-height: 90px; min-height: 20px; flex-grow: 1;"></div>
</div>
@ShchAlexander I fiddled a bit around, and got a repo. Thanks for the report. I'll have a look in the next days. A minimal repo is: ```html <div id="test" style="height: 440px; width: 860px;flex-direction: column; "> <div style="max-height: 120px; min-height: 20px; flex-grow: 1;"></div> <div style="min-height: 120px; flex-grow: 1;" ></div> <div style="max-height: 90px; min-height: 20px; flex-grow: 1;"></div> </div> ```
woehrl01 commented 2017-11-27 07:08:22 -08:00 (Migrated from github.com)

I found the issue. It is happening due to the choice of doing only a two way pass, instead of a loop for resolving the min/max constraints. I'm currently busy with other tasks, so I'll provide a more w3c compliant fix in a few weeks. In the mean time, feel free to provide a PR 😉

I found the issue. It is happening due to the choice of doing only [a two way pass, instead of a loop for resolving the min/max constraints](https://github.com/facebook/yoga/blob/afaafb41262f7ef2d9eb1bcefcd0aba987360017/yoga/Yoga.cpp#L2178). I'm currently busy with other tasks, so I'll provide a more w3c compliant fix in a few weeks. In the mean time, feel free to provide a PR 😉
SpinyOwl commented 2018-01-14 15:52:22 -08:00 (Migrated from github.com)

@woehrl01, can u please apply fix if you have more time now?

@woehrl01, can u please apply fix if you have more time now?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DaddyFrosty/yoga#674
No description provided.