Change NaN with large number

Reviewed By: emilsjolander

Differential Revision: D6969537

fbshipit-source-id: bdc09eaf703e0d313ca65c25a4fb44c99203d9bf
This commit is contained in:
Pritesh Nandgaonkar 2018-03-01 04:00:35 -08:00 committed by Facebook Github Bot
parent af9d6479e5
commit d174ab8a7a
11 changed files with 262 additions and 127 deletions

View File

@ -9,12 +9,29 @@ package com.facebook.yoga;
public class YogaConstants {
public static final float UNDEFINED = Float.NaN;
/**
* Large positive number signifies that the property(float) is undefined. Earlier we used to have
* YGundefined as NAN, but the downside of this is that we can't use -ffast-math compiler flag as
* it assumes all floating-point calculation involve and result into finite numbers. For more
* information regarding -ffast-math compiler flag in clang, have a look at
* https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math
*/
public static final float UNDEFINED = (float) (10E20);
public static boolean shouldUseFastMath = false;
public static boolean isUndefined(float value) {
return Float.compare(value, UNDEFINED) == 0;
// Value of a float in the case of it being not defined is 10.1E20. Earlier it used to be NAN,
// the benefit of which
// was that if NAN is involved in any mathematical expression the result was NAN. But since we
// want to have `-ffast-math`
// flag being used by compiler which assumes that the floating point values are not NAN and Inf,
// we represent YGUndefined as 10.1E20.
// But now if YGUndefined is involved in any mathematical operations this value(10.1E20) would
// change.
// So the following check makes sure that if the value is outside a range (-10E8, 10E8) then it
// is undefined.
return (Float.compare(value, (float) 10E8) >= 0 || Float.compare(value, (float) -10E8) <= 0);
}
public static boolean isUndefined(YogaValue value) {

View File

@ -342,8 +342,10 @@ struct JYogaValue : public JavaClass<JYogaValue> {
return (javatype)YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \
} \
\
void jni_YGNodeStyleSet##name(alias_ref<jobject>, jlong nativePointer, javatype value) { \
YGNodeStyleSet##name(_jlong2YGNodeRef(nativePointer), static_cast<type>(value)); \
void jni_YGNodeStyleSet##name( \
alias_ref<jobject>, jlong nativePointer, javatype value) { \
YGNodeStyleSet##name( \
_jlong2YGNodeRef(nativePointer), static_cast<type>(value)); \
}
#define YG_NODE_JNI_STYLE_UNIT_PROP(name) \

View File

@ -15,15 +15,37 @@ YGFlexDirection YGFlexDirectionCross(
: YGFlexDirectionColumn;
}
float YGFloatMax(const float a, const float b) {
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return fmaxf(a, b);
}
return YGFloatIsUndefined(a) ? b : a;
}
float YGFloatMin(const float a, const float b) {
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return fminf(a, b);
}
return YGFloatIsUndefined(a) ? b : a;
}
bool YGValueEqual(const YGValue a, const YGValue b) {
if (a.unit != b.unit) {
return false;
}
if (a.unit == YGUnitUndefined ||
(std::isnan(a.value) && std::isnan(b.value))) {
(YGFloatIsUndefined(a.value) && YGFloatIsUndefined(b.value))) {
return true;
}
return fabs(a.value - b.value) < 0.0001f;
}
bool YGFloatsEqual(const float a, const float b) {
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return fabs(a - b) < 0.0001f;
}
return YGFloatIsUndefined(a) && YGFloatIsUndefined(b);
}

View File

@ -54,6 +54,38 @@ struct YGCollectFlexItemsRowValues {
bool YGValueEqual(const YGValue a, const YGValue b);
// This custom float equality function returns true if either absolute
// difference between two floats is less than 0.0001f or both are undefined.
bool YGFloatsEqual(const float a, const float b);
// We need custom max function, since we want that, if one argument is
// YGUndefined then the max funtion should return the other argument as the max
// value. We wouldn't have needed a custom max function if YGUndefined was NAN
// as fmax has the same behaviour, but with NAN we cannot use `-ffast-math`
// compiler flag.
float YGFloatMax(const float a, const float b);
// We need custom min function, since we want that, if one argument is
// YGUndefined then the min funtion should return the other argument as the min
// value. We wouldn't have needed a custom min function if YGUndefined was NAN
// as fmin has the same behaviour, but with NAN we cannot use `-ffast-math`
// compiler flag.
float YGFloatMin(const float a, const float b);
// This custom float comparision function compares the array of float with
// YGFloatsEqual, as the default float comparision operator will not work(Look
// at the comments of YGFloatsEqual function).
template <std::size_t size>
bool YGFloatArrayEqual(
const std::array<float, size>& val1,
const std::array<float, size>& val2) {
bool areEqual = true;
for (std::size_t i = 0; i < size && areEqual; ++i) {
areEqual = YGFloatsEqual(val1[i], val2[i]);
}
return areEqual;
}
YGFlexDirection YGFlexDirectionCross(
const YGFlexDirection flexDirection,
const YGDirection direction);
@ -71,7 +103,7 @@ inline float YGResolveValue(const YGValue value, const float parentSize) {
case YGUnitPoint:
return value.value;
case YGUnitPercent:
return value.value * parentSize / 100.0f;
return value.value * parentSize * 0.01;
}
return YGUndefined;
}

View File

@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "YGLayout.h"
#include "Utils.h"
const std::array<float, 2> kYGDefaultDimensionValues = {
{YGUndefined, YGUndefined}};
@ -31,9 +32,11 @@ YGLayout::YGLayout()
doesLegacyStretchFlagAffectsLayout(false) {}
bool YGLayout::operator==(YGLayout layout) const {
bool isEqual = position == layout.position &&
dimensions == layout.dimensions && margin == layout.margin &&
border == layout.border && padding == layout.padding &&
bool isEqual = YGFloatArrayEqual(position, layout.position) &&
YGFloatArrayEqual(dimensions, layout.dimensions) &&
YGFloatArrayEqual(margin, layout.margin) &&
YGFloatArrayEqual(border, layout.border) &&
YGFloatArrayEqual(padding, layout.padding) &&
direction == layout.direction && hadOverflow == layout.hadOverflow &&
lastParentDirection == layout.lastParentDirection &&
nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&

View File

@ -624,26 +624,28 @@ bool YGNode::isNodeFlexible() {
float YGNode::getLeadingBorder(const YGFlexDirection axis) {
if (YGFlexDirectionIsRow(axis) &&
style_.border[YGEdgeStart].unit != YGUnitUndefined &&
!YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
style_.border[YGEdgeStart].value >= 0.0f) {
return style_.border[YGEdgeStart].value;
}
return fmaxf(
YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value,
0.0f);
float computedEdgeValue =
YGComputedEdgeValue(style_.border, leading[axis], &YGValueZero)->value;
return YGFloatMax(computedEdgeValue, 0.0f);
}
float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) {
if (YGFlexDirectionIsRow(flexDirection) &&
style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
!YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
style_.border[YGEdgeEnd].value >= 0.0f) {
return style_.border[YGEdgeEnd].value;
}
return fmaxf(
float computedEdgeValue =
YGComputedEdgeValue(style_.border, trailing[flexDirection], &YGValueZero)
->value,
0.0f);
->value;
return YGFloatMax(computedEdgeValue, 0.0f);
}
float YGNode::getLeadingPadding(
@ -651,14 +653,16 @@ float YGNode::getLeadingPadding(
const float widthSize) {
if (YGFlexDirectionIsRow(axis) &&
style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
YGResolveValue(style_.padding[YGEdgeStart], widthSize) >= 0.0f) {
!YGFloatIsUndefined(
YGResolveValue(style_.padding[YGEdgeStart], widthSize)) &&
YGResolveValue(style_.padding[YGEdgeStart], widthSize) > 0.0f) {
return YGResolveValue(style_.padding[YGEdgeStart], widthSize);
}
return fmaxf(
YGResolveValue(
float resolvedValue = YGResolveValue(
*YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
widthSize),
0.0f);
widthSize);
return YGFloatMax(resolvedValue, 0.0f);
}
float YGNode::getTrailingPadding(
@ -666,14 +670,17 @@ float YGNode::getTrailingPadding(
const float widthSize) {
if (YGFlexDirectionIsRow(axis) &&
style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
!YGFloatIsUndefined(
YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) &&
YGResolveValue(style_.padding[YGEdgeEnd], widthSize) >= 0.0f) {
return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
}
return fmaxf(
YGResolveValue(
float resolvedValue = YGResolveValue(
*YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
widthSize),
0.0f);
widthSize);
return YGFloatMax(resolvedValue, 0.0f);
}
float YGNode::getLeadingPaddingAndBorder(

View File

@ -70,21 +70,23 @@ bool YGStyle::operator==(const YGStyle& style) {
YGValueArrayEqual(minDimensions, style.minDimensions) &&
YGValueArrayEqual(maxDimensions, style.maxDimensions);
if (!(std::isnan(flex) && std::isnan(style.flex))) {
if (!(YGFloatIsUndefined(flex) && YGFloatIsUndefined(style.flex))) {
areNonFloatValuesEqual = areNonFloatValuesEqual && flex == style.flex;
}
if (!(std::isnan(flexGrow) && std::isnan(style.flexGrow))) {
if (!(YGFloatIsUndefined(flexGrow) && YGFloatIsUndefined(style.flexGrow))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && flexGrow == style.flexGrow;
}
if (!(std::isnan(flexShrink) && std::isnan(style.flexShrink))) {
if (!(YGFloatIsUndefined(flexShrink) &&
YGFloatIsUndefined(style.flexShrink))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && flexShrink == style.flexShrink;
}
if (!(std::isnan(aspectRatio) && std::isnan(style.aspectRatio))) {
if (!(YGFloatIsUndefined(aspectRatio) &&
YGFloatIsUndefined(style.aspectRatio))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && aspectRatio == style.aspectRatio;
}

View File

@ -62,19 +62,20 @@ struct YGCachedMeasurement {
bool isEqual = widthMeasureMode == measurement.widthMeasureMode &&
heightMeasureMode == measurement.heightMeasureMode;
if (!std::isnan(availableWidth) ||
!std::isnan(measurement.availableWidth)) {
if (!YGFloatIsUndefined(availableWidth) ||
!YGFloatIsUndefined(measurement.availableWidth)) {
isEqual = isEqual && availableWidth == measurement.availableWidth;
}
if (!std::isnan(availableHeight) ||
!std::isnan(measurement.availableHeight)) {
if (!YGFloatIsUndefined(availableHeight) ||
!YGFloatIsUndefined(measurement.availableHeight)) {
isEqual = isEqual && availableHeight == measurement.availableHeight;
}
if (!std::isnan(computedWidth) || !std::isnan(measurement.computedWidth)) {
if (!YGFloatIsUndefined(computedWidth) ||
!YGFloatIsUndefined(measurement.computedWidth)) {
isEqual = isEqual && computedWidth == measurement.computedWidth;
}
if (!std::isnan(computedHeight) ||
!std::isnan(measurement.computedHeight)) {
if (!YGFloatIsUndefined(computedHeight) ||
!YGFloatIsUndefined(measurement.computedHeight)) {
isEqual = isEqual && computedHeight == measurement.computedHeight;
}

View File

@ -19,8 +19,11 @@
/* define fmaxf if < VC12 */
#if _MSC_VER < 1800
__forceinline const float fmaxf(const float a, const float b) {
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
return (a > b) ? a : b;
}
return YGFloatIsUndefined(a) ? b : a;
}
#endif
#endif
@ -118,7 +121,15 @@ static int YGDefaultLog(const YGConfigRef config,
#endif
bool YGFloatIsUndefined(const float value) {
return std::isnan(value);
// Value of a float in the case of it being not defined is 10.1E20. Earlier
// it used to be NAN, the benefit of which was that if NAN is involved in any
// mathematical expression the result was NAN. But since we want to have
// `-ffast-math` flag being used by compiler which assumes that the floating
// point values are not NAN and Inf, we represent YGUndefined as 10.1E20. But
// now if YGUndefined is involved in any mathematical operations this
// value(10.1E20) would change. So the following check makes sure that if the
// value is outside a range (-10E8, 10E8) then it is undefined.
return value >= 10E8 || value <= -10E8;
}
const YGValue* YGComputedEdgeValue(
@ -788,13 +799,6 @@ bool YGLayoutNodeInternal(const YGNodeRef node,
const char *reason,
const YGConfigRef config);
bool YGFloatsEqual(const float a, const float b) {
if (YGFloatIsUndefined(a)) {
return YGFloatIsUndefined(b);
}
return fabs(a - b) < 0.0001f;
}
static void YGNodePrintInternal(const YGNodeRef node,
const YGPrintOptions options) {
std::string str;
@ -909,12 +913,15 @@ static inline float YGNodeDimWithMargin(const YGNodeRef node,
static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node,
const YGFlexDirection axis,
const float parentSize) {
bool isUndefined =
YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value);
return !(
node->getResolvedDimension(dim[axis]).unit == YGUnitAuto ||
node->getResolvedDimension(dim[axis]).unit == YGUnitUndefined ||
(node->getResolvedDimension(dim[axis]).unit == YGUnitPoint &&
node->getResolvedDimension(dim[axis]).value < 0.0f) ||
!isUndefined && node->getResolvedDimension(dim[axis]).value < 0.0f) ||
(node->getResolvedDimension(dim[axis]).unit == YGUnitPercent &&
!isUndefined &&
(node->getResolvedDimension(dim[axis]).value < 0.0f ||
YGFloatIsUndefined(parentSize))));
}
@ -964,7 +971,8 @@ static inline float YGNodeBoundAxis(const YGNodeRef node,
const float value,
const float axisSize,
const float widthSize) {
return fmaxf(YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize),
return YGFloatMax(
YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize),
YGNodePaddingAndBorderForAxis(node, axis, widthSize));
}
@ -1035,19 +1043,19 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
child->getLayout().computedFlexBasisGeneration !=
gCurrentGenerationCount)) {
child->setLayoutComputedFlexBasis(fmaxf(
child->setLayoutComputedFlexBasis(YGFloatMax(
resolvedFlexBasis,
YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth)));
}
} else if (isMainAxisRow && isRowStyleDimDefined) {
// The width is definite, so use that as the flex basis.
child->setLayoutComputedFlexBasis(fmaxf(
child->setLayoutComputedFlexBasis(YGFloatMax(
YGResolveValue(
child->getResolvedDimension(YGDimensionWidth), parentWidth),
YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth)));
} else if (!isMainAxisRow && isColumnStyleDimDefined) {
// The height is definite, so use that as the flex basis.
child->setLayoutComputedFlexBasis(fmaxf(
child->setLayoutComputedFlexBasis(YGFloatMax(
YGResolveValue(
child->getResolvedDimension(YGDimensionHeight), parentHeight),
YGNodePaddingAndBorderForAxis(
@ -1162,7 +1170,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
"measure",
config);
child->setLayoutComputedFlexBasis(fmaxf(
child->setLayoutComputedFlexBasis(YGFloatMax(
child->getLayout().measuredDimensions[dim[mainAxis]],
YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth)));
}
@ -1252,7 +1260,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
// If the size of the parent is defined then try to constrain the absolute child to that size
// as well. This allows text within the absolute child to wrap to the size of its parent.
// This is the same behavior as many browsers implement.
if (!isMainAxisRow && YGFloatIsUndefined(childWidth) && widthMode != YGMeasureModeUndefined &&
if (!isMainAxisRow && YGFloatIsUndefined(childWidth) &&
widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) &&
width > 0) {
childWidth = width;
childWidthMeasureMode = YGMeasureModeAtMost;
@ -1368,10 +1377,10 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node,
// We want to make sure we don't call measure with negative size
const float innerWidth = YGFloatIsUndefined(availableWidth)
? availableWidth
: fmaxf(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
: YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
const float innerHeight = YGFloatIsUndefined(availableHeight)
? availableHeight
: fmaxf(
: YGFloatMax(
0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
if (widthMeasureMode == YGMeasureModeExactly &&
@ -1474,9 +1483,12 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node,
const YGMeasureMode heightMeasureMode,
const float parentWidth,
const float parentHeight) {
if ((widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
(heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
(widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) {
if ((!YGFloatIsUndefined(availableWidth) &&
widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
(!YGFloatIsUndefined(availableHeight) &&
heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
(widthMeasureMode == YGMeasureModeExactly &&
heightMeasureMode == YGMeasureModeExactly)) {
const float marginAxisColumn =
node->getMarginForAxis(YGFlexDirectionColumn, parentWidth);
const float marginAxisRow =
@ -1545,13 +1557,16 @@ static float YGNodeCalculateAvailableInnerDim(
// We want to make sure our available height does not violate min and max
// constraints
const float minInnerDim =
YGResolveValue(node->getStyle().minDimensions[dimension], parentDim) -
YGFloatIsUndefined(YGResolveValue(
node->getStyle().minDimensions[dimension], parentDim))
? 0.0f
: YGResolveValue(node->getStyle().minDimensions[dimension], parentDim) -
paddingAndBorder;
const float maxInnerDim =
YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) -
paddingAndBorder;
availableInnerDim =
fmaxf(fminf(availableInnerDim, maxInnerDim), minInnerDim);
YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
}
return availableInnerDim;
@ -1752,14 +1767,17 @@ static float YGDistributeFreeSpaceSecondPass(
mainAxisParentSize);
float updatedMainSize = childFlexBasis;
if (collectedFlexItemsValues.remainingFreeSpace < 0) {
if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
collectedFlexItemsValues.remainingFreeSpace < 0) {
flexShrinkScaledFactor =
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
// Is this child able to shrink?
if (flexShrinkScaledFactor != 0) {
float childSize;
if (collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
if (!YGFloatIsUndefined(
collectedFlexItemsValues.totalFlexShrinkScaledFactors) &&
collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
childSize = childFlexBasis + flexShrinkScaledFactor;
} else {
childSize = childFlexBasis +
@ -1775,11 +1793,13 @@ static float YGDistributeFreeSpaceSecondPass(
availableInnerMainDim,
availableInnerWidth);
}
} else if (collectedFlexItemsValues.remainingFreeSpace > 0) {
} else if (
!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
collectedFlexItemsValues.remainingFreeSpace > 0) {
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
// Is this child able to grow?
if (flexGrowFactor != 0) {
if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
updatedMainSize = YGNodeBoundAxis(
currentRelativeChild,
mainAxis,
@ -1926,7 +1946,8 @@ static void YGDistributeFreeSpaceFirstPass(
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
// Is this child able to shrink?
if (flexShrinkScaledFactor != 0) {
if (!YGFloatIsUndefined(flexShrinkScaledFactor) &&
flexShrinkScaledFactor != 0) {
baseMainSize = childFlexBasis +
collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexShrinkScaledFactors *
@ -1937,7 +1958,9 @@ static void YGDistributeFreeSpaceFirstPass(
baseMainSize,
availableInnerMainDim,
availableInnerWidth);
if (baseMainSize != boundMainSize) {
if (!YGFloatIsUndefined(baseMainSize) &&
!YGFloatIsUndefined(boundMainSize) &&
baseMainSize != boundMainSize) {
// By excluding this item's size and flex factor from remaining,
// this item's
// min/max constraints should also trigger in the second pass
@ -1949,11 +1972,13 @@ static void YGDistributeFreeSpaceFirstPass(
flexShrinkScaledFactor;
}
}
} else if (collectedFlexItemsValues.remainingFreeSpace > 0) {
} else if (
!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
collectedFlexItemsValues.remainingFreeSpace > 0) {
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
// Is this child able to grow?
if (flexGrowFactor != 0) {
if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
baseMainSize = childFlexBasis +
collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
@ -1964,7 +1989,9 @@ static void YGDistributeFreeSpaceFirstPass(
availableInnerMainDim,
availableInnerWidth);
if (baseMainSize != boundMainSize) {
if (!YGFloatIsUndefined(baseMainSize) &&
!YGFloatIsUndefined(boundMainSize) &&
baseMainSize != boundMainSize) {
// By excluding this item's size and flex factor from remaining,
// this item's
// min/max constraints should also trigger in the second pass
@ -2069,9 +2096,9 @@ static void YGJustifyMainAxis(
if (measureModeMainDim == YGMeasureModeAtMost &&
collectedFlexItemsValues.remainingFreeSpace > 0) {
if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
YGResolveValue(
style.minDimensions[dim[mainAxis]], mainAxisParentSize) >= 0) {
collectedFlexItemsValues.remainingFreeSpace = fmaxf(
!YGFloatIsUndefined(YGResolveValue(
style.minDimensions[dim[mainAxis]], mainAxisParentSize))) {
collectedFlexItemsValues.remainingFreeSpace = YGFloatMax(
0,
YGResolveValue(
style.minDimensions[dim[mainAxis]], mainAxisParentSize) -
@ -2115,7 +2142,7 @@ static void YGJustifyMainAxis(
case YGJustifySpaceBetween:
if (collectedFlexItemsValues.itemsOnLine > 1) {
betweenMainDim =
fmaxf(collectedFlexItemsValues.remainingFreeSpace, 0) /
YGFloatMax(collectedFlexItemsValues.remainingFreeSpace, 0) /
(collectedFlexItemsValues.itemsOnLine - 1);
} else {
betweenMainDim = 0;
@ -2207,7 +2234,7 @@ static void YGJustifyMainAxis(
// The cross dimension is the max of the elements dimension since
// there can only be one element in that cross dimension.
collectedFlexItemsValues.crossDim = fmaxf(
collectedFlexItemsValues.crossDim = YGFloatMax(
collectedFlexItemsValues.crossDim,
YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
}
@ -2537,8 +2564,11 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerMainDim = maxInnerMainDim;
} else {
if (!node->getConfig()->useLegacyStretchBehaviour &&
(collectedFlexItemsValues.totalFlexGrowFactors == 0 ||
node->resolveFlexGrow() == 0)) {
((YGFloatIsUndefined(
collectedFlexItemsValues.totalFlexGrowFactors) &&
collectedFlexItemsValues.totalFlexGrowFactors == 0) ||
(YGFloatIsUndefined(node->resolveFlexGrow()) &&
node->resolveFlexGrow() == 0))) {
// If we don't have any children to flex or we can't flex the node
// itself, space we've used is all space we need. Root node also
// should be shrunk to minimum
@ -2743,13 +2773,13 @@ static void YGNodelayoutImpl(const YGNodeRef node,
if (child->marginLeadingValue(crossAxis).unit == YGUnitAuto &&
child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
leadingCrossDim += fmaxf(0.0f, remainingCrossDim / 2);
leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim / 2);
} else if (
child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
// No-Op
} else if (
child->marginLeadingValue(crossAxis).unit == YGUnitAuto) {
leadingCrossDim += fmaxf(0.0f, remainingCrossDim);
leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim);
} else if (alignItem == YGAlignFlexStart) {
// No-Op
} else if (alignItem == YGAlignCenter) {
@ -2768,7 +2798,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
}
totalLineCrossDim += collectedFlexItemsValues.crossDim;
maxLineMainDim = fmaxf(maxLineMainDim, collectedFlexItemsValues.mainDim);
maxLineMainDim =
YGFloatMax(maxLineMainDim, collectedFlexItemsValues.mainDim);
}
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
@ -2831,7 +2862,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
break;
}
if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
lineHeight = fmaxf(
lineHeight = YGFloatMax(
lineHeight,
child->getLayout().measuredDimensions[dim[crossAxis]] +
child->getMarginForAxis(crossAxis, availableInnerWidth));
@ -2845,9 +2876,12 @@ static void YGNodelayoutImpl(const YGNodeRef node,
child->getMarginForAxis(
YGFlexDirectionColumn, availableInnerWidth) -
ascent;
maxAscentForCurrentLine = fmaxf(maxAscentForCurrentLine, ascent);
maxDescentForCurrentLine = fmaxf(maxDescentForCurrentLine, descent);
lineHeight = fmaxf(lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
maxAscentForCurrentLine =
YGFloatMax(maxAscentForCurrentLine, ascent);
maxDescentForCurrentLine =
YGFloatMax(maxDescentForCurrentLine, descent);
lineHeight = YGFloatMax(
lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
}
}
}
@ -2990,8 +3024,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
measureModeMainDim == YGMeasureModeAtMost &&
node->getStyle().overflow == YGOverflowScroll) {
node->setLayoutMeasuredDimension(
fmaxf(
fminf(
YGFloatMax(
YGFloatMin(
availableInnerMainDim + paddingAndBorderAxisMain,
YGNodeBoundAxisWithinMinAndMax(
node, mainAxis, maxLineMainDim, mainAxisParentSize)),
@ -3018,8 +3052,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
measureModeCrossDim == YGMeasureModeAtMost &&
node->getStyle().overflow == YGOverflowScroll) {
node->setLayoutMeasuredDimension(
fmaxf(
fminf(
YGFloatMax(
YGFloatMin(
availableInnerCrossDim + paddingAndBorderAxisCross,
YGNodeBoundAxisWithinMinAndMax(
node,
@ -3134,8 +3168,11 @@ static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(YGMeasureM
YGMeasureMode lastSizeMode,
float lastSize,
float lastComputedSize) {
return lastSizeMode == YGMeasureModeAtMost && sizeMode == YGMeasureModeAtMost &&
lastSize > size && (lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
return lastSizeMode == YGMeasureModeAtMost &&
sizeMode == YGMeasureModeAtMost && !YGFloatIsUndefined(lastSize) &&
!YGFloatIsUndefined(size) && !YGFloatIsUndefined(lastComputedSize) &&
lastSize > size &&
(lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
}
float YGRoundValueToPixelGrid(const float value,
@ -3157,9 +3194,15 @@ float YGRoundValueToPixelGrid(const float value,
} else {
// Finally we just round the value
scaledValue = scaledValue - fractial +
(fractial > 0.5f || YGFloatsEqual(fractial, 0.5f) ? 1.0f : 0.0f);
(!YGFloatIsUndefined(fractial) &&
(fractial > 0.5f || YGFloatsEqual(fractial, 0.5f))
? 1.0f
: 0.0f);
}
return scaledValue / pointScaleFactor;
return (YGFloatIsUndefined(scaledValue) ||
YGFloatIsUndefined(pointScaleFactor))
? YGUndefined
: scaledValue / pointScaleFactor;
}
bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
@ -3175,7 +3218,8 @@ bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode,
const float marginRow,
const float marginColumn,
const YGConfigRef config) {
if (lastComputedHeight < 0 || lastComputedWidth < 0) {
if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) ||
(!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) {
return false;
}
bool useRoundedComparison =
@ -3533,11 +3577,16 @@ static void YGRoundToPixelGrid(const YGNodeRef node,
const uint32_t childCount = YGNodeGetChildCount(node);
for (uint32_t i = 0; i < childCount; i++) {
YGRoundToPixelGrid(YGNodeGetChild(node, i), pointScaleFactor, absoluteNodeLeft, absoluteNodeTop);
YGRoundToPixelGrid(
YGNodeGetChild(node, i),
pointScaleFactor,
absoluteNodeLeft,
absoluteNodeTop);
}
}
void YGNodeCalculateLayout(const YGNodeRef node,
void YGNodeCalculateLayout(
const YGNodeRef node,
const float parentWidth,
const float parentHeight,
const YGDirection parentDirection) {
@ -3556,16 +3605,16 @@ void YGNodeCalculateLayout(const YGNodeRef node,
node->getResolvedDimension(dim[YGFlexDirectionRow]), parentWidth) +
node->getMarginForAxis(YGFlexDirectionRow, parentWidth);
widthMeasureMode = YGMeasureModeExactly;
} else if (
YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], parentWidth) >=
0.0f) {
} else if (!YGFloatIsUndefined(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth],
parentWidth))) {
width = YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], parentWidth);
widthMeasureMode = YGMeasureModeAtMost;
} else {
width = parentWidth;
widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined : YGMeasureModeExactly;
widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined
: YGMeasureModeExactly;
}
float height = YGUndefined;
@ -3576,18 +3625,17 @@ void YGNodeCalculateLayout(const YGNodeRef node,
parentHeight) +
node->getMarginForAxis(YGFlexDirectionColumn, parentWidth);
heightMeasureMode = YGMeasureModeExactly;
} else if (
YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight], parentHeight) >=
0.0f) {
} else if (!YGFloatIsUndefined(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight],
parentHeight))) {
height = YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight], parentHeight);
heightMeasureMode = YGMeasureModeAtMost;
} else {
height = parentHeight;
heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined : YGMeasureModeExactly;
heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined
: YGMeasureModeExactly;
}
if (YGLayoutNodeInternal(
node,
width,

View File

@ -18,13 +18,14 @@
#include <stdbool.h>
#endif
// Not defined in MSVC++
#ifndef NAN
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define NAN (*(const float *) __nan)
#endif
#define YGUndefined NAN
/** Large positive number signifies that the property(float) is undefined.
*Earlier we used to have YGundefined as NAN, but the downside of this is that
*we can't use -ffast-math compiler flag as it assumes all floating-point
*calculation involve and result into finite numbers. For more information
*regarding -ffast-math compiler flag in clang, have a look at
*https://clang.llvm.org/docs/UsersManual.html#cmdoption-ffast-math
**/
#define YGUndefined 10E20F
#include "YGEnums.h"
#include "YGMacros.h"