Skip to content

Commit

Permalink
Fixing potential measure call with negative size value
Browse files Browse the repository at this point in the history
Summary: There is a case when measure() function will be called with negative width/height because of margin/padding. This diff fixes that scenario

Reviewed By: emilsjolander

Differential Revision: D5111534

fbshipit-source-id: 99f09b85f0c6a0e5dec89a26baba8f9d560100da
  • Loading branch information
Georgiy Kassabli authored and facebook-github-bot committed May 23, 2017
1 parent bf4ff07 commit cd1dbc3
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 2 deletions.
51 changes: 51 additions & 0 deletions tests/YGMeasureTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ static YGSize _simulate_wrapping_text(YGNodeRef node,
};
}

static YGSize _measure_assert_negative(YGNodeRef node,
float width,
YGMeasureMode widthMode,
float height,
YGMeasureMode heightMode) {
EXPECT_GE(width, 0);
EXPECT_GE(height, 0);

return YGSize{
.width = 0, .height = 0,
};
}

TEST(YogaTest, dont_measure_single_grow_shrink_child) {
const YGNodeRef root = YGNodeNew();
YGNodeStyleSetWidth(root, 100);
Expand Down Expand Up @@ -563,3 +576,41 @@ TEST(YogaTest, can_nullify_measure_func_on_any_node) {
ASSERT_TRUE(YGNodeGetMeasureFunc(root) == NULL);
YGNodeFreeRecursive(root);
}

TEST(YogaTest, cant_call_negative_measure) {
const YGConfigRef config = YGConfigNew();

const YGNodeRef root = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn);
YGNodeStyleSetWidth(root, 50);
YGNodeStyleSetHeight(root, 10);

const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
YGNodeSetMeasureFunc(root_child0, _measure_assert_negative);
YGNodeStyleSetMargin(root_child0, YGEdgeTop, 20);
YGNodeInsertChild(root, root_child0, 0);

YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);

YGNodeFreeRecursive(root);
YGConfigFree(config);
}

TEST(YogaTest, cant_call_negative_measure_horizontal) {
const YGConfigRef config = YGConfigNew();

const YGNodeRef root = YGNodeNewWithConfig(config);
YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
YGNodeStyleSetWidth(root, 10);
YGNodeStyleSetHeight(root, 20);

const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
YGNodeSetMeasureFunc(root_child0, _measure_assert_negative);
YGNodeStyleSetMargin(root_child0, YGEdgeStart, 20);
YGNodeInsertChild(root, root_child0, 0);

YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);

YGNodeFreeRecursive(root);
YGConfigFree(config);
}
9 changes: 7 additions & 2 deletions yoga/Yoga.c
Original file line number Diff line number Diff line change
Expand Up @@ -1736,8 +1736,13 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node,
const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, availableWidth);
const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, availableWidth);

const float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
const float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
// We want to make sure we don't call measure with negative size
const float innerWidth = YGFloatIsUndefined(availableWidth)
? availableWidth
: fmaxf(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
const float innerHeight = YGFloatIsUndefined(availableHeight)
? availableHeight
: fmaxf(0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);

if (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly) {
// Don't bother sizing the text if both dimensions are already defined.
Expand Down

0 comments on commit cd1dbc3

Please sign in to comment.