diff --git a/tests/YGHadOverflowTest.cpp b/tests/YGHadOverflowTest.cpp new file mode 100644 index 00000000..7e45adb5 --- /dev/null +++ b/tests/YGHadOverflowTest.cpp @@ -0,0 +1,103 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include + +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)); +} diff --git a/yoga/Yoga.c b/yoga/Yoga.c index b9469263..aba42c7d 100644 --- a/yoga/Yoga.c +++ b/yoga/Yoga.c @@ -54,6 +54,7 @@ typedef struct YGLayout { uint32_t computedFlexBasisGeneration; float computedFlexBasis; + bool hadOverflow; // Instead of recomputing the entire layout every single time, we // cache some information to break early when nothing changed @@ -192,6 +193,7 @@ static YGNode gYGNodeDefaults = { .lastParentDirection = (YGDirection) -1, .nextCachedMeasurementsIndex = 0, .computedFlexBasis = YGUndefined, + .hadOverflow = false, .measuredDimensions = YG_DEFAULT_DIMENSION_VALUES, .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, Height, dimensions[YGDimensionHeight]); 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, Border, border); @@ -2574,12 +2577,14 @@ static void YGNodelayoutImpl(const YGNodeRef node, performLayout && !requiresStretchLayout, "flex", config); + node->layout.hadOverflow = node->layout.hadOverflow || currentRelativeChild->layout.hadOverflow; currentRelativeChild = currentRelativeChild->nextChild; } } remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace; + node->layout.hadOverflow = node->layout.hadOverflow || (remainingFreeSpace < 0); // STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION diff --git a/yoga/Yoga.h b/yoga/Yoga.h index 3579941c..c3d3260d 100644 --- a/yoga/Yoga.h +++ b/yoga/Yoga.h @@ -215,6 +215,7 @@ YG_NODE_LAYOUT_PROPERTY(float, Bottom); YG_NODE_LAYOUT_PROPERTY(float, Width); YG_NODE_LAYOUT_PROPERTY(float, Height); 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 // point values then the returned value will be the same as YGNodeStyleGetXXX. However if