From 8309cfc9764f7ba7e1fed4cec4596d8c7d740a07 Mon Sep 17 00:00:00 2001 From: Pritesh Nandgaonkar Date: Thu, 16 Aug 2018 06:22:10 -0700 Subject: [PATCH] Fix parent height calculation in case of baseline alignment Summary: Prior to this diff, if parents height was not set then the height of parent was deduced as max of childrens height(considering line ht, padding, margin etc. ), but it didn't consider the baseline scenario where the previous logic will fail as then the parents height will be determined by the space taken by children above and below the reference baseline. I added a test case for the same. Look at the diff D9088051 which shows the screenshot of the bug. It is solved to https://pxl.cl/gvVk Reviewed By: dsyang Differential Revision: D9219678 fbshipit-source-id: f4a0b9f1452c33e78bd8c6cf39f6fcf538a04074 --- tests/YGAlignBaselineTest.cpp | 96 +++++++++++++++++++++++++++++++++++ tests/YGAlignItemsTest.cpp | 10 ++-- yoga/Yoga.cpp | 86 +++++++++++++++++-------------- 3 files changed, 149 insertions(+), 43 deletions(-) create mode 100644 tests/YGAlignBaselineTest.cpp diff --git a/tests/YGAlignBaselineTest.cpp b/tests/YGAlignBaselineTest.cpp new file mode 100644 index 00000000..477ecb48 --- /dev/null +++ b/tests/YGAlignBaselineTest.cpp @@ -0,0 +1,96 @@ +/* + * 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. + * + */ + +#include +#include + +static float +_baselineFunc(YGNodeRef node, const float width, const float height) { + return height / 2; +} + +TEST(YogaTest, align_baseline_with_no_parent_ht) { + YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetAlignItems(root, YGAlignBaseline); + YGNodeStyleSetWidth(root, 150); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child0, 50); + YGNodeStyleSetHeight(root_child0, 50); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child1, 50); + YGNodeStyleSetHeight(root_child1, 40); + YGNodeSetBaselineFunc(root_child1, _baselineFunc); + 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(150, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(70, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(40, YGNodeLayoutGetHeight(root_child1)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} + +TEST(YogaTest, align_baseline_with_no_baseline_func_and_no_parent_ht) { + YGConfigRef config = YGConfigNew(); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + YGNodeStyleSetAlignItems(root, YGAlignBaseline); + YGNodeStyleSetWidth(root, 150); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child0, 50); + YGNodeStyleSetHeight(root_child0, 80); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNewWithConfig(config); + YGNodeStyleSetWidth(root_child1, 50); + 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(150, YGNodeLayoutGetWidth(root)); + ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root)); + + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0)); + ASSERT_FLOAT_EQ(80, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1)); + ASSERT_FLOAT_EQ(30, YGNodeLayoutGetTop(root_child1)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1)); + ASSERT_FLOAT_EQ(50, YGNodeLayoutGetHeight(root_child1)); + + YGNodeFreeRecursive(root); + + YGConfigFree(config); +} diff --git a/tests/YGAlignItemsTest.cpp b/tests/YGAlignItemsTest.cpp index fd5e424f..29f43645 100644 --- a/tests/YGAlignItemsTest.cpp +++ b/tests/YGAlignItemsTest.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/YGAlignItemsTest.html #include diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index 86d66956..e17766bc 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -3152,47 +3152,46 @@ static void YGNodelayoutImpl( } // STEP 8: MULTI-LINE CONTENT ALIGNMENT - if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) && - !YGFloatIsUndefined(availableInnerCrossDim)) { - const float remainingAlignContentDim = - availableInnerCrossDim - totalLineCrossDim; - + // currentLead stores the size of the cross dim + float currentLead = leadingPaddingAndBorderCross; + if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node))) { float crossDimLead = 0; - float currentLead = leadingPaddingAndBorderCross; - - switch (node->getStyle().alignContent) { - case YGAlignFlexEnd: - currentLead += remainingAlignContentDim; - break; - case YGAlignCenter: - currentLead += remainingAlignContentDim / 2; - break; - case YGAlignStretch: - if (availableInnerCrossDim > totalLineCrossDim) { - crossDimLead = remainingAlignContentDim / lineCount; - } - break; - case YGAlignSpaceAround: - if (availableInnerCrossDim > totalLineCrossDim) { - currentLead += remainingAlignContentDim / (2 * lineCount); - if (lineCount > 1) { + if (!YGFloatIsUndefined(availableInnerCrossDim)) { + const float remainingAlignContentDim = + availableInnerCrossDim - totalLineCrossDim; + switch (node->getStyle().alignContent) { + case YGAlignFlexEnd: + currentLead += remainingAlignContentDim; + break; + case YGAlignCenter: + currentLead += remainingAlignContentDim / 2; + break; + case YGAlignStretch: + if (availableInnerCrossDim > totalLineCrossDim) { crossDimLead = remainingAlignContentDim / lineCount; } - } else { - currentLead += remainingAlignContentDim / 2; - } - break; - case YGAlignSpaceBetween: - if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) { - crossDimLead = remainingAlignContentDim / (lineCount - 1); - } - break; - case YGAlignAuto: - case YGAlignFlexStart: - case YGAlignBaseline: - break; + break; + case YGAlignSpaceAround: + if (availableInnerCrossDim > totalLineCrossDim) { + currentLead += remainingAlignContentDim / (2 * lineCount); + if (lineCount > 1) { + crossDimLead = remainingAlignContentDim / lineCount; + } + } else { + currentLead += remainingAlignContentDim / 2; + } + break; + case YGAlignSpaceBetween: + if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) { + crossDimLead = remainingAlignContentDim / (lineCount - 1); + } + break; + case YGAlignAuto: + case YGAlignFlexStart: + case YGAlignBaseline: + break; + } } - uint32_t endIndex = 0; for (uint32_t i = 0; i < lineCount; i++) { const uint32_t startIndex = endIndex; @@ -3394,7 +3393,6 @@ static void YGNodelayoutImpl( measureModeCrossDim == YGMeasureModeAtMost)) { // Clamp the size to the min/max size, if specified, and make sure it // doesn't go below the padding and border amount. - node->setLayoutMeasuredDimension( YGNodeBoundAxis( node, @@ -3420,6 +3418,18 @@ static void YGNodelayoutImpl( dim[crossAxis]); } + if (performLayout && + node->getStyle().dimensions[dim[crossAxis]].unit == YGUnitAuto && + node->getStyle().alignItems == YGAlignBaseline) { + node->setLayoutMeasuredDimension( + YGNodeBoundAxis( + node, + crossAxis, + currentLead + paddingAndBorderAxisRow, + crossAxisownerSize, + ownerWidth), + dim[crossAxis]); + } // As we only wrapped in normal direction yet, we need to reverse the // positions on wrap-reverse. if (performLayout && node->getStyle().flexWrap == YGWrapWrapReverse) {