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 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 shouldUseFastMath = false;
public static boolean isUndefined(float value) { 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) { public static boolean isUndefined(YogaValue value) {

View File

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

View File

@ -15,15 +15,37 @@ YGFlexDirection YGFlexDirectionCross(
: YGFlexDirectionColumn; : 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) { bool YGValueEqual(const YGValue a, const YGValue b) {
if (a.unit != b.unit) { if (a.unit != b.unit) {
return false; return false;
} }
if (a.unit == YGUnitUndefined || if (a.unit == YGUnitUndefined ||
(std::isnan(a.value) && std::isnan(b.value))) { (YGFloatIsUndefined(a.value) && YGFloatIsUndefined(b.value))) {
return true; return true;
} }
return fabs(a.value - b.value) < 0.0001f; 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); 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( YGFlexDirection YGFlexDirectionCross(
const YGFlexDirection flexDirection, const YGFlexDirection flexDirection,
const YGDirection direction); const YGDirection direction);
@ -71,7 +103,7 @@ inline float YGResolveValue(const YGValue value, const float parentSize) {
case YGUnitPoint: case YGUnitPoint:
return value.value; return value.value;
case YGUnitPercent: case YGUnitPercent:
return value.value * parentSize / 100.0f; return value.value * parentSize * 0.01;
} }
return YGUndefined; return YGUndefined;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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