diff --git a/csharp/Facebook.Yoga/YogaExperimentalFeature.cs b/csharp/Facebook.Yoga/YogaExperimentalFeature.cs index 0f8156cb..53a6524b 100644 --- a/csharp/Facebook.Yoga/YogaExperimentalFeature.cs +++ b/csharp/Facebook.Yoga/YogaExperimentalFeature.cs @@ -13,5 +13,6 @@ namespace Facebook.Yoga { Rounding, WebFlexBasis, + MinFlexFix, } } diff --git a/csharp/tests/Facebook.Yoga/YGMinMaxDimensionTest.cs b/csharp/tests/Facebook.Yoga/YGMinMaxDimensionTest.cs index fb98750a..7ebfa382 100644 --- a/csharp/tests/Facebook.Yoga/YGMinMaxDimensionTest.cs +++ b/csharp/tests/Facebook.Yoga/YGMinMaxDimensionTest.cs @@ -348,6 +348,121 @@ namespace Facebook.Yoga Assert.AreEqual(50f, root_child2.LayoutHeight); } + [Test] + public void Test_flex_grow_to_min() + { + YogaNode.SetExperimentalFeatureEnabled(YogaExperimentalFeature.MinFlexFix, true); + + YogaNode root = new YogaNode(); + root.Width = 100; + root.MinHeight = 100; + root.MaxHeight = 500; + + YogaNode root_child0 = new YogaNode(); + root_child0.FlexGrow = 1; + root_child0.FlexShrink = 1; + root.Insert(0, root_child0); + + YogaNode root_child1 = new YogaNode(); + root_child1.Height = 50; + root.Insert(1, root_child1); + root.StyleDirection = YogaDirection.LTR; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(100f, root.LayoutWidth); + Assert.AreEqual(100f, root.LayoutHeight); + + Assert.AreEqual(0f, root_child0.LayoutX); + Assert.AreEqual(0f, root_child0.LayoutY); + Assert.AreEqual(100f, root_child0.LayoutWidth); + Assert.AreEqual(50f, root_child0.LayoutHeight); + + Assert.AreEqual(0f, root_child1.LayoutX); + Assert.AreEqual(50f, root_child1.LayoutY); + Assert.AreEqual(100f, root_child1.LayoutWidth); + Assert.AreEqual(50f, root_child1.LayoutHeight); + + root.StyleDirection = YogaDirection.RTL; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(100f, root.LayoutWidth); + Assert.AreEqual(100f, root.LayoutHeight); + + Assert.AreEqual(0f, root_child0.LayoutX); + Assert.AreEqual(0f, root_child0.LayoutY); + Assert.AreEqual(100f, root_child0.LayoutWidth); + Assert.AreEqual(50f, root_child0.LayoutHeight); + + Assert.AreEqual(0f, root_child1.LayoutX); + Assert.AreEqual(50f, root_child1.LayoutY); + Assert.AreEqual(100f, root_child1.LayoutWidth); + Assert.AreEqual(50f, root_child1.LayoutHeight); + + YogaNode.SetExperimentalFeatureEnabled(YogaExperimentalFeature.MinFlexFix, false); + } + + [Test] + public void Test_flex_grow_in_at_most_container() + { + YogaNode.SetExperimentalFeatureEnabled(YogaExperimentalFeature.MinFlexFix, true); + + YogaNode root = new YogaNode(); + root.FlexDirection = YogaFlexDirection.Row; + root.AlignItems = YogaAlign.FlexStart; + root.Width = 100; + root.Height = 100; + + YogaNode root_child0 = new YogaNode(); + root_child0.FlexDirection = YogaFlexDirection.Row; + root.Insert(0, root_child0); + + YogaNode root_child0_child0 = new YogaNode(); + root_child0_child0.FlexGrow = 1; + root_child0_child0.FlexBasis = 0; + root_child0.Insert(0, root_child0_child0); + root.StyleDirection = YogaDirection.LTR; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(100f, root.LayoutWidth); + Assert.AreEqual(100f, root.LayoutHeight); + + Assert.AreEqual(0f, root_child0.LayoutX); + Assert.AreEqual(0f, root_child0.LayoutY); + Assert.AreEqual(0f, root_child0.LayoutWidth); + Assert.AreEqual(0f, root_child0.LayoutHeight); + + Assert.AreEqual(0f, root_child0_child0.LayoutX); + Assert.AreEqual(0f, root_child0_child0.LayoutY); + Assert.AreEqual(0f, root_child0_child0.LayoutWidth); + Assert.AreEqual(0f, root_child0_child0.LayoutHeight); + + root.StyleDirection = YogaDirection.RTL; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(100f, root.LayoutWidth); + Assert.AreEqual(100f, root.LayoutHeight); + + Assert.AreEqual(100f, root_child0.LayoutX); + Assert.AreEqual(0f, root_child0.LayoutY); + Assert.AreEqual(0f, root_child0.LayoutWidth); + Assert.AreEqual(0f, root_child0.LayoutHeight); + + Assert.AreEqual(0f, root_child0_child0.LayoutX); + Assert.AreEqual(0f, root_child0_child0.LayoutY); + Assert.AreEqual(0f, root_child0_child0.LayoutWidth); + Assert.AreEqual(0f, root_child0_child0.LayoutHeight); + + YogaNode.SetExperimentalFeatureEnabled(YogaExperimentalFeature.MinFlexFix, false); + } + [Test] public void Test_flex_grow_within_max_width() { diff --git a/enums.py b/enums.py index f09de262..da8a5425 100644 --- a/enums.py +++ b/enums.py @@ -95,6 +95,7 @@ ENUMS = { 'Rounding', # Mimic web flex-basis behavior. 'WebFlexBasis', + 'MinFlexFix' ], 'PrintOptions': [ ('Layout', 1), diff --git a/gentest/fixtures/YGMinMaxDimensionTest.html b/gentest/fixtures/YGMinMaxDimensionTest.html index 621c6cc3..f102e207 100644 --- a/gentest/fixtures/YGMinMaxDimensionTest.html +++ b/gentest/fixtures/YGMinMaxDimensionTest.html @@ -30,6 +30,17 @@
+
+
+
+
+ +
+
+
+
+
+
diff --git a/java/com/facebook/yoga/YogaExperimentalFeature.java b/java/com/facebook/yoga/YogaExperimentalFeature.java index 3ac45e79..1ac1f9b3 100644 --- a/java/com/facebook/yoga/YogaExperimentalFeature.java +++ b/java/com/facebook/yoga/YogaExperimentalFeature.java @@ -14,7 +14,8 @@ import com.facebook.proguard.annotations.DoNotStrip; @DoNotStrip public enum YogaExperimentalFeature { ROUNDING(0), - WEB_FLEX_BASIS(1); + WEB_FLEX_BASIS(1), + MIN_FLEX_FIX(2); private int mIntValue; @@ -30,6 +31,7 @@ public enum YogaExperimentalFeature { switch (value) { case 0: return ROUNDING; case 1: return WEB_FLEX_BASIS; + case 2: return MIN_FLEX_FIX; default: throw new IllegalArgumentException("Unknown enum value: " + value); } } diff --git a/java/tests/com/facebook/yoga/YGMinMaxDimensionTest.java b/java/tests/com/facebook/yoga/YGMinMaxDimensionTest.java index a5d4ce35..d1e33a46 100644 --- a/java/tests/com/facebook/yoga/YGMinMaxDimensionTest.java +++ b/java/tests/com/facebook/yoga/YGMinMaxDimensionTest.java @@ -340,6 +340,119 @@ public class YGMinMaxDimensionTest { assertEquals(50f, root_child2.getLayoutHeight(), 0.0f); } + @Test + public void test_flex_grow_to_min() { + YogaNode.setExperimentalFeatureEnabled(YogaExperimentalFeature.MIN_FLEX_FIX, true); + + final YogaNode root = new YogaNode(); + root.setWidth(100f); + root.setMinHeight(100f); + root.setMaxHeight(500f); + + final YogaNode root_child0 = new YogaNode(); + root_child0.setFlexGrow(1f); + root_child0.setFlexShrink(1f); + root.addChildAt(root_child0, 0); + + final YogaNode root_child1 = new YogaNode(); + root_child1.setHeight(50f); + root.addChildAt(root_child1, 1); + root.setDirection(YogaDirection.LTR); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(100f, root.getLayoutWidth(), 0.0f); + assertEquals(100f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(100f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(50f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child1.getLayoutX(), 0.0f); + assertEquals(50f, root_child1.getLayoutY(), 0.0f); + assertEquals(100f, root_child1.getLayoutWidth(), 0.0f); + assertEquals(50f, root_child1.getLayoutHeight(), 0.0f); + + root.setDirection(YogaDirection.RTL); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(100f, root.getLayoutWidth(), 0.0f); + assertEquals(100f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(100f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(50f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child1.getLayoutX(), 0.0f); + assertEquals(50f, root_child1.getLayoutY(), 0.0f); + assertEquals(100f, root_child1.getLayoutWidth(), 0.0f); + assertEquals(50f, root_child1.getLayoutHeight(), 0.0f); + + YogaNode.setExperimentalFeatureEnabled(YogaExperimentalFeature.MIN_FLEX_FIX, false); + } + + @Test + public void test_flex_grow_in_at_most_container() { + YogaNode.setExperimentalFeatureEnabled(YogaExperimentalFeature.MIN_FLEX_FIX, true); + + final YogaNode root = new YogaNode(); + root.setFlexDirection(YogaFlexDirection.ROW); + root.setAlignItems(YogaAlign.FLEX_START); + root.setWidth(100f); + root.setHeight(100f); + + final YogaNode root_child0 = new YogaNode(); + root_child0.setFlexDirection(YogaFlexDirection.ROW); + root.addChildAt(root_child0, 0); + + final YogaNode root_child0_child0 = new YogaNode(); + root_child0_child0.setFlexGrow(1f); + root_child0_child0.setFlexBasis(0f); + root_child0.addChildAt(root_child0_child0, 0); + root.setDirection(YogaDirection.LTR); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(100f, root.getLayoutWidth(), 0.0f); + assertEquals(100f, root.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(0f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutHeight(), 0.0f); + + root.setDirection(YogaDirection.RTL); + root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(100f, root.getLayoutWidth(), 0.0f); + assertEquals(100f, root.getLayoutHeight(), 0.0f); + + assertEquals(100f, root_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0.getLayoutWidth(), 0.0f); + assertEquals(0f, root_child0.getLayoutHeight(), 0.0f); + + assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutWidth(), 0.0f); + assertEquals(0f, root_child0_child0.getLayoutHeight(), 0.0f); + + YogaNode.setExperimentalFeatureEnabled(YogaExperimentalFeature.MIN_FLEX_FIX, false); + } + @Test public void test_flex_grow_within_max_width() { final YogaNode root = new YogaNode(); diff --git a/javascript/sources/YGEnums.js b/javascript/sources/YGEnums.js index 91db6a3b..9d1cb2c2 100644 --- a/javascript/sources/YGEnums.js +++ b/javascript/sources/YGEnums.js @@ -43,9 +43,10 @@ module.exports = { EDGE_VERTICAL: 7, EDGE_ALL: 8, - EXPERIMENTAL_FEATURE_COUNT: 2, + EXPERIMENTAL_FEATURE_COUNT: 3, EXPERIMENTAL_FEATURE_ROUNDING: 0, EXPERIMENTAL_FEATURE_WEB_FLEX_BASIS: 1, + EXPERIMENTAL_FEATURE_MIN_FLEX_FIX: 2, FLEX_DIRECTION_COUNT: 4, FLEX_DIRECTION_COLUMN: 0, diff --git a/javascript/tests/Facebook.Yoga/YGMinMaxDimensionTest.js b/javascript/tests/Facebook.Yoga/YGMinMaxDimensionTest.js index 0d9369e7..be9466ef 100644 --- a/javascript/tests/Facebook.Yoga/YGMinMaxDimensionTest.js +++ b/javascript/tests/Facebook.Yoga/YGMinMaxDimensionTest.js @@ -349,6 +349,123 @@ it("justify_content_overflow_min_max", function () { } } }); +it("flex_grow_to_min", function () { + Yoga.setExperimentalFeatureEnabled(Yoga.EXPERIMENTAL_FEATURE_MIN_FLEX_FIX, true); + + try { + var root = Yoga.Node.create(); + root.setWidth(100); + root.setMinHeight(100); + root.setMaxHeight(500); + + var root_child0 = Yoga.Node.create(); + root_child0.setFlexGrow(1); + root_child0.setFlexShrink(1); + root.insertChild(root_child0, 0); + + var root_child1 = Yoga.Node.create(); + root_child1.setHeight(50); + root.insertChild(root_child1, 1); + root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_LTR); + + console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")"); + console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")"); + console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")"); + + console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")"); + console.assert(100 === root_child0.getComputedWidth(), "100 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")"); + console.assert(50 === root_child0.getComputedHeight(), "50 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")"); + + console.assert(0 === root_child1.getComputedLeft(), "0 === root_child1.getComputedLeft() (" + root_child1.getComputedLeft() + ")"); + console.assert(50 === root_child1.getComputedTop(), "50 === root_child1.getComputedTop() (" + root_child1.getComputedTop() + ")"); + console.assert(100 === root_child1.getComputedWidth(), "100 === root_child1.getComputedWidth() (" + root_child1.getComputedWidth() + ")"); + console.assert(50 === root_child1.getComputedHeight(), "50 === root_child1.getComputedHeight() (" + root_child1.getComputedHeight() + ")"); + + root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_RTL); + + console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")"); + console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")"); + console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")"); + + console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")"); + console.assert(100 === root_child0.getComputedWidth(), "100 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")"); + console.assert(50 === root_child0.getComputedHeight(), "50 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")"); + + console.assert(0 === root_child1.getComputedLeft(), "0 === root_child1.getComputedLeft() (" + root_child1.getComputedLeft() + ")"); + console.assert(50 === root_child1.getComputedTop(), "50 === root_child1.getComputedTop() (" + root_child1.getComputedTop() + ")"); + console.assert(100 === root_child1.getComputedWidth(), "100 === root_child1.getComputedWidth() (" + root_child1.getComputedWidth() + ")"); + console.assert(50 === root_child1.getComputedHeight(), "50 === root_child1.getComputedHeight() (" + root_child1.getComputedHeight() + ")"); + } finally { + if (typeof root !== "undefined") { + root.freeRecursive(); + } + + Yoga.setExperimentalFeatureEnabled(Yoga.EXPERIMENTAL_FEATURE_MIN_FLEX_FIX, false); + } +}); +it("flex_grow_in_at_most_container", function () { + Yoga.setExperimentalFeatureEnabled(Yoga.EXPERIMENTAL_FEATURE_MIN_FLEX_FIX, true); + + try { + var root = Yoga.Node.create(); + root.setFlexDirection(Yoga.FLEX_DIRECTION_ROW); + root.setAlignItems(Yoga.ALIGN_FLEX_START); + root.setWidth(100); + root.setHeight(100); + + var root_child0 = Yoga.Node.create(); + root_child0.setFlexDirection(Yoga.FLEX_DIRECTION_ROW); + root.insertChild(root_child0, 0); + + var root_child0_child0 = Yoga.Node.create(); + root_child0_child0.setFlexGrow(1); + root_child0_child0.setFlexBasis(0); + root_child0.insertChild(root_child0_child0, 0); + root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_LTR); + + console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")"); + console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")"); + console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")"); + + console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")"); + console.assert(0 === root_child0.getComputedWidth(), "0 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")"); + console.assert(0 === root_child0.getComputedHeight(), "0 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")"); + + console.assert(0 === root_child0_child0.getComputedLeft(), "0 === root_child0_child0.getComputedLeft() (" + root_child0_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0_child0.getComputedTop(), "0 === root_child0_child0.getComputedTop() (" + root_child0_child0.getComputedTop() + ")"); + console.assert(0 === root_child0_child0.getComputedWidth(), "0 === root_child0_child0.getComputedWidth() (" + root_child0_child0.getComputedWidth() + ")"); + console.assert(0 === root_child0_child0.getComputedHeight(), "0 === root_child0_child0.getComputedHeight() (" + root_child0_child0.getComputedHeight() + ")"); + + root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_RTL); + + console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")"); + console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")"); + console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")"); + + console.assert(100 === root_child0.getComputedLeft(), "100 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")"); + console.assert(0 === root_child0.getComputedWidth(), "0 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")"); + console.assert(0 === root_child0.getComputedHeight(), "0 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")"); + + console.assert(0 === root_child0_child0.getComputedLeft(), "0 === root_child0_child0.getComputedLeft() (" + root_child0_child0.getComputedLeft() + ")"); + console.assert(0 === root_child0_child0.getComputedTop(), "0 === root_child0_child0.getComputedTop() (" + root_child0_child0.getComputedTop() + ")"); + console.assert(0 === root_child0_child0.getComputedWidth(), "0 === root_child0_child0.getComputedWidth() (" + root_child0_child0.getComputedWidth() + ")"); + console.assert(0 === root_child0_child0.getComputedHeight(), "0 === root_child0_child0.getComputedHeight() (" + root_child0_child0.getComputedHeight() + ")"); + } finally { + if (typeof root !== "undefined") { + root.freeRecursive(); + } + + Yoga.setExperimentalFeatureEnabled(Yoga.EXPERIMENTAL_FEATURE_MIN_FLEX_FIX, false); + } +}); it("flex_grow_within_max_width", function () { try { var root = Yoga.Node.create(); diff --git a/tests/YGMinMaxDimensionTest.cpp b/tests/YGMinMaxDimensionTest.cpp index c9b7ea58..0d246789 100644 --- a/tests/YGMinMaxDimensionTest.cpp +++ b/tests/YGMinMaxDimensionTest.cpp @@ -329,6 +329,117 @@ TEST(YogaTest, justify_content_overflow_min_max) { YGNodeFreeRecursive(root); } +TEST(YogaTest, flex_grow_to_min) { + YGSetExperimentalFeatureEnabled(YGExperimentalFeatureMinFlexFix, true); + + const YGNodeRef root = YGNodeNew(); + YGNodeStyleSetWidth(root, 100); + YGNodeStyleSetMinHeight(root, 100); + YGNodeStyleSetMaxHeight(root, 500); + + const YGNodeRef root_child0 = YGNodeNew(); + YGNodeStyleSetFlexGrow(root_child0, 1); + YGNodeStyleSetFlexShrink(root_child0, 1); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNew(); + YGNodeStyleSetHeight(root_child1, 50); + YGNodeInsertChild(root, root_child1, 1); + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1)); + + YGNodeFreeRecursive(root); + + YGSetExperimentalFeatureEnabled(YGExperimentalFeatureMinFlexFix, false); +} + +TEST(YogaTest, flex_grow_in_at_most_container) { + YGSetExperimentalFeatureEnabled(YGExperimentalFeatureMinFlexFix, true); + + const YGNodeRef root = YGNodeNew(); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetAlignItems(root, YGAlignFlexStart); + YGNodeStyleSetWidth(root, 100); + YGNodeStyleSetHeight(root, 100); + + const YGNodeRef root_child0 = YGNodeNew(); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child0_child0 = YGNodeNew(); + YGNodeStyleSetFlexGrow(root_child0_child0, 1); + YGNodeStyleSetFlexBasis(root_child0_child0, 0); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0_child0)); + + YGNodeFreeRecursive(root); + + YGSetExperimentalFeatureEnabled(YGExperimentalFeatureMinFlexFix, false); +} + TEST(YogaTest, flex_grow_within_max_width) { const YGNodeRef root = YGNodeNew(); YGNodeStyleSetWidth(root, 200); diff --git a/yoga/YGEnums.h b/yoga/YGEnums.h index e466ad7b..6022f558 100644 --- a/yoga/YGEnums.h +++ b/yoga/YGEnums.h @@ -57,10 +57,11 @@ typedef YG_ENUM_BEGIN(YGEdge) { YGEdgeAll, } YG_ENUM_END(YGEdge); -#define YGExperimentalFeatureCount 2 +#define YGExperimentalFeatureCount 3 typedef YG_ENUM_BEGIN(YGExperimentalFeature) { YGExperimentalFeatureRounding, YGExperimentalFeatureWebFlexBasis, + YGExperimentalFeatureMinFlexFix, } YG_ENUM_END(YGExperimentalFeature); #define YGFlexDirectionCount 4 diff --git a/yoga/Yoga.c b/yoga/Yoga.c index 4dfa8682..f4de9b95 100644 --- a/yoga/Yoga.c +++ b/yoga/Yoga.c @@ -1960,11 +1960,13 @@ static void YGNodelayoutImpl(const YGNodeRef node, // above float availableInnerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow; if (!YGFloatIsUndefined(availableInnerWidth)) { + // We want to make sure our available width does not violate min and max constraints availableInnerWidth = fmaxf(fminf(availableInnerWidth, maxInnerWidth), minInnerWidth); } float availableInnerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn; if (!YGFloatIsUndefined(availableInnerHeight)) { + // We want to make sure our available height does not violate min and max constraints availableInnerHeight = fmaxf(fminf(availableInnerHeight, maxInnerHeight), minInnerHeight); } @@ -2149,13 +2151,16 @@ static void YGNodelayoutImpl(const YGNodeRef node, // If the main dimension size isn't known, it is computed based on // the line length, so there's no more space left to distribute. - // We resolve main dimension to fit minimum and maximum values - if (YGFloatIsUndefined(availableInnerMainDim)) { + // If we don't measure with exact main dimension we want to ensure we don't violate min and max + if (measureModeMainDim != YGMeasureModeExactly) { if (!YGFloatIsUndefined(minInnerMainDim) && sizeConsumedOnCurrentLine < minInnerMainDim) { availableInnerMainDim = minInnerMainDim; - } else if (!YGFloatIsUndefined(maxInnerMainDim) && - sizeConsumedOnCurrentLine > maxInnerMainDim) { + } else if (!YGFloatIsUndefined(maxInnerMainDim) && sizeConsumedOnCurrentLine > maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; + } else if (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureMinFlexFix)) { + // TODO: this needs to be moved out of experimental feature, as this is legitimate fix + // If the measurement isn't exact, we want to use as little space as possible + availableInnerMainDim = sizeConsumedOnCurrentLine; } }