From 1080cf22e3f520875108ffedd1295a801ea6dd5c Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Mon, 20 Aug 2018 06:14:50 -0700 Subject: [PATCH] Solve width bug when the size is less than min Summary: This diff updates the logic which reassigns `remainingFreeSpace` when the node's calculated dimension falls below min width of the node. So we will have to update the `remainingFreeSpace` as there is more available space since the calculated nodes width is less than the min width. I have also added comments at relevant places in the code so that it is clearer. This diff solves the issue raised in litho support grp. The details can be found here T32199608. This diff also makes sure that it doesn't break fblite, as the earlier version broke it, details of which can be found here T32881750. Reviewed By: IanChilds Differential Revision: D9359026 fbshipit-source-id: 4168e385e962c168a9de9370220c75f14a6726a7 --- gentest/fixtures/YGJustifyContentTest.html | 15 ++ tests/YGJustifyContentTest.cpp | 171 ++++++++++++++++++++- tests/YGPaddingTest.cpp | 10 +- yoga/Yoga.cpp | 31 ++-- 4 files changed, 205 insertions(+), 22 deletions(-) diff --git a/gentest/fixtures/YGJustifyContentTest.html b/gentest/fixtures/YGJustifyContentTest.html index 0dee8c3a..2f832df7 100644 --- a/gentest/fixtures/YGJustifyContentTest.html +++ b/gentest/fixtures/YGJustifyContentTest.html @@ -86,3 +86,18 @@
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
diff --git a/tests/YGJustifyContentTest.cpp b/tests/YGJustifyContentTest.cpp index e5d42168..9a022889 100644 --- a/tests/YGJustifyContentTest.cpp +++ b/tests/YGJustifyContentTest.cpp @@ -1,11 +1,12 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. +/* + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. */ - -// @Generated by gentest/gentest.rb from gentest/fixtures/YGJustifyContentTest.html +// @Generated by gentest/gentest.rb from +// gentest/fixtures/YGJustifyContentTest.html #include #include @@ -735,6 +736,164 @@ TEST(YogaTest, justify_content_row_min_width_and_margin) { YGConfigFree(config); } +TEST( + YogaTest, + justify_content_min_width_with_padding_child_width_greater_than_parent) { + const YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetAlignContent(root, YGAlignStretch); + YGNodeStyleSetWidth(root, 1000); + YGNodeStyleSetHeight(root, 1584); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeStyleSetAlignContent(root_child0, YGAlignStretch); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0_child0, YGFlexDirectionRow); + YGNodeStyleSetJustifyContent(root_child0_child0, YGJustifyCenter); + YGNodeStyleSetAlignContent(root_child0_child0, YGAlignStretch); + YGNodeStyleSetMinWidth(root_child0_child0, 400); + YGNodeStyleSetPadding(root_child0_child0, YGEdgeHorizontal, 100); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + + const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0_child0_child0, YGFlexDirectionRow); + YGNodeStyleSetAlignContent(root_child0_child0_child0, YGAlignStretch); + YGNodeStyleSetWidth(root_child0_child0_child0, 300); + YGNodeStyleSetHeight(root_child0_child0_child0, 100); + YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(1000, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(1584, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(1000, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(300, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(1000, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(1584, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(1000, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(500, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(300, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} + +TEST( + YogaTest, + justify_content_min_width_with_padding_child_width_lower_than_parent) { + const YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetAlignContent(root, YGAlignStretch); + YGNodeStyleSetWidth(root, 1080); + YGNodeStyleSetHeight(root, 1584); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeStyleSetAlignContent(root_child0, YGAlignStretch); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0_child0, YGFlexDirectionRow); + YGNodeStyleSetJustifyContent(root_child0_child0, YGJustifyCenter); + YGNodeStyleSetAlignContent(root_child0_child0, YGAlignStretch); + YGNodeStyleSetMinWidth(root_child0_child0, 400); + YGNodeStyleSetPadding(root_child0_child0, YGEdgeHorizontal, 100); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + + const YGNodeRef root_child0_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0_child0_child0, YGFlexDirectionRow); + YGNodeStyleSetAlignContent(root_child0_child0_child0, YGAlignStretch); + YGNodeStyleSetWidth(root_child0_child0_child0, 199); + YGNodeStyleSetHeight(root_child0_child0_child0, 100); + YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(1584, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(101, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(199, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0)); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root)); + ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(1584, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(1080, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(680, YGNodeLayoutGetLeft(root_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0)); + ASSERT_FLOAT_EQ(400, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0)); + + ASSERT_FLOAT_EQ(101, YGNodeLayoutGetLeft(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(199, YGNodeLayoutGetWidth(root_child0_child0_child0)); + ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0)); + // + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} + TEST(YogaTest, justify_content_row_max_width_and_margin) { const YGConfigRef config = YGConfigNew(); diff --git a/tests/YGPaddingTest.cpp b/tests/YGPaddingTest.cpp index f0d37527..1873151c 100644 --- a/tests/YGPaddingTest.cpp +++ b/tests/YGPaddingTest.cpp @@ -1,10 +1,10 @@ -/** - * Copyright (c) 2014-present, Facebook, Inc. +/* + * Copyright (c) 2014-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. */ - // @Generated by gentest/gentest.rb from gentest/fixtures/YGPaddingTest.html #include diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index f35b70b5..621564f4 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -2420,20 +2420,32 @@ static void YGJustifyMainAxis( const float& availableInnerWidth, const bool& performLayout) { const YGStyle& style = node->getStyle(); - - // If we are using "at most" rules in the main axis. Calculate the remaining - // space when constraint by the min size defined for the main axis. + const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional( + node->getLeadingPaddingAndBorder(mainAxis, ownerWidth)); + const float trailingPaddingAndBorderMain = YGUnwrapFloatOptional( + node->getTrailingPaddingAndBorder(mainAxis, ownerWidth)); + // If we are using "at most" rules in the main axis, make sure that + // remainingFreeSpace is 0 when min main dimension is not given if (measureModeMainDim == YGMeasureModeAtMost && collectedFlexItemsValues.remainingFreeSpace > 0) { if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined && !YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize) .isUndefined()) { - collectedFlexItemsValues.remainingFreeSpace = YGFloatMax( - 0, + // This condition makes sure that if the size of main dimension(after + // considering child nodes main dim, leading and trailing padding etc) + // falls below min dimension, then the remainingFreeSpace is reassigned + // considering the min dimension + + // `minAvailableMainDim` denotes minimum available space in which child + // can be laid out, it will exclude space consumed by padding and border. + const float minAvailableMainDim = YGUnwrapFloatOptional(YGResolveValue( style.minDimensions[dim[mainAxis]], mainAxisownerSize)) - - (availableInnerMainDim - - collectedFlexItemsValues.remainingFreeSpace)); + leadingPaddingAndBorderMain - trailingPaddingAndBorderMain; + const float occupiedSpaceByChildNodes = + availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace; + collectedFlexItemsValues.remainingFreeSpace = + YGFloatMax(0, minAvailableMainDim - occupiedSpaceByChildNodes); } else { collectedFlexItemsValues.remainingFreeSpace = 0; } @@ -2495,8 +2507,6 @@ static void YGJustifyMainAxis( } } - const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional( - node->getLeadingPaddingAndBorder(mainAxis, ownerWidth)); collectedFlexItemsValues.mainDim = leadingPaddingAndBorderMain + leadingMainDim; collectedFlexItemsValues.crossDim = 0; @@ -2579,8 +2589,7 @@ static void YGJustifyMainAxis( } } } - collectedFlexItemsValues.mainDim += YGUnwrapFloatOptional( - node->getTrailingPaddingAndBorder(mainAxis, ownerWidth)); + collectedFlexItemsValues.mainDim += trailingPaddingAndBorderMain; } //