From cfeac791300079d09a65c6291816f4f2c194abee Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Fri, 3 Feb 2017 05:37:47 -0800 Subject: [PATCH] Fix percentage calculation when parent size is undefined Summary: If parent size was undefined and node specified percentage size it would pass does an exact measure mode with an undefined value which broke an assertion. Reviewed By: gkassabli Differential Revision: D4494265 fbshipit-source-id: 9efef9e39a1b66af2d0f144575a96c919d60dbf7 --- .../tests/Facebook.Yoga/YGPercentageTest.cs | 36 ++++++++++++++++++ gentest/fixtures/YGPercentageTest.html | 4 ++ .../com/facebook/yoga/YGPercentageTest.java | 35 ++++++++++++++++++ .../tests/Facebook.Yoga/YGPercentageTest.js | 37 +++++++++++++++++++ tests/YGPercentageTest.cpp | 34 +++++++++++++++++ yoga/Yoga.c | 20 ++++++---- 6 files changed, 159 insertions(+), 7 deletions(-) diff --git a/csharp/tests/Facebook.Yoga/YGPercentageTest.cs b/csharp/tests/Facebook.Yoga/YGPercentageTest.cs index 251ce823..bbbff024 100644 --- a/csharp/tests/Facebook.Yoga/YGPercentageTest.cs +++ b/csharp/tests/Facebook.Yoga/YGPercentageTest.cs @@ -955,5 +955,41 @@ namespace Facebook.Yoga YogaNode.SetExperimentalFeatureEnabled(YogaExperimentalFeature.Rounding, false); } + [Test] + public void Test_percentage_width_height_undefined_parent_size() + { + YogaNode root = new YogaNode(); + + YogaNode root_child0 = new YogaNode(); + root_child0.Width = 50.Percent(); + root_child0.Height = 50.Percent(); + root.Insert(0, root_child0); + root.StyleDirection = YogaDirection.LTR; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(0f, root.LayoutWidth); + Assert.AreEqual(0f, 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); + + root.StyleDirection = YogaDirection.RTL; + root.CalculateLayout(); + + Assert.AreEqual(0f, root.LayoutX); + Assert.AreEqual(0f, root.LayoutY); + Assert.AreEqual(0f, root.LayoutWidth); + Assert.AreEqual(0f, 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); + } + } } diff --git a/gentest/fixtures/YGPercentageTest.html b/gentest/fixtures/YGPercentageTest.html index 1aa99012..5d09d77c 100644 --- a/gentest/fixtures/YGPercentageTest.html +++ b/gentest/fixtures/YGPercentageTest.html @@ -79,3 +79,7 @@
+ +
+
+
diff --git a/java/tests/com/facebook/yoga/YGPercentageTest.java b/java/tests/com/facebook/yoga/YGPercentageTest.java index c04a34dc..f87981ca 100644 --- a/java/tests/com/facebook/yoga/YGPercentageTest.java +++ b/java/tests/com/facebook/yoga/YGPercentageTest.java @@ -938,4 +938,39 @@ public class YGPercentageTest { YogaNode.setExperimentalFeatureEnabled(YogaExperimentalFeature.ROUNDING, false); } + @Test + public void test_percentage_width_height_undefined_parent_size() { + final YogaNode root = new YogaNode(); + + final YogaNode root_child0 = new YogaNode(); + root_child0.setWidthPercent(50f); + root_child0.setHeightPercent(50f); + root.addChildAt(root_child0, 0); + root.setDirection(YogaDirection.LTR); + root.calculateLayout(); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(0f, root.getLayoutWidth(), 0.0f); + assertEquals(0f, 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); + + root.setDirection(YogaDirection.RTL); + root.calculateLayout(); + + assertEquals(0f, root.getLayoutX(), 0.0f); + assertEquals(0f, root.getLayoutY(), 0.0f); + assertEquals(0f, root.getLayoutWidth(), 0.0f); + assertEquals(0f, 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); + } + } diff --git a/javascript/tests/Facebook.Yoga/YGPercentageTest.js b/javascript/tests/Facebook.Yoga/YGPercentageTest.js index 615cb905..3b8d5d44 100644 --- a/javascript/tests/Facebook.Yoga/YGPercentageTest.js +++ b/javascript/tests/Facebook.Yoga/YGPercentageTest.js @@ -965,3 +965,40 @@ it("percentage_absolute_position", function () { Yoga.setExperimentalFeatureEnabled(Yoga.FEATURE_ROUNDING, false); }); +it("percentage_width_height_undefined_parent_size", function () { + var root = Yoga.Node.create(); + + var root_child0 = Yoga.Node.create(); + root_child0.setWidth("50%"); + root_child0.setHeight("50%"); + root.insertChild(root_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(0 === root.getComputedWidth(), "0 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(0 === root.getComputedHeight(), "0 === 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() + ")"); + + 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(0 === root.getComputedWidth(), "0 === root.getComputedWidth() (" + root.getComputedWidth() + ")"); + console.assert(0 === root.getComputedHeight(), "0 === 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() + ")"); + + if (typeof root !== "undefined") + root.freeRecursive(); + + (typeof gc !== "undefined") && gc(); + console.assert(0 === Yoga.getInstanceCount(), "0 === Yoga.getInstanceCount() (" + Yoga.getInstanceCount() + ")"); +}); diff --git a/tests/YGPercentageTest.cpp b/tests/YGPercentageTest.cpp index b29e6a63..baa4b677 100644 --- a/tests/YGPercentageTest.cpp +++ b/tests/YGPercentageTest.cpp @@ -917,3 +917,37 @@ TEST(YogaTest, percentage_absolute_position) { YGSetExperimentalFeatureEnabled(YGExperimentalFeatureRounding, false); } + +TEST(YogaTest, percentage_width_height_undefined_parent_size) { + const YGNodeRef root = YGNodeNew(); + + const YGNodeRef root_child0 = YGNodeNew(); + YGNodeStyleSetWidthPercent(root_child0, 50); + YGNodeStyleSetHeightPercent(root_child0, 50); + YGNodeInsertChild(root, root_child0, 0); + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(0, 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)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(0, 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)); + + YGNodeFreeRecursive(root); +} diff --git a/yoga/Yoga.c b/yoga/Yoga.c index 1163e870..c476b47d 100644 --- a/yoga/Yoga.c +++ b/yoga/Yoga.c @@ -256,12 +256,16 @@ static inline const YGValue *YGComputedEdgeValue(const YGValue edges[YGEdgeCount return defaultValue; } -static inline float YGValueResolve(const YGValue *const unit, const float parentSize) { - if (unit->unit == YGUnitPixel) { - return unit->value; - } else { - return unit->value * parentSize / 100.0f; +static inline float YGValueResolve(const YGValue *const value, const float parentSize) { + switch (value->unit) { + case YGUnitUndefined: + return YGUndefined; + case YGUnitPixel: + return value->value; + case YGUnitPercent: + return value->value * parentSize / 100.0f; } + return YGUndefined; } int32_t gNodeInstanceCount = 0; @@ -2253,7 +2257,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, childHeight = YGValueResolve(¤tRelativeChild->style.dimensions[YGDimensionHeight], availableInnerHeight) + marginColumn; - childHeightMeasureMode = YGMeasureModeExactly; + childHeightMeasureMode = + YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly; } } else { childHeight = updatedMainSize + marginColumn; @@ -2277,7 +2282,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, childWidth = YGValueResolve(¤tRelativeChild->style.dimensions[YGDimensionWidth], availableInnerWidth) + marginRow; - childWidthMeasureMode = YGMeasureModeExactly; + childWidthMeasureMode = + YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly; } }