Fix SingleFlex Child condition

Summary:
Fixes the improper `singleFlexChild` optimization. In the case when all the childs have `flex-grow:0 flex-grow:0` except one child with `flex-grow:1 flex-shrink:1`, then one can simply measure all the non-flexing children and then give the flexing child all the remaining space.

Also added a test case which reproduced the bug

Reviewed By: IanChilds

Differential Revision: D8782684

fbshipit-source-id: ffd4d35b6122f82111b987540efb23bd2a8da5a2
This commit is contained in:
Pritesh Nandgaonkar
2018-07-11 05:55:02 -07:00
committed by Facebook Github Bot
parent 966f5ece4a
commit 6548dddec3
3 changed files with 102 additions and 17 deletions

View File

@@ -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/YGFlexTest.html // @Generated by gentest/gentest.rb from gentest/fixtures/YGFlexTest.html
#include <gtest/gtest.h> #include <gtest/gtest.h>
@@ -64,6 +64,90 @@ TEST(YogaTest, flex_basis_flex_grow_column) {
YGConfigFree(config); YGConfigFree(config);
} }
TEST(YogaTest, flex_shrink_flex_grow_row) {
const YGConfigRef config = YGConfigNew();
const YGNodeRef root = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
YGNodeStyleSetWidth(root, 500);
YGNodeStyleSetHeight(root, 500);
const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexGrow(root_child0, 0);
YGNodeStyleSetFlexShrink(root_child0, 1);
YGNodeStyleSetWidth(root_child0, 500);
YGNodeStyleSetHeight(root_child0, 100);
YGNodeInsertChild(root, root_child0, 0);
const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexGrow(root_child1, 0);
YGNodeStyleSetFlexShrink(root_child1, 1);
YGNodeStyleSetWidth(root_child1, 500);
YGNodeStyleSetHeight(root_child1, 100);
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(500, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(250, YGNodeLayoutGetLeft(root_child1));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
YGNodeFreeRecursive(root);
YGConfigFree(config);
}
TEST(YogaTest, flex_shrink_flex_grow_child_flex_shrink_other_child) {
const YGConfigRef config = YGConfigNew();
const YGNodeRef root = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
YGNodeStyleSetWidth(root, 500);
YGNodeStyleSetHeight(root, 500);
const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexGrow(root_child0, 0);
YGNodeStyleSetFlexShrink(root_child0, 1);
YGNodeStyleSetWidth(root_child0, 500);
YGNodeStyleSetHeight(root_child0, 100);
YGNodeInsertChild(root, root_child0, 0);
const YGNodeRef root_child1 = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexGrow(root_child1, 1);
YGNodeStyleSetFlexShrink(root_child1, 1);
YGNodeStyleSetWidth(root_child1, 500);
YGNodeStyleSetHeight(root_child1, 100);
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(500, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(500, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(250, YGNodeLayoutGetLeft(root_child1));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
ASSERT_FLOAT_EQ(250, YGNodeLayoutGetWidth(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
YGNodeFreeRecursive(root);
YGConfigFree(config);
}
TEST(YogaTest, flex_basis_flex_grow_row) { TEST(YogaTest, flex_basis_flex_grow_row) {
const YGConfigRef config = YGConfigNew(); const YGConfigRef config = YGConfigNew();

View File

@@ -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.
*/ */
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <yoga/YGNode.h> #include <yoga/YGNode.h>
#include <yoga/Yoga.h> #include <yoga/Yoga.h>

View File

@@ -1788,16 +1788,17 @@ static void YGNodeComputeFlexBasisForChildren(
// child to exactly match the remaining space // child to exactly match the remaining space
if (measureModeMainDim == YGMeasureModeExactly) { if (measureModeMainDim == YGMeasureModeExactly) {
for (auto child : children) { for (auto child : children) {
if (singleFlexChild != nullptr) { if (child->isNodeFlexible()) {
if (child->isNodeFlexible()) { if (singleFlexChild != nullptr ||
// There is already a flexible child, abort YGFloatsEqual(child->resolveFlexGrow(), 0.0f) ||
YGFloatsEqual(child->resolveFlexShrink(), 0.0f)) {
// There is already a flexible child, or this flexible child doesn't
// have flexGrow and flexShrink, abort
singleFlexChild = nullptr; singleFlexChild = nullptr;
break; break;
} else {
singleFlexChild = child;
} }
} else if (
child->resolveFlexGrow() > 0.0f &&
child->resolveFlexShrink() > 0.0f) {
singleFlexChild = child;
} }
} }
} }