Overflow detection in Yoga
Summary: We need to provide Yoga clients with means of detecting overflow in flexbox layout. This information can be used later to identify a non-overflowing layout variant among others. Flexbox layout considered overflown if (this is *not* an exhaustive list): - if any child node overflows - [no-wrap] total flex basis of all child nodes is greater than available space in parent and there are no flexible children - [no-wrap] after flexing there is still not enough space to layout all child nodes Reviewed By: gkassabli Differential Revision: D5336645 fbshipit-source-id: c4f87d1754d7bac848e8d347b31d619393b94d2c
This commit is contained in:
committed by
Facebook Github Bot
parent
11bc97b16c
commit
ce3f99939f
103
tests/YGHadOverflowTest.cpp
Normal file
103
tests/YGHadOverflowTest.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <yoga/Yoga.h>
|
||||||
|
|
||||||
|
using namespace ::testing;
|
||||||
|
|
||||||
|
class YogaTest_HadOverflowTests : public Test {
|
||||||
|
protected:
|
||||||
|
YogaTest_HadOverflowTests() {
|
||||||
|
config = YGConfigNew();
|
||||||
|
root = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(root, 200);
|
||||||
|
YGNodeStyleSetHeight(root, 100);
|
||||||
|
YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
|
||||||
|
YGNodeStyleSetFlexWrap(root, YGWrapNoWrap);
|
||||||
|
}
|
||||||
|
|
||||||
|
~YogaTest_HadOverflowTests() {
|
||||||
|
YGNodeFreeRecursive(root);
|
||||||
|
YGConfigFree(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
YGNodeRef root;
|
||||||
|
YGConfigRef config;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(YogaTest_HadOverflowTests, children_overflow_no_wrap_and_no_flex_children) {
|
||||||
|
const YGNodeRef child0 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child0, 80);
|
||||||
|
YGNodeStyleSetHeight(child0, 40);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeBottom, 15);
|
||||||
|
YGNodeInsertChild(root, child0, 0);
|
||||||
|
const YGNodeRef child1 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child1, 80);
|
||||||
|
YGNodeStyleSetHeight(child1, 40);
|
||||||
|
YGNodeStyleSetMargin(child1, YGEdgeBottom, 5);
|
||||||
|
YGNodeInsertChild(root, child1, 1);
|
||||||
|
|
||||||
|
YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
|
||||||
|
|
||||||
|
ASSERT_TRUE(YGNodeLayoutGetHadOverflow(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(YogaTest_HadOverflowTests, spacing_overflow_no_wrap_and_no_flex_children) {
|
||||||
|
const YGNodeRef child0 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child0, 80);
|
||||||
|
YGNodeStyleSetHeight(child0, 40);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeBottom, 10);
|
||||||
|
YGNodeInsertChild(root, child0, 0);
|
||||||
|
const YGNodeRef child1 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child1, 80);
|
||||||
|
YGNodeStyleSetHeight(child1, 40);
|
||||||
|
YGNodeStyleSetMargin(child1, YGEdgeBottom, 5);
|
||||||
|
YGNodeInsertChild(root, child1, 1);
|
||||||
|
|
||||||
|
YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
|
||||||
|
|
||||||
|
ASSERT_TRUE(YGNodeLayoutGetHadOverflow(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(YogaTest_HadOverflowTests, no_overflow_no_wrap_and_flex_children) {
|
||||||
|
const YGNodeRef child0 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child0, 80);
|
||||||
|
YGNodeStyleSetHeight(child0, 40);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeBottom, 10);
|
||||||
|
YGNodeInsertChild(root, child0, 0);
|
||||||
|
const YGNodeRef child1 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child1, 80);
|
||||||
|
YGNodeStyleSetHeight(child1, 40);
|
||||||
|
YGNodeStyleSetMargin(child1, YGEdgeBottom, 5);
|
||||||
|
YGNodeStyleSetFlexShrink(child1, 1);
|
||||||
|
YGNodeInsertChild(root, child1, 1);
|
||||||
|
|
||||||
|
YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
|
||||||
|
|
||||||
|
ASSERT_FALSE(YGNodeLayoutGetHadOverflow(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(YogaTest_HadOverflowTests, spacing_overflow_in_nested_nodes) {
|
||||||
|
const YGNodeRef child0 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child0, 80);
|
||||||
|
YGNodeStyleSetHeight(child0, 40);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeTop, 10);
|
||||||
|
YGNodeStyleSetMargin(child0, YGEdgeBottom, 10);
|
||||||
|
YGNodeInsertChild(root, child0, 0);
|
||||||
|
const YGNodeRef child1 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child1, 80);
|
||||||
|
YGNodeStyleSetHeight(child1, 40);
|
||||||
|
YGNodeInsertChild(root, child1, 1);
|
||||||
|
const YGNodeRef child1_1 = YGNodeNewWithConfig(config);
|
||||||
|
YGNodeStyleSetWidth(child1_1, 80);
|
||||||
|
YGNodeStyleSetHeight(child1_1, 40);
|
||||||
|
YGNodeStyleSetMargin(child1_1, YGEdgeBottom, 5);
|
||||||
|
YGNodeInsertChild(child1, child1_1, 0);
|
||||||
|
|
||||||
|
YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR);
|
||||||
|
|
||||||
|
ASSERT_TRUE(YGNodeLayoutGetHadOverflow(root));
|
||||||
|
}
|
@@ -54,6 +54,7 @@ typedef struct YGLayout {
|
|||||||
|
|
||||||
uint32_t computedFlexBasisGeneration;
|
uint32_t computedFlexBasisGeneration;
|
||||||
float computedFlexBasis;
|
float computedFlexBasis;
|
||||||
|
bool hadOverflow;
|
||||||
|
|
||||||
// Instead of recomputing the entire layout every single time, we
|
// Instead of recomputing the entire layout every single time, we
|
||||||
// cache some information to break early when nothing changed
|
// cache some information to break early when nothing changed
|
||||||
@@ -192,6 +193,7 @@ static YGNode gYGNodeDefaults = {
|
|||||||
.lastParentDirection = (YGDirection) -1,
|
.lastParentDirection = (YGDirection) -1,
|
||||||
.nextCachedMeasurementsIndex = 0,
|
.nextCachedMeasurementsIndex = 0,
|
||||||
.computedFlexBasis = YGUndefined,
|
.computedFlexBasis = YGUndefined,
|
||||||
|
.hadOverflow = false,
|
||||||
.measuredDimensions = YG_DEFAULT_DIMENSION_VALUES,
|
.measuredDimensions = YG_DEFAULT_DIMENSION_VALUES,
|
||||||
|
|
||||||
.cachedLayout =
|
.cachedLayout =
|
||||||
@@ -782,6 +784,7 @@ YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]);
|
|||||||
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
|
||||||
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
|
||||||
YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
|
YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
|
||||||
|
YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow);
|
||||||
|
|
||||||
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
|
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
|
||||||
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
|
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
|
||||||
@@ -2574,12 +2577,14 @@ static void YGNodelayoutImpl(const YGNodeRef node,
|
|||||||
performLayout && !requiresStretchLayout,
|
performLayout && !requiresStretchLayout,
|
||||||
"flex",
|
"flex",
|
||||||
config);
|
config);
|
||||||
|
node->layout.hadOverflow = node->layout.hadOverflow || currentRelativeChild->layout.hadOverflow;
|
||||||
|
|
||||||
currentRelativeChild = currentRelativeChild->nextChild;
|
currentRelativeChild = currentRelativeChild->nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
||||||
|
node->layout.hadOverflow = node->layout.hadOverflow || (remainingFreeSpace < 0);
|
||||||
|
|
||||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||||
|
|
||||||
|
@@ -215,6 +215,7 @@ YG_NODE_LAYOUT_PROPERTY(float, Bottom);
|
|||||||
YG_NODE_LAYOUT_PROPERTY(float, Width);
|
YG_NODE_LAYOUT_PROPERTY(float, Width);
|
||||||
YG_NODE_LAYOUT_PROPERTY(float, Height);
|
YG_NODE_LAYOUT_PROPERTY(float, Height);
|
||||||
YG_NODE_LAYOUT_PROPERTY(YGDirection, Direction);
|
YG_NODE_LAYOUT_PROPERTY(YGDirection, Direction);
|
||||||
|
YG_NODE_LAYOUT_PROPERTY(bool, HadOverflow);
|
||||||
|
|
||||||
// Get the computed values for these nodes after performing layout. If they were set using
|
// Get the computed values for these nodes after performing layout. If they were set using
|
||||||
// point values then the returned value will be the same as YGNodeStyleGetXXX. However if
|
// point values then the returned value will be the same as YGNodeStyleGetXXX. However if
|
||||||
|
Reference in New Issue
Block a user