diff --git a/csharp/Facebook.Yoga/YogaConstants.cs b/csharp/Facebook.Yoga/YogaConstants.cs index 9e05cca3..a715b43c 100644 --- a/csharp/Facebook.Yoga/YogaConstants.cs +++ b/csharp/Facebook.Yoga/YogaConstants.cs @@ -1,4 +1,4 @@ -/** +/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the @@ -9,11 +9,28 @@ namespace Facebook.Yoga { public static class YogaConstants { - public const 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 const float Undefined = 10E20F; public static bool IsUndefined(float value) { - return float.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 >= 10E8F || value <= -10E8; } public static bool IsUndefined(YogaValue value) diff --git a/java/com/facebook/yoga/YogaConstants.java b/java/com/facebook/yoga/YogaConstants.java index b04a7e53..61e212ef 100644 --- a/java/com/facebook/yoga/YogaConstants.java +++ b/java/com/facebook/yoga/YogaConstants.java @@ -1,17 +1,35 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. */ 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 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) { diff --git a/tests/YGFloatOptionalTest.cpp b/tests/YGFloatOptionalTest.cpp deleted file mode 100644 index cb4a35a7..00000000 --- a/tests/YGFloatOptionalTest.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. - */ -#include -#include -#include -#include - -constexpr auto empty = YGFloatOptional{}; -constexpr auto zero = YGFloatOptional{0.0f}; -constexpr auto one = YGFloatOptional{1.0f}; -constexpr auto positive = YGFloatOptional{1234.5f}; -constexpr auto negative = YGFloatOptional{-9876.5f}; - -TEST(YGFloatOptional, value) { - ASSERT_EQ(zero.unwrap(), 0.0f); - ASSERT_EQ(positive.unwrap(), 1234.5f); - ASSERT_EQ(negative.unwrap(), -9876.5f); - ASSERT_TRUE(YGFloatIsUndefined(empty.unwrap())); - - ASSERT_TRUE(empty.isUndefined()); - ASSERT_FALSE(zero.isUndefined()); - ASSERT_FALSE(negative.isUndefined()); -} - -TEST(YGFloatOptional, equality) { - ASSERT_TRUE(empty == empty); - ASSERT_TRUE(empty == YGUndefined); - ASSERT_FALSE(empty == zero); - ASSERT_FALSE(empty == negative); - ASSERT_FALSE(empty == 12.3f); - - ASSERT_TRUE(zero == zero); - ASSERT_TRUE(zero == 0.0f); - ASSERT_FALSE(zero == positive); - ASSERT_FALSE(zero == -5555.5f); - - ASSERT_TRUE(one == one); - ASSERT_TRUE(one == 1.0f); - ASSERT_FALSE(one == positive); - - ASSERT_TRUE(negative == negative); - ASSERT_TRUE(negative == negative.unwrap()); - ASSERT_FALSE(negative == zero); -} - -TEST(YGFloatOptional, inequality) { - ASSERT_FALSE(empty != empty); - ASSERT_FALSE(empty != YGUndefined); - ASSERT_TRUE(empty != zero); - ASSERT_TRUE(empty != negative); - ASSERT_TRUE(empty != 12.3f); - - ASSERT_FALSE(zero != zero); - ASSERT_FALSE(zero != 0.0f); - ASSERT_TRUE(zero != positive); - ASSERT_TRUE(zero != -5555.5f); - - ASSERT_FALSE(one != one); - ASSERT_FALSE(one != 1.0f); - ASSERT_TRUE(one != positive); - - ASSERT_FALSE(negative != negative); - ASSERT_FALSE(negative != negative.unwrap()); - ASSERT_TRUE(negative != zero); -} - -TEST(YGFloatOptional, greater) { - ASSERT_FALSE(empty > empty); - ASSERT_FALSE(empty > zero); - ASSERT_FALSE(empty > one); - ASSERT_FALSE(empty > positive); - ASSERT_FALSE(empty > negative); - ASSERT_FALSE(zero > empty); - ASSERT_FALSE(one > empty); - ASSERT_FALSE(positive > empty); - ASSERT_FALSE(negative > empty); - - ASSERT_TRUE(zero > negative); - ASSERT_FALSE(zero > zero); - ASSERT_FALSE(zero > positive); - ASSERT_FALSE(zero > one); - - ASSERT_TRUE(one > negative); - ASSERT_TRUE(one > zero); - ASSERT_FALSE(one > empty); - ASSERT_FALSE(one > positive); - - ASSERT_TRUE(negative > YGFloatOptional{-INFINITY}); - ASSERT_FALSE(negative > empty); -} - -TEST(YGFloatOptional, lower) { - ASSERT_FALSE(empty < empty); - ASSERT_FALSE(empty < zero); - ASSERT_FALSE(empty < one); - ASSERT_FALSE(empty < positive); - ASSERT_FALSE(empty < negative); - ASSERT_FALSE(zero < empty); - ASSERT_FALSE(one < empty); - ASSERT_FALSE(positive < empty); - ASSERT_FALSE(negative < empty); - - ASSERT_TRUE(negative < zero); - ASSERT_FALSE(zero < zero); - ASSERT_FALSE(positive < zero); - ASSERT_FALSE(one < zero); - - ASSERT_TRUE(negative < one); - ASSERT_TRUE(zero < one); - ASSERT_FALSE(empty < one); - ASSERT_FALSE(positive < one); - - ASSERT_TRUE(YGFloatOptional{-INFINITY} < negative); - ASSERT_FALSE(empty < negative); -} - -TEST(YGFloatOptional, greater_equals) { - ASSERT_TRUE(empty >= empty); - ASSERT_FALSE(empty >= zero); - ASSERT_FALSE(empty >= one); - ASSERT_FALSE(empty >= positive); - ASSERT_FALSE(empty >= negative); - - ASSERT_TRUE(zero >= negative); - ASSERT_TRUE(zero >= zero); - ASSERT_FALSE(zero >= positive); - ASSERT_FALSE(zero >= one); - - ASSERT_TRUE(one >= negative); - ASSERT_TRUE(one >= zero); - ASSERT_FALSE(one >= empty); - ASSERT_FALSE(one >= positive); - - ASSERT_TRUE(negative >= YGFloatOptional{-INFINITY}); - ASSERT_TRUE(negative >= negative); - ASSERT_FALSE(negative >= empty); -} - -TEST(YGFloatOptional, lower_equals) { - ASSERT_TRUE(empty <= empty); - ASSERT_FALSE(zero <= empty); - ASSERT_FALSE(one <= empty); - ASSERT_FALSE(positive <= empty); - ASSERT_FALSE(negative <= empty); - - ASSERT_TRUE(negative <= zero); - ASSERT_TRUE(zero <= zero); - ASSERT_FALSE(positive <= zero); - ASSERT_FALSE(one <= zero); - - ASSERT_TRUE(negative <= one); - ASSERT_TRUE(zero <= one); - ASSERT_FALSE(empty <= one); - ASSERT_FALSE(positive <= one); - - ASSERT_TRUE(YGFloatOptional{-INFINITY} <= negative); - ASSERT_TRUE(negative <= negative); - ASSERT_FALSE(empty <= negative); -} - -TEST(YGFloatOptional, addition) { - ASSERT_EQ(zero + one, one); - ASSERT_EQ( - negative + positive, - YGFloatOptional{negative.unwrap() + positive.unwrap()}); - ASSERT_EQ(empty + zero, empty); - ASSERT_EQ(empty + empty, empty); - ASSERT_EQ(negative + empty, empty); -} - -TEST(YGFloatOptional, subtraction) { - ASSERT_EQ(zero - one, YGFloatOptional{-1.0f}); - ASSERT_EQ( - negative - positive, - YGFloatOptional{negative.unwrap() - positive.unwrap()}); - ASSERT_EQ(empty - zero, empty); - ASSERT_EQ(empty - empty, empty); - ASSERT_EQ(negative - empty, empty); -} - -TEST(YGFloatOptional, unary_minus) { - ASSERT_EQ(-zero, zero); - ASSERT_EQ(-negative, YGFloatOptional{-negative.unwrap()}); - ASSERT_EQ(-positive, YGFloatOptional{-positive.unwrap()}); - ASSERT_EQ(-empty, empty); -} - -TEST(YGFloatOptional, orElse) { - ASSERT_EQ(empty.orElse(1.23f), 1.23f); - ASSERT_TRUE(YGFloatIsUndefined(empty.orElse(YGUndefined))); - ASSERT_EQ(one.orElse(1.23f), 1.0f); -} - -TEST(YGFloatOptional, orElseGet) { - auto x = empty.orElseGet([] { return 1.23f; }); - ASSERT_EQ(x, 1.23f); - ASSERT_TRUE(YGFloatIsUndefined(empty.orElseGet([] { return YGUndefined; }))); - - auto y = one.orElseGet([] { return 1.23f; }); - ASSERT_EQ(y, 1.0f); -} diff --git a/tools/build_defs/oss/yoga_defs.bzl b/tools/build_defs/oss/yoga_defs.bzl index 5a5872fe..7eca7b9b 100644 --- a/tools/build_defs/oss/yoga_defs.bzl +++ b/tools/build_defs/oss/yoga_defs.bzl @@ -58,6 +58,7 @@ BASE_COMPILER_FLAGS = [ "-Wall", "-Werror", "-O3", + "-ffast-math", ] LIBRARY_COMPILER_FLAGS = BASE_COMPILER_FLAGS + [ diff --git a/yoga/Utils.cpp b/yoga/Utils.cpp index b246f943..74cc38c9 100644 --- a/yoga/Utils.cpp +++ b/yoga/Utils.cpp @@ -55,14 +55,15 @@ float YGFloatSanitize(const float val) { return yoga::isUndefined(val) ? 0 : val; } +float YGUnwrapFloatOptional(const YGFloatOptional& op) { + return op.isUndefined() ? YGUndefined : op.getValue(); +} + YGFloatOptional YGFloatOptionalMax( - const YGFloatOptional op1, - const YGFloatOptional op2) { - if (op1 > op2) { - return op1; - } - if (op2 > op1) { - return op2; + const YGFloatOptional& op1, + const YGFloatOptional& op2) { + if (!op1.isUndefined() && !op2.isUndefined()) { + return op1.getValue() > op2.getValue() ? op1 : op2; } return op1.isUndefined() ? op2 : op1; } diff --git a/yoga/Utils.h b/yoga/Utils.h index a0d49235..d578511c 100644 --- a/yoga/Utils.h +++ b/yoga/Utils.h @@ -57,12 +57,22 @@ bool YGValueEqual(const YGValue a, const YGValue b); // 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); YGFloatOptional YGFloatOptionalMax( - const YGFloatOptional op1, - const YGFloatOptional op2); + const YGFloatOptional& op1, + const YGFloatOptional& op2); +// 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 @@ -82,6 +92,11 @@ bool YGFloatArrayEqual( // This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise float YGFloatSanitize(const float val); +// This function unwraps optional and returns YGUndefined if not defined or +// op.value otherwise +// TODO: Get rid off this function +float YGUnwrapFloatOptional(const YGFloatOptional& op); + YGFlexDirection YGFlexDirectionCross( const YGFlexDirection flexDirection, const YGDirection direction); @@ -91,17 +106,18 @@ inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) { flexDirection == YGFlexDirectionRowReverse; } -inline YGFloatOptional YGResolveValue( - const YGValue value, - const float ownerSize) { +inline YGFloatOptional YGResolveValue(const YGValue value, const float ownerSize) { switch (value.unit) { + case YGUnitUndefined: + case YGUnitAuto: + return YGFloatOptional(); case YGUnitPoint: - return YGFloatOptional{value.value}; + return YGFloatOptional(value.value); case YGUnitPercent: - return YGFloatOptional{value.value * ownerSize * 0.01f}; - default: - return YGFloatOptional{}; + return YGFloatOptional( + static_cast(value.value * ownerSize * 0.01)); } + return YGFloatOptional(); } inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) { @@ -123,7 +139,7 @@ inline YGFlexDirection YGResolveFlexDirection( return flexDirection; } -inline YGFloatOptional YGResolveValueMargin( +static inline YGFloatOptional YGResolveValueMargin( const YGValue value, const float ownerSize) { return value.unit == YGUnitAuto ? YGFloatOptional(0) diff --git a/yoga/YGFloatOptional.cpp b/yoga/YGFloatOptional.cpp new file mode 100644 index 00000000..d023dccb --- /dev/null +++ b/yoga/YGFloatOptional.cpp @@ -0,0 +1,83 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + */ +#include "YGFloatOptional.h" +#include +#include +#include "Yoga.h" +#include "Yoga-internal.h" + +using namespace facebook; + +YGFloatOptional::YGFloatOptional(float value) { + if (yoga::isUndefined(value)) { + isUndefined_ = true; + value_ = 0; + } else { + value_ = value; + isUndefined_ = false; + } +} + +float YGFloatOptional::getValue() const { + if (isUndefined_) { + // Abort, accessing a value of an undefined float optional + std::cerr << "Tried to get value of an undefined YGFloatOptional\n"; + std::exit(EXIT_FAILURE); + } + return value_; +} + +bool YGFloatOptional::operator==(const YGFloatOptional& op) const { + if (isUndefined_ == op.isUndefined()) { + return isUndefined_ || value_ == op.getValue(); + } + return false; +} + +bool YGFloatOptional::operator!=(const YGFloatOptional& op) const { + return !(*this == op); +} + +bool YGFloatOptional::operator==(float val) const { + if (yoga::isUndefined(val) == isUndefined_) { + return isUndefined_ || val == value_; + } + return false; +} + +bool YGFloatOptional::operator!=(float val) const { + return !(*this == val); +} + +YGFloatOptional YGFloatOptional::operator+(const YGFloatOptional& op) { + if (!isUndefined_ && !op.isUndefined_) { + return YGFloatOptional(value_ + op.value_); + } + return YGFloatOptional(); +} + +bool YGFloatOptional::operator>(const YGFloatOptional& op) const { + if (isUndefined_ || op.isUndefined_) { + return false; + } + return value_ > op.value_; +} + +bool YGFloatOptional::operator<(const YGFloatOptional& op) const { + if (isUndefined_ || op.isUndefined_) { + return false; + } + return value_ < op.value_; +} + +bool YGFloatOptional::operator>=(const YGFloatOptional& op) const { + return *this == op || *this > op; +} + +bool YGFloatOptional::operator<=(const YGFloatOptional& op) const { + return *this == op || *this < op; +} diff --git a/yoga/YGFloatOptional.h b/yoga/YGFloatOptional.h index 3dd3d5c9..07fbb64b 100644 --- a/yoga/YGFloatOptional.h +++ b/yoga/YGFloatOptional.h @@ -6,68 +6,38 @@ */ #pragma once -#include -#include "Yoga-internal.h" - struct YGFloatOptional { private: - float value_ = std::numeric_limits::quiet_NaN(); + float value_ = 0; + bool isUndefined_ = true; public: - explicit constexpr YGFloatOptional(float value) : value_(value) {} - constexpr YGFloatOptional() = default; + explicit YGFloatOptional(float value); + YGFloatOptional() = default; - // returns the wrapped value, or a value x with YGIsUndefined(x) == true - constexpr float unwrap() const { - return value_; + // Program will terminate if the value of an undefined is accessed. Please + // make sure to check if the optional is defined before calling this function. + // To check if float optional is defined, use `isUndefined()`. + float getValue() const; + + // Sets the value of float optional, and thus isUndefined is assigned false. + void setValue(float val) { + value_ = val; + isUndefined_ = false; } - constexpr bool isUndefined() const { - // std::isnan is not constexpr - return !(value_ == value_); + bool isUndefined() const { + return isUndefined_; } - constexpr float orElse(float other) const { - return isUndefined() ? other : value_; - } + YGFloatOptional operator+(const YGFloatOptional& op); + bool operator>(const YGFloatOptional& op) const; + bool operator<(const YGFloatOptional& op) const; + bool operator>=(const YGFloatOptional& op) const; + bool operator<=(const YGFloatOptional& op) const; + bool operator==(const YGFloatOptional& op) const; + bool operator!=(const YGFloatOptional& op) const; - template - constexpr float orElseGet(Factory&& f) const { - return isUndefined() ? f() : value_; - } - - YGFloatOptional operator-() const { - return YGFloatOptional{-value_}; - } - YGFloatOptional operator+(YGFloatOptional op) const { - return YGFloatOptional{value_ + op.value_}; - } - YGFloatOptional operator-(YGFloatOptional op) const { - return YGFloatOptional{value_ - op.value_}; - } - bool operator>(YGFloatOptional op) const { - return value_ > op.value_; - } - bool operator<(YGFloatOptional op) const { - return value_ < op.value_; - } - bool operator>=(YGFloatOptional op) const { - return *this > op || *this == op; - } - bool operator<=(YGFloatOptional op) const { - return *this < op || *this == op; - } - bool operator==(YGFloatOptional op) const { - return value_ == op.value_ || (isUndefined() && op.isUndefined()); - } - bool operator!=(YGFloatOptional op) const { - return !(*this == op); - } - - bool operator==(float val) const { - return value_ == val || (isUndefined() && yoga::isUndefined(val)); - } - bool operator!=(float val) const { - return !(*this == val); - } + bool operator==(float val) const; + bool operator!=(float val) const; }; diff --git a/yoga/YGNode.cpp b/yoga/YGNode.cpp index 9ae03b01..1694692c 100644 --- a/yoga/YGNode.cpp +++ b/yoga/YGNode.cpp @@ -175,7 +175,7 @@ void YGNode::setLayoutLastOwnerDirection(YGDirection direction) { } void YGNode::setLayoutComputedFlexBasis( - const YGFloatOptional computedFlexBasis) { + const YGFloatOptional& computedFlexBasis) { layout_.computedFlexBasis = computedFlexBasis; } @@ -209,7 +209,11 @@ YGFloatOptional YGNode::relativePosition( return getLeadingPosition(axis, axisSize); } - return -getTrailingPosition(axis, axisSize); + YGFloatOptional trailingPosition = getTrailingPosition(axis, axisSize); + if (!trailingPosition.isUndefined()) { + trailingPosition.setValue(-1 * trailingPosition.getValue()); + } + return trailingPosition; } void YGNode::setPosition( @@ -232,18 +236,20 @@ void YGNode::setPosition( relativePosition(crossAxis, crossSize); setLayoutPosition( - (getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), + YGUnwrapFloatOptional( + getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain), leading[mainAxis]); setLayoutPosition( - (getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), + YGUnwrapFloatOptional( + getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain), trailing[mainAxis]); setLayoutPosition( - (getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross) - .unwrap(), + YGUnwrapFloatOptional( + getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross), leading[crossAxis]); setLayoutPosition( - (getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross) - .unwrap(), + YGUnwrapFloatOptional( + getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross), trailing[crossAxis]); } @@ -298,7 +304,7 @@ YGValue YGNode::resolveFlexBasisPtr() const { if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) { return flexBasis; } - if (style_.flex > YGFloatOptional{0.0f}) { + if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) { return config_->useWebDefaults ? YGValueAuto : YGValueZero; } return YGValueAuto; @@ -388,23 +394,27 @@ float YGNode::resolveFlexGrow() { if (owner_ == nullptr) { return 0.0; } - - return style_.flexGrow.orElseGet( - [this] { return style_.flex.orElse(kDefaultFlexGrow); }); + if (!style_.flexGrow.isUndefined()) { + return style_.flexGrow.getValue(); + } + if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) { + return style_.flex.getValue(); + } + return kDefaultFlexGrow; } float YGNode::resolveFlexShrink() { if (owner_ == nullptr) { return 0.0; } - return style_.flexShrink.orElseGet([this] { - if (style_.flex < YGFloatOptional{0.0f} && !config_->useWebDefaults) { - return -style_.flex.unwrap(); - } else { - return config_->useWebDefaults ? kWebDefaultFlexShrink - : kDefaultFlexShrink; - } - }); + if (!style_.flexShrink.isUndefined()) { + return style_.flexShrink.getValue(); + } + if (!config_->useWebDefaults && !style_.flex.isUndefined() && + style_.flex.getValue() < 0.0f) { + return -style_.flex.getValue(); + } + return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink; } bool YGNode::isNodeFlexible() { @@ -443,9 +453,11 @@ float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const { YGFloatOptional YGNode::getLeadingPadding( const YGFlexDirection axis, const float widthSize) const { - const YGFloatOptional paddingEdgeStart = + const YGFloatOptional& paddingEdgeStart = YGResolveValue(style_.padding[YGEdgeStart], widthSize); - if (YGFlexDirectionIsRow(axis) && paddingEdgeStart >= YGFloatOptional{0.0f}) { + if (YGFlexDirectionIsRow(axis) && + style_.padding[YGEdgeStart].unit != YGUnitUndefined && + !paddingEdgeStart.isUndefined() && paddingEdgeStart.getValue() >= 0.0f) { return paddingEdgeStart; } @@ -458,10 +470,11 @@ YGFloatOptional YGNode::getLeadingPadding( YGFloatOptional YGNode::getTrailingPadding( const YGFlexDirection axis, const float widthSize) const { - const YGFloatOptional paddingEdgeEnd = - YGResolveValue(style_.padding[YGEdgeEnd], widthSize); - if (YGFlexDirectionIsRow(axis) && paddingEdgeEnd >= YGFloatOptional{0.0f}) { - return paddingEdgeEnd; + if (YGFlexDirectionIsRow(axis) && + style_.padding[YGEdgeEnd].unit != YGUnitUndefined && + !YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() && + YGResolveValue(style_.padding[YGEdgeEnd], widthSize).getValue() >= 0.0f) { + return YGResolveValue(style_.padding[YGEdgeEnd], widthSize); } YGFloatOptional resolvedValue = YGResolveValue( diff --git a/yoga/YGNode.h b/yoga/YGNode.h index 57312812..719eb2ea 100644 --- a/yoga/YGNode.h +++ b/yoga/YGNode.h @@ -235,7 +235,7 @@ struct YGNode { void setDirty(bool isDirty); void setLayoutLastOwnerDirection(YGDirection direction); - void setLayoutComputedFlexBasis(const YGFloatOptional computedFlexBasis); + void setLayoutComputedFlexBasis(const YGFloatOptional& computedFlexBasis); void setLayoutComputedFlexBasisGeneration( uint32_t computedFlexBasisGeneration); void setLayoutMeasuredDimension(float measuredDimension, int index); diff --git a/yoga/YGNodePrint.cpp b/yoga/YGNodePrint.cpp index 753a00b6..541a6fef 100644 --- a/yoga/YGNodePrint.cpp +++ b/yoga/YGNodePrint.cpp @@ -14,9 +14,9 @@ namespace facebook { namespace yoga { typedef std::string string; -static void indent(string& base, uint32_t level) { +static void indent(string* base, uint32_t level) { for (uint32_t i = 0; i < level; ++i) { - base.append(" "); + base->append(" "); } } @@ -25,7 +25,7 @@ static bool areFourValuesEqual(const std::array& four) { YGValueEqual(four[0], four[3]); } -static void appendFormatedString(string& str, const char* fmt, ...) { +static void appendFormatedString(string* str, const char* fmt, ...) { va_list args; va_start(args, fmt); va_list argsCopy; @@ -35,25 +35,25 @@ static void appendFormatedString(string& str, const char* fmt, ...) { vsnprintf(buf.data(), buf.size(), fmt, argsCopy); va_end(argsCopy); string result = string(buf.begin(), buf.end() - 1); - str.append(result); + str->append(result); } static void appendFloatOptionalIfDefined( - string& base, + string* base, const string key, const YGFloatOptional num) { if (!num.isUndefined()) { - appendFormatedString(base, "%s: %g; ", key.c_str(), num.unwrap()); + appendFormatedString(base, "%s: %g; ", key.c_str(), num.getValue()); } } static void appendNumberIfNotUndefined( - string& base, + string* base, const string key, const YGValue number) { if (number.unit != YGUnitUndefined) { if (number.unit == YGUnitAuto) { - base.append(key + ": auto; "); + base->append(key + ": auto; "); } else { string unit = number.unit == YGUnitPoint ? "px" : "%%"; appendFormatedString( @@ -63,23 +63,24 @@ static void appendNumberIfNotUndefined( } static void -appendNumberIfNotAuto(string& base, const string& key, const YGValue number) { +appendNumberIfNotAuto(string* base, const string& key, const YGValue number) { if (number.unit != YGUnitAuto) { appendNumberIfNotUndefined(base, key, number); } } static void -appendNumberIfNotZero(string& base, const string& str, const YGValue number) { +appendNumberIfNotZero(string* base, const string& str, const YGValue number) { + if (number.unit == YGUnitAuto) { - base.append(str + ": auto; "); + base->append(str + ": auto; "); } else if (!YGFloatsEqual(number.value, 0)) { appendNumberIfNotUndefined(base, str, number); } } static void appendEdges( - string& base, + string* base, const string& key, const std::array& edges) { if (areFourValuesEqual(edges)) { @@ -93,7 +94,7 @@ static void appendEdges( } static void appendEdgeIfNotUndefined( - string& base, + string* base, const string& str, const std::array& edges, const YGEdge edge) { @@ -102,7 +103,7 @@ static void appendEdgeIfNotUndefined( } void YGNodeToString( - std::string& str, + std::string* str, YGNodeRef node, YGPrintOptions options, uint32_t level) { diff --git a/yoga/YGNodePrint.h b/yoga/YGNodePrint.h index 9615bf8e..9d36ba8d 100644 --- a/yoga/YGNodePrint.h +++ b/yoga/YGNodePrint.h @@ -13,7 +13,7 @@ namespace facebook { namespace yoga { void YGNodeToString( - std::string& str, + std::string* str, YGNodeRef node, YGPrintOptions options, uint32_t level); diff --git a/yoga/YGStyle.cpp b/yoga/YGStyle.cpp index a2f4a17e..bc90463e 100644 --- a/yoga/YGStyle.cpp +++ b/yoga/YGStyle.cpp @@ -8,8 +8,8 @@ // Yoga specific properties, not compatible with flexbox specification bool YGStyle::operator==(const YGStyle& style) { - return ( - direction == style.direction && flexDirection == style.flexDirection && + bool areNonFloatValuesEqual = direction == style.direction && + flexDirection == style.flexDirection && justifyContent == style.justifyContent && alignContent == style.alignContent && alignItems == style.alignItems && alignSelf == style.alignSelf && positionType == style.positionType && @@ -21,7 +21,34 @@ bool YGStyle::operator==(const YGStyle& style) { YGValueArrayEqual(border, style.border) && YGValueArrayEqual(dimensions, style.dimensions) && YGValueArrayEqual(minDimensions, style.minDimensions) && - YGValueArrayEqual(maxDimensions, style.maxDimensions) && - flex == style.flex && flexGrow == style.flexGrow && - flexShrink == style.flexShrink && aspectRatio == style.aspectRatio); + YGValueArrayEqual(maxDimensions, style.maxDimensions); + + areNonFloatValuesEqual = + areNonFloatValuesEqual && flex.isUndefined() == style.flex.isUndefined(); + if (areNonFloatValuesEqual && !flex.isUndefined() && + !style.flex.isUndefined()) { + areNonFloatValuesEqual = + areNonFloatValuesEqual && flex.getValue() == style.flex.getValue(); + } + + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexGrow.isUndefined() == style.flexGrow.isUndefined(); + if (areNonFloatValuesEqual && !flexGrow.isUndefined()) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexGrow.getValue() == style.flexGrow.getValue(); + } + + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexShrink.isUndefined() == style.flexShrink.isUndefined(); + if (areNonFloatValuesEqual && !style.flexShrink.isUndefined()) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + flexShrink.getValue() == style.flexShrink.getValue(); + } + + if (!(aspectRatio.isUndefined() && style.aspectRatio.isUndefined())) { + areNonFloatValuesEqual = areNonFloatValuesEqual && + aspectRatio.getValue() == style.aspectRatio.getValue(); + } + + return areNonFloatValuesEqual; } diff --git a/yoga/YGStyle.h b/yoga/YGStyle.h index c4f7e3c7..c3a01d44 100644 --- a/yoga/YGStyle.h +++ b/yoga/YGStyle.h @@ -30,16 +30,16 @@ constexpr std::array kYGDefaultDimensionValuesUnit = { struct YGStyle { using Dimensions = std::array; - YGDirection direction : 2; - YGFlexDirection flexDirection : 2; - YGJustify justifyContent : 3; - YGAlign alignContent : 3; - YGAlign alignItems : 3; - YGAlign alignSelf : 3; - YGPositionType positionType : 1; - YGWrap flexWrap : 2; - YGOverflow overflow : 2; - YGDisplay display : 1; + YGDirection direction = YGDirectionInherit; + YGFlexDirection flexDirection = YGFlexDirectionColumn; + YGJustify justifyContent = YGJustifyFlexStart; + YGAlign alignContent = YGAlignFlexStart; + YGAlign alignItems = YGAlignStretch; + YGAlign alignSelf = YGAlignAuto; + YGPositionType positionType = YGPositionTypeRelative; + YGWrap flexWrap = YGWrapNoWrap; + YGOverflow overflow = YGOverflowVisible; + YGDisplay display = YGDisplayFlex; YGFloatOptional flex = {}; YGFloatOptional flexGrow = {}; YGFloatOptional flexShrink = {}; @@ -54,17 +54,7 @@ struct YGStyle { // Yoga specific properties, not compatible with flexbox specification YGFloatOptional aspectRatio = {}; - YGStyle() - : direction(YGDirectionInherit), - flexDirection(YGFlexDirectionColumn), - justifyContent(YGJustifyFlexStart), - alignContent(YGAlignFlexStart), - alignItems(YGAlignStretch), - alignSelf(YGAlignAuto), - positionType(YGPositionTypeRelative), - flexWrap(YGWrapNoWrap), - overflow(YGOverflowVisible), - display(YGDisplayFlex) {} + YGStyle() = default; bool operator==(const YGStyle& style); bool operator!=(YGStyle style) { diff --git a/yoga/YGValue.cpp b/yoga/YGValue.cpp deleted file mode 100644 index fcdd0c69..00000000 --- a/yoga/YGValue.cpp +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. - */ -#include "YGValue.h" - -const YGValue YGValueZero = {0, YGUnitPoint}; -const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; -const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; diff --git a/yoga/YGValue.h b/yoga/YGValue.h deleted file mode 100644 index 4e43f7b2..00000000 --- a/yoga/YGValue.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the LICENSE - * file in the root directory of this source tree. - */ -#pragma once - -#include -#include "YGEnums.h" -#include "YGMacros.h" - -YG_EXTERN_C_BEGIN - -// Not defined in MSVC++ -#ifndef NAN -static const uint32_t __nan = 0x7fc00000; -#define NAN (*(const float*)__nan) -#endif - -#define YGUndefined NAN - -typedef struct YGValue { - float value; - YGUnit unit; -} YGValue; - -extern const YGValue YGValueAuto; -extern const YGValue YGValueUndefined; -extern const YGValue YGValueZero; - -YG_EXTERN_C_END - -#ifdef __cplusplus - -inline bool operator==(const YGValue& lhs, const YGValue& rhs) { - if (lhs.unit != rhs.unit) { - return false; - } - - switch (lhs.unit) { - case YGUnitUndefined: - case YGUnitAuto: - return true; - case YGUnitPoint: - case YGUnitPercent: - default: - return lhs.value == rhs.value; - } -} - -inline bool operator!=(const YGValue& lhs, const YGValue& rhs) { - return !(lhs == rhs); -} - -#endif diff --git a/yoga/Yoga-internal.h b/yoga/Yoga-internal.h index ef5e5d8c..1e9a1aaf 100644 --- a/yoga/Yoga-internal.h +++ b/yoga/Yoga-internal.h @@ -27,7 +27,15 @@ namespace facebook { namespace yoga { inline bool isUndefined(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; } } // namespace yoga diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index f0327f87..6abfb7d3 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -18,7 +18,10 @@ /* define fmaxf if < VC12 */ #if _MSC_VER < 1800 __forceinline const float fmaxf(const float a, const float b) { - return (a > b) ? a : b; + if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) { + return (a > b) ? a : b; + } + return YGFloatIsUndefined(a) ? b : a; } #endif #endif @@ -39,6 +42,23 @@ static int YGDefaultLog( va_list args); #endif +const YGValue YGValueZero = {0, YGUnitPoint}; +const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; +const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; + +bool operator==(const YGValue& lhs, const YGValue& rhs) { + if ((lhs.unit == YGUnitUndefined && rhs.unit == YGUnitUndefined) || + (lhs.unit == YGUnitAuto && rhs.unit == YGUnitAuto)) { + return true; + } + + return lhs.unit == rhs.unit && lhs.value == rhs.value; +} + +bool operator!=(const YGValue& lhs, const YGValue& rhs) { + return !(lhs == rhs); +} + #ifdef ANDROID #include static int YGAndroidLog( @@ -579,18 +599,33 @@ void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) { } float YGNodeStyleGetFlexGrow(const YGNodeRef node) { - return node->getStyle().flexGrow.orElse(kDefaultFlexGrow); + return node->getStyle().flexGrow.isUndefined() + ? kDefaultFlexGrow + : node->getStyle().flexGrow.getValue(); } float YGNodeStyleGetFlexShrink(const YGNodeRef node) { - return node->getStyle().flexShrink.orElseGet([node] { - return node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink - : kDefaultFlexShrink; - }); + return node->getStyle().flexShrink.isUndefined() + ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink + : kDefaultFlexShrink) + : node->getStyle().flexShrink.getValue(); } namespace { +template +struct StyleProp { + static T get(YGNodeRef node) { + return node->getStyle().*P; + } + static void set(YGNodeRef node, T newValue) { + if (node->getStyle().*P != newValue) { + node->getStyle().*P = newValue; + node->markDirtyAndPropogate(); + } + } +}; + struct Value { template static YGValue create(float value) { @@ -750,88 +785,84 @@ struct DimensionProp { return node->getLayout().instanceName[edge]; \ } -#define YG_NODE_STYLE_SET(node, property, value) \ - if (node->getStyle().property != value) { \ - node->getStyle().property = value; \ - node->markDirtyAndPropogate(); \ - } - -void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) { - YG_NODE_STYLE_SET(node, direction, value); +void YGNodeStyleSetDirection( + const YGNodeRef node, + const YGDirection direction) { + StyleProp::set(node, direction); } YGDirection YGNodeStyleGetDirection(const YGNodeRef node) { - return node->getStyle().direction; + return StyleProp::get(node); } void YGNodeStyleSetFlexDirection( const YGNodeRef node, const YGFlexDirection flexDirection) { - YG_NODE_STYLE_SET(node, flexDirection, flexDirection); + StyleProp::set(node, flexDirection); } YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeRef node) { - return node->getStyle().flexDirection; + return StyleProp::get(node); } void YGNodeStyleSetJustifyContent( const YGNodeRef node, const YGJustify justifyContent) { - YG_NODE_STYLE_SET(node, justifyContent, justifyContent); + StyleProp::set(node, justifyContent); } YGJustify YGNodeStyleGetJustifyContent(const YGNodeRef node) { - return node->getStyle().justifyContent; + return StyleProp::get(node); } void YGNodeStyleSetAlignContent( const YGNodeRef node, const YGAlign alignContent) { - YG_NODE_STYLE_SET(node, alignContent, alignContent); + StyleProp::set(node, alignContent); } YGAlign YGNodeStyleGetAlignContent(const YGNodeRef node) { - return node->getStyle().alignContent; + return StyleProp::get(node); } void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) { - YG_NODE_STYLE_SET(node, alignItems, alignItems); + StyleProp::set(node, alignItems); } YGAlign YGNodeStyleGetAlignItems(const YGNodeRef node) { - return node->getStyle().alignItems; + return StyleProp::get(node); } void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) { - YG_NODE_STYLE_SET(node, alignSelf, alignSelf); + StyleProp::set(node, alignSelf); } YGAlign YGNodeStyleGetAlignSelf(const YGNodeRef node) { - return node->getStyle().alignSelf; + return StyleProp::get(node); } void YGNodeStyleSetPositionType( const YGNodeRef node, const YGPositionType positionType) { - YG_NODE_STYLE_SET(node, positionType, positionType); + StyleProp::set(node, positionType); } YGPositionType YGNodeStyleGetPositionType(const YGNodeRef node) { - return node->getStyle().positionType; + return StyleProp::get(node); } void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) { - YG_NODE_STYLE_SET(node, flexWrap, flexWrap); + StyleProp::set(node, flexWrap); } YGWrap YGNodeStyleGetFlexWrap(const YGNodeRef node) { - return node->getStyle().flexWrap; + return StyleProp::get(node); } void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) { - YG_NODE_STYLE_SET(node, overflow, overflow); + StyleProp::set(node, overflow); } YGOverflow YGNodeStyleGetOverflow(const YGNodeRef node) { - return node->getStyle().overflow; + return StyleProp::get(node); } void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) { - YG_NODE_STYLE_SET(node, display, display); + StyleProp::set(node, display); } YGDisplay YGNodeStyleGetDisplay(const YGNodeRef node) { - return node->getStyle().display; + return StyleProp::get(node); } // TODO(T26792433): Change the API to accept YGFloatOptional. @@ -845,7 +876,8 @@ void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { // TODO(T26792433): Change the API to accept YGFloatOptional. float YGNodeStyleGetFlex(const YGNodeRef node) { - return node->getStyle().flex.orElse(YGUndefined); + return node->getStyle().flex.isUndefined() ? YGUndefined + : node->getStyle().flex.getValue(); } // TODO(T26792433): Change the API to accept YGFloatOptional. @@ -947,7 +979,7 @@ float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) { // TODO(T26792433): Change the API to accept YGFloatOptional. float YGNodeStyleGetAspectRatio(const YGNodeRef node) { const YGFloatOptional op = node->getStyle().aspectRatio; - return op.orElse(YGUndefined); + return op.isUndefined() ? YGUndefined : op.getValue(); } // TODO(T26792433): Change the API to accept YGFloatOptional. @@ -1057,7 +1089,7 @@ static void YGNodePrintInternal( const YGNodeRef node, const YGPrintOptions options) { std::string str; - facebook::yoga::YGNodeToString(str, node, options, 0); + facebook::yoga::YGNodeToString(&str, node, options, 0); YGLog(node, YGLogLevelDebug, str.c_str()); } @@ -1084,9 +1116,9 @@ static inline float YGNodePaddingAndBorderForAxis( const YGNodeRef node, const YGFlexDirection axis, const float widthSize) { - return (node->getLeadingPaddingAndBorder(axis, widthSize) + - node->getTrailingPaddingAndBorder(axis, widthSize)) - .unwrap(); + return YGUnwrapFloatOptional( + node->getLeadingPaddingAndBorder(axis, widthSize) + + node->getTrailingPaddingAndBorder(axis, widthSize)); } static inline YGAlign YGNodeAlignItem( @@ -1168,9 +1200,9 @@ static inline float YGNodeDimWithMargin( const YGFlexDirection axis, const float widthSize) { return node->getLayout().measuredDimensions[dim[axis]] + - (node->getLeadingMargin(axis, widthSize) + - node->getTrailingMargin(axis, widthSize)) - .unwrap(); + YGUnwrapFloatOptional( + node->getLeadingMargin(axis, widthSize) + + node->getTrailingMargin(axis, widthSize)); } static inline bool YGNodeIsStyleDimDefined( @@ -1200,7 +1232,7 @@ static inline bool YGNodeIsLayoutDimDefined( static YGFloatOptional YGNodeBoundAxisWithinMinAndMax( const YGNodeRef node, const YGFlexDirection axis, - const YGFloatOptional value, + const float value, const float axisSize) { YGFloatOptional min; YGFloatOptional max; @@ -1217,15 +1249,15 @@ static YGFloatOptional YGNodeBoundAxisWithinMinAndMax( node->getStyle().maxDimensions[YGDimensionWidth], axisSize); } - if (max >= YGFloatOptional{0} && value > max) { + if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) { return max; } - if (min >= YGFloatOptional{0} && value < min) { + if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) { return min; } - return value; + return YGFloatOptional(value); } // Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't @@ -1237,9 +1269,8 @@ static inline float YGNodeBoundAxis( const float axisSize, const float widthSize) { return YGFloatMax( - (YGNodeBoundAxisWithinMinAndMax( - node, axis, YGFloatOptional{value}, axisSize)) - .unwrap(), + YGUnwrapFloatOptional( + YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)), YGNodePaddingAndBorderForAxis(node, axis, widthSize)); } @@ -1267,14 +1298,14 @@ static void YGConstrainMaxSizeForMode( switch (*mode) { case YGMeasureModeExactly: case YGMeasureModeAtMost: - if (YGFloatOptional{*size} > maxSize) { - *size = maxSize.unwrap(); - } + *size = (maxSize.isUndefined() || *size < maxSize.getValue()) + ? *size + : maxSize.getValue(); break; case YGMeasureModeUndefined: if (!maxSize.isUndefined()) { *mode = YGMeasureModeAtMost; - *size = maxSize.unwrap(); + *size = maxSize.getValue(); } break; } @@ -1315,14 +1346,14 @@ static void YGNodeComputeFlexBasisForChild( child->getConfig(), YGExperimentalFeatureWebFlexBasis) && child->getLayout().computedFlexBasisGeneration != gCurrentGenerationCount)) { - const YGFloatOptional paddingAndBorder = YGFloatOptional( + const YGFloatOptional& paddingAndBorder = YGFloatOptional( YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)); child->setLayoutComputedFlexBasis( YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder)); } } else if (isMainAxisRow && isRowStyleDimDefined) { // The width is definite, so use that as the flex basis. - const YGFloatOptional paddingAndBorder = YGFloatOptional( + const YGFloatOptional& paddingAndBorder = YGFloatOptional( YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth)); child->setLayoutComputedFlexBasis(YGFloatOptionalMax( @@ -1331,7 +1362,7 @@ static void YGNodeComputeFlexBasisForChild( paddingAndBorder)); } else if (!isMainAxisRow && isColumnStyleDimDefined) { // The height is definite, so use that as the flex basis. - const YGFloatOptional paddingAndBorder = + const YGFloatOptional& paddingAndBorder = YGFloatOptional(YGNodePaddingAndBorderForAxis( child, YGFlexDirectionColumn, ownerWidth)); child->setLayoutComputedFlexBasis(YGFloatOptionalMax( @@ -1346,24 +1377,22 @@ static void YGNodeComputeFlexBasisForChild( childWidthMeasureMode = YGMeasureModeUndefined; childHeightMeasureMode = YGMeasureModeUndefined; - auto marginRow = - (child->getMarginForAxis(YGFlexDirectionRow, ownerWidth)).unwrap(); - auto marginColumn = - (child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)).unwrap(); + auto marginRow = YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + auto marginColumn = YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); if (isRowStyleDimDefined) { childWidth = - (YGResolveValue( - child->getResolvedDimension(YGDimensionWidth), ownerWidth)) - .unwrap() + + YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionWidth), ownerWidth)) + marginRow; childWidthMeasureMode = YGMeasureModeExactly; } if (isColumnStyleDimDefined) { childHeight = - (YGResolveValue( - child->getResolvedDimension(YGDimensionHeight), ownerHeight)) - .unwrap() + + YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionHeight), ownerHeight)) + marginColumn; childHeightMeasureMode = YGMeasureModeExactly; } @@ -1386,15 +1415,16 @@ static void YGNodeComputeFlexBasisForChild( } } - auto hasAspectRatio = !child->getStyle().aspectRatio.isUndefined(); - auto aspectRatio = child->getStyle().aspectRatio.unwrap(); - if (hasAspectRatio) { + if (!child->getStyle().aspectRatio.isUndefined()) { if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) { - childHeight = marginColumn + (childWidth - marginRow) / aspectRatio; + childHeight = marginColumn + + (childWidth - marginRow) / child->getStyle().aspectRatio.getValue(); childHeightMeasureMode = YGMeasureModeExactly; } else if ( isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) { - childWidth = marginRow + (childHeight - marginColumn) * aspectRatio; + childWidth = marginRow + + (childHeight - marginColumn) * + child->getStyle().aspectRatio.getValue(); childWidthMeasureMode = YGMeasureModeExactly; } } @@ -1412,8 +1442,9 @@ static void YGNodeComputeFlexBasisForChild( childWidthStretch) { childWidth = width; childWidthMeasureMode = YGMeasureModeExactly; - if (hasAspectRatio) { - childHeight = (childWidth - marginRow) / aspectRatio; + if (!child->getStyle().aspectRatio.isUndefined()) { + childHeight = + (childWidth - marginRow) / child->getStyle().aspectRatio.getValue(); childHeightMeasureMode = YGMeasureModeExactly; } } @@ -1428,8 +1459,9 @@ static void YGNodeComputeFlexBasisForChild( childHeight = height; childHeightMeasureMode = YGMeasureModeExactly; - if (hasAspectRatio) { - childWidth = (childHeight - marginColumn) * aspectRatio; + if (!child->getStyle().aspectRatio.isUndefined()) { + childWidth = (childHeight - marginColumn) * + child->getStyle().aspectRatio.getValue(); childWidthMeasureMode = YGMeasureModeExactly; } } @@ -1489,14 +1521,13 @@ static void YGNodeAbsoluteLayoutChild( YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined; auto marginRow = - (child->getMarginForAxis(YGFlexDirectionRow, width)).unwrap(); - auto marginColumn = - (child->getMarginForAxis(YGFlexDirectionColumn, width)).unwrap(); + YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width)); + auto marginColumn = YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionColumn, width)); if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) { - childWidth = - (YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)) - .unwrap() + + childWidth = YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionWidth), width)) + marginRow; } else { // If the child doesn't have a specified width, compute the width based @@ -1507,18 +1538,17 @@ static void YGNodeAbsoluteLayoutChild( childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] - (node->getLeadingBorder(YGFlexDirectionRow) + node->getTrailingBorder(YGFlexDirectionRow)) - - (child->getLeadingPosition(YGFlexDirectionRow, width) + - child->getTrailingPosition(YGFlexDirectionRow, width)) - .unwrap(); + YGUnwrapFloatOptional( + child->getLeadingPosition(YGFlexDirectionRow, width) + + child->getTrailingPosition(YGFlexDirectionRow, width)); childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width); } } if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) { - childHeight = - (YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)) - .unwrap() + + childHeight = YGUnwrapFloatOptional(YGResolveValue( + child->getResolvedDimension(YGDimensionHeight), height)) + marginColumn; } else { // If the child doesn't have a specified height, compute the height @@ -1526,12 +1556,13 @@ static void YGNodeAbsoluteLayoutChild( // offsets if they're defined. if (child->isLeadingPositionDefined(YGFlexDirectionColumn) && child->isTrailingPosDefined(YGFlexDirectionColumn)) { - childHeight = node->getLayout().measuredDimensions[YGDimensionHeight] - + childHeight = + node->getLayout().measuredDimensions[YGDimensionHeight] - (node->getLeadingBorder(YGFlexDirectionColumn) + node->getTrailingBorder(YGFlexDirectionColumn)) - - (child->getLeadingPosition(YGFlexDirectionColumn, height) + - child->getTrailingPosition(YGFlexDirectionColumn, height)) - .unwrap(); + YGUnwrapFloatOptional( + child->getLeadingPosition(YGFlexDirectionColumn, height) + + child->getTrailingPosition(YGFlexDirectionColumn, height)); childHeight = YGNodeBoundAxis( child, YGFlexDirectionColumn, childHeight, height, width); } @@ -1542,11 +1573,13 @@ static void YGNodeAbsoluteLayoutChild( // flexible. if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) { if (!child->getStyle().aspectRatio.isUndefined()) { - auto aspectRatio = child->getStyle().aspectRatio.unwrap(); if (YGFloatIsUndefined(childWidth)) { - childWidth = marginRow + (childHeight - marginColumn) * aspectRatio; + childWidth = marginRow + + (childHeight - marginColumn) * + child->getStyle().aspectRatio.getValue(); } else if (YGFloatIsUndefined(childHeight)) { - childHeight = marginColumn + (childWidth - marginRow) / aspectRatio; + childHeight = marginColumn + + (childWidth - marginRow) / child->getStyle().aspectRatio.getValue(); } } } @@ -1584,9 +1617,11 @@ static void YGNodeAbsoluteLayoutChild( "abs-measure", config); childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] + - (child->getMarginForAxis(YGFlexDirectionRow, width)).unwrap(); + YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionRow, width)); childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] + - (child->getMarginForAxis(YGFlexDirectionColumn, width)).unwrap(); + YGUnwrapFloatOptional( + child->getMarginForAxis(YGFlexDirectionColumn, width)); } YGLayoutNodeInternal( @@ -1608,10 +1643,9 @@ static void YGNodeAbsoluteLayoutChild( node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]] - node->getTrailingBorder(mainAxis) - - (child->getTrailingMargin(mainAxis, width)).unwrap() - - (child->getTrailingPosition( - mainAxis, isMainAxisRow ? width : height)) - .unwrap(), + YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) - + YGUnwrapFloatOptional(child->getTrailingPosition( + mainAxis, isMainAxisRow ? width : height)), leading[mainAxis]); } else if ( !child->isLeadingPositionDefined(mainAxis) && @@ -1636,10 +1670,9 @@ static void YGNodeAbsoluteLayoutChild( node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().measuredDimensions[dim[crossAxis]] - node->getTrailingBorder(crossAxis) - - (child->getTrailingMargin(crossAxis, width)).unwrap() - - (child->getTrailingPosition( - crossAxis, isMainAxisRow ? height : width)) - .unwrap(), + YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) - + YGUnwrapFloatOptional(child->getTrailingPosition( + crossAxis, isMainAxisRow ? height : width)), leading[crossAxis]); } else if ( @@ -1678,10 +1711,10 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis( node, YGFlexDirectionColumn, availableWidth); - const float marginAxisRow = - (node->getMarginForAxis(YGFlexDirectionRow, availableWidth)).unwrap(); - const float marginAxisColumn = - (node->getMarginForAxis(YGFlexDirectionColumn, availableWidth)).unwrap(); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, availableWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, availableWidth)); // We want to make sure we don't call measure with negative size const float innerWidth = YGFloatIsUndefined(availableWidth) @@ -1756,10 +1789,10 @@ static void YGNodeEmptyContainerSetMeasuredDimensions( YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth); const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth); - const float marginAxisRow = - (node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)).unwrap(); - const float marginAxisColumn = - (node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)).unwrap(); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); node->setLayoutMeasuredDimension( YGNodeBoundAxis( @@ -1800,10 +1833,10 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) || (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) { - auto marginAxisColumn = - (node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)).unwrap(); - auto marginAxisRow = - (node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)).unwrap(); + auto marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); + auto marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); node->setLayoutMeasuredDimension( YGNodeBoundAxis( @@ -1859,7 +1892,8 @@ static float YGNodeCalculateAvailableInnerDim( YGDimension dimension = YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight; - const float margin = (node->getMarginForAxis(direction, ownerDim)).unwrap(); + const float margin = + YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim)); const float paddingAndBorder = YGNodePaddingAndBorderForAxis(node, direction, ownerDim); @@ -1871,15 +1905,16 @@ static float YGNodeCalculateAvailableInnerDim( // constraints const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim); - const float minInnerDim = - (minDimensionOptional - YGFloatOptional{paddingAndBorder}).orElse(0.0f); + const float minInnerDim = minDimensionOptional.isUndefined() + ? 0.0f + : minDimensionOptional.getValue() - paddingAndBorder; const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim); - const float maxInnerDim = - (maxDimensionOptional - YGFloatOptional{paddingAndBorder}) - .orElse(FLT_MAX); + const float maxInnerDim = maxDimensionOptional.isUndefined() + ? FLT_MAX + : maxDimensionOptional.getValue() - paddingAndBorder; availableInnerDim = YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim); } @@ -1963,10 +1998,9 @@ static float YGNodeComputeFlexBasisForChildren( config); } - totalOuterFlexBasis += - (child->getLayout().computedFlexBasis + - child->getMarginForAxis(mainAxis, availableInnerWidth)) - .unwrap(); + totalOuterFlexBasis += YGUnwrapFloatOptional( + child->getLayout().computedFlexBasis + + child->getMarginForAxis(mainAxis, availableInnerWidth)); } return totalOuterFlexBasis; @@ -2001,15 +2035,14 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( continue; } child->setLineIndex(lineCount); - const float childMarginMainAxis = - (child->getMarginForAxis(mainAxis, availableInnerWidth)).unwrap(); + const float childMarginMainAxis = YGUnwrapFloatOptional( + child->getMarginForAxis(mainAxis, availableInnerWidth)); const float flexBasisWithMinAndMaxConstraints = - (YGNodeBoundAxisWithinMinAndMax( - child, - mainAxis, - child->getLayout().computedFlexBasis, - mainAxisownerSize)) - .unwrap(); + YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( + child, + mainAxis, + YGUnwrapFloatOptional(child->getLayout().computedFlexBasis), + mainAxisownerSize)); // If this is a multi-line flow and this item pushes us over the // available size, we've @@ -2035,7 +2068,7 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues( // child dimension. flexAlgoRowMeasurement.totalFlexShrinkScaledFactors += -child->resolveFlexShrink() * - (child->getLayout().computedFlexBasis).unwrap(); + YGUnwrapFloatOptional(child->getLayout().computedFlexBasis); } flexAlgoRowMeasurement.relativeChildren.push_back(child); @@ -2082,12 +2115,12 @@ static float YGDistributeFreeSpaceSecondPass( const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap; for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) { - childFlexBasis = (YGNodeBoundAxisWithinMinAndMax( - currentRelativeChild, - mainAxis, - currentRelativeChild->getLayout().computedFlexBasis, - mainAxisownerSize)) - .unwrap(); + childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( + currentRelativeChild, + mainAxis, + YGUnwrapFloatOptional( + currentRelativeChild->getLayout().computedFlexBasis), + mainAxisownerSize)); float updatedMainSize = childFlexBasis; if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && @@ -2137,12 +2170,10 @@ static float YGDistributeFreeSpaceSecondPass( deltaFreeSpace += updatedMainSize - childFlexBasis; - const float marginMain = - (currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth)) - .unwrap(); - const float marginCross = - (currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth)) - .unwrap(); + const float marginMain = YGUnwrapFloatOptional( + currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth)); + const float marginCross = YGUnwrapFloatOptional( + currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth)); float childCrossSize; float childMainSize = updatedMainSize + marginMain; @@ -2151,9 +2182,9 @@ static float YGDistributeFreeSpaceSecondPass( if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) { childCrossSize = isMainAxisRow ? (childMainSize - marginMain) / - currentRelativeChild->getStyle().aspectRatio.unwrap() + currentRelativeChild->getStyle().aspectRatio.getValue() : (childMainSize - marginMain) * - currentRelativeChild->getStyle().aspectRatio.unwrap(); + currentRelativeChild->getStyle().aspectRatio.getValue(); childCrossMeasureMode = YGMeasureModeExactly; childCrossSize += marginCross; @@ -2178,10 +2209,9 @@ static float YGDistributeFreeSpaceSecondPass( : YGMeasureModeAtMost; } else { childCrossSize = - (YGResolveValue( - currentRelativeChild->getResolvedDimension(dim[crossAxis]), - availableInnerCrossDim)) - .unwrap() + + YGUnwrapFloatOptional(YGResolveValue( + currentRelativeChild->getResolvedDimension(dim[crossAxis]), + availableInnerCrossDim)) + marginCross; const bool isLoosePercentageMeasurement = currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit == @@ -2261,13 +2291,12 @@ static void YGDistributeFreeSpaceFirstPass( float deltaFreeSpace = 0; for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) { - float childFlexBasis = - (YGNodeBoundAxisWithinMinAndMax( - currentRelativeChild, - mainAxis, - currentRelativeChild->getLayout().computedFlexBasis, - mainAxisownerSize)) - .unwrap(); + float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( + currentRelativeChild, + mainAxis, + YGUnwrapFloatOptional( + currentRelativeChild->getLayout().computedFlexBasis), + mainAxisownerSize)); if (collectedFlexItemsValues.remainingFreeSpace < 0) { flexShrinkScaledFactor = @@ -2418,10 +2447,10 @@ static void YGJustifyMainAxis( const float availableInnerWidth, const bool performLayout) { const YGStyle& style = node->getStyle(); - const float leadingPaddingAndBorderMain = - (node->getLeadingPaddingAndBorder(mainAxis, ownerWidth)).unwrap(); - const float trailingPaddingAndBorderMain = - (node->getTrailingPaddingAndBorder(mainAxis, ownerWidth)).unwrap(); + const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional( + node->getLeadingPaddingAndBorder(mainAxis, ownerWidth)); + const float trailingPaddingAndBorderMain = YGUnwrapFloatOptional( + node->getTrailingPaddingAndBorder(mainAxis, ownerWidth)); // If we are using "at most" rules in the main axis, make sure that // remainingFreeSpace is 0 when min main dimension is not given if (measureModeMainDim == YGMeasureModeAtMost && @@ -2437,9 +2466,8 @@ static void YGJustifyMainAxis( // `minAvailableMainDim` denotes minimum available space in which child // can be laid out, it will exclude space consumed by padding and border. const float minAvailableMainDim = - (YGResolveValue( - style.minDimensions[dim[mainAxis]], mainAxisownerSize)) - .unwrap() - + YGUnwrapFloatOptional(YGResolveValue( + style.minDimensions[dim[mainAxis]], mainAxisownerSize)) - leadingPaddingAndBorderMain - trailingPaddingAndBorderMain; const float occupiedSpaceByChildNodes = availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace; @@ -2529,11 +2557,11 @@ static void YGJustifyMainAxis( // defined, we override the position to whatever the user said // (and margin/border). child->setLayoutPosition( - (child->getLeadingPosition(mainAxis, availableInnerMainDim)) - .unwrap() + + YGUnwrapFloatOptional( + child->getLeadingPosition(mainAxis, availableInnerMainDim)) + node->getLeadingBorder(mainAxis) + - (child->getLeadingMargin(mainAxis, availableInnerWidth)) - .unwrap(), + YGUnwrapFloatOptional( + child->getLeadingMargin(mainAxis, availableInnerWidth)), pos[mainAxis]); } } else { @@ -2567,9 +2595,9 @@ static void YGJustifyMainAxis( // they weren't computed. This means we can't call // YGNodeDimWithMargin. collectedFlexItemsValues.mainDim += betweenMainDim + - (child->getMarginForAxis(mainAxis, availableInnerWidth)) - .unwrap() + - (childLayout.computedFlexBasis).unwrap(); + YGUnwrapFloatOptional(child->getMarginForAxis( + mainAxis, availableInnerWidth)) + + YGUnwrapFloatOptional(childLayout.computedFlexBasis); collectedFlexItemsValues.crossDim = availableInnerCrossDim; } else { // The main dimension is the sum of all the elements dimension plus @@ -2581,14 +2609,12 @@ static void YGJustifyMainAxis( // If the child is baseline aligned then the cross dimension is // calculated by adding maxAscent and maxDescent from the baseline. const float ascent = YGBaseline(child) + - (child->getLeadingMargin( - YGFlexDirectionColumn, availableInnerWidth)) - .unwrap(); + YGUnwrapFloatOptional(child->getLeadingMargin( + YGFlexDirectionColumn, availableInnerWidth)); const float descent = child->getLayout().measuredDimensions[YGDimensionHeight] + - (child->getMarginForAxis( - YGFlexDirectionColumn, availableInnerWidth)) - .unwrap() - + YGUnwrapFloatOptional(child->getMarginForAxis( + YGFlexDirectionColumn, availableInnerWidth)) - ascent; maxAscentForCurrentLine = @@ -2741,16 +2767,20 @@ static void YGNodelayoutImpl( YGResolveFlexDirection(YGFlexDirectionColumn, direction); node->setLayoutMargin( - (node->getLeadingMargin(flexRowDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getLeadingMargin(flexRowDirection, ownerWidth)), YGEdgeStart); node->setLayoutMargin( - (node->getTrailingMargin(flexRowDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getTrailingMargin(flexRowDirection, ownerWidth)), YGEdgeEnd); node->setLayoutMargin( - (node->getLeadingMargin(flexColumnDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getLeadingMargin(flexColumnDirection, ownerWidth)), YGEdgeTop); node->setLayoutMargin( - (node->getTrailingMargin(flexColumnDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getTrailingMargin(flexColumnDirection, ownerWidth)), YGEdgeBottom); node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart); @@ -2760,16 +2790,20 @@ static void YGNodelayoutImpl( node->getTrailingBorder(flexColumnDirection), YGEdgeBottom); node->setLayoutPadding( - (node->getLeadingPadding(flexRowDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getLeadingPadding(flexRowDirection, ownerWidth)), YGEdgeStart); node->setLayoutPadding( - (node->getTrailingPadding(flexRowDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getTrailingPadding(flexRowDirection, ownerWidth)), YGEdgeEnd); node->setLayoutPadding( - (node->getLeadingPadding(flexColumnDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getLeadingPadding(flexColumnDirection, ownerWidth)), YGEdgeTop); node->setLayoutPadding( - (node->getTrailingPadding(flexColumnDirection, ownerWidth)).unwrap(), + YGUnwrapFloatOptional( + node->getTrailingPadding(flexColumnDirection, ownerWidth)), YGEdgeBottom); if (node->getMeasure() != nullptr) { @@ -2827,8 +2861,8 @@ static void YGNodelayoutImpl( const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth; - const float leadingPaddingAndBorderCross = - (node->getLeadingPaddingAndBorder(crossAxis, ownerWidth)).unwrap(); + const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional( + node->getLeadingPaddingAndBorder(crossAxis, ownerWidth)); const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth); const float paddingAndBorderAxisCross = @@ -2844,30 +2878,26 @@ static void YGNodelayoutImpl( const float paddingAndBorderAxisColumn = isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain; - const float marginAxisRow = - (node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)).unwrap(); - const float marginAxisColumn = - (node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)).unwrap(); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); const float minInnerWidth = - (YGResolveValue( - node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) - .unwrap() - + YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) - paddingAndBorderAxisRow; const float maxInnerWidth = - (YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) - .unwrap() - + YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) - paddingAndBorderAxisRow; const float minInnerHeight = - (YGResolveValue( - node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) - .unwrap() - + YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) - paddingAndBorderAxisColumn; const float maxInnerHeight = - (YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) - .unwrap() - + YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) - paddingAndBorderAxisColumn; const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight; @@ -3078,11 +3108,11 @@ static void YGNodelayoutImpl( child->isLeadingPositionDefined(crossAxis); if (isChildLeadingPosDefined) { child->setLayoutPosition( - (child->getLeadingPosition(crossAxis, availableInnerCrossDim)) - .unwrap() + + YGUnwrapFloatOptional(child->getLeadingPosition( + crossAxis, availableInnerCrossDim)) + node->getLeadingBorder(crossAxis) + - (child->getLeadingMargin(crossAxis, availableInnerWidth)) - .unwrap(), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); } // If leading position is not defined or calculations result in Nan, @@ -3091,8 +3121,8 @@ static void YGNodelayoutImpl( YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) { child->setLayoutPosition( node->getLeadingBorder(crossAxis) + - (child->getLeadingMargin(crossAxis, availableInnerWidth)) - .unwrap(), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); } } else { @@ -3118,17 +3148,16 @@ static void YGNodelayoutImpl( child->getLayout().measuredDimensions[dim[mainAxis]]; float childCrossSize = !child->getStyle().aspectRatio.isUndefined() - ? (((child->getMarginForAxis(crossAxis, availableInnerWidth)) - .unwrap() + + ? ((YGUnwrapFloatOptional(child->getMarginForAxis( + crossAxis, availableInnerWidth)) + (isMainAxisRow ? childMainSize / - child->getStyle().aspectRatio.unwrap() + child->getStyle().aspectRatio.getValue() : childMainSize * - child->getStyle().aspectRatio.unwrap()))) + child->getStyle().aspectRatio.getValue()))) : collectedFlexItemsValues.crossDim; - childMainSize += - (child->getMarginForAxis(mainAxis, availableInnerWidth)) - .unwrap(); + childMainSize += YGUnwrapFloatOptional( + child->getMarginForAxis(mainAxis, availableInnerWidth)); YGMeasureMode childMainMeasureMode = YGMeasureModeExactly; YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly; @@ -3270,19 +3299,17 @@ static void YGNodelayoutImpl( lineHeight = YGFloatMax( lineHeight, child->getLayout().measuredDimensions[dim[crossAxis]] + - (child->getMarginForAxis(crossAxis, availableInnerWidth)) - .unwrap()); + YGUnwrapFloatOptional(child->getMarginForAxis( + crossAxis, availableInnerWidth))); } if (YGNodeAlignItem(node, child) == YGAlignBaseline) { const float ascent = YGBaseline(child) + - (child->getLeadingMargin( - YGFlexDirectionColumn, availableInnerWidth)) - .unwrap(); + YGUnwrapFloatOptional(child->getLeadingMargin( + YGFlexDirectionColumn, availableInnerWidth)); const float descent = child->getLayout().measuredDimensions[YGDimensionHeight] + - (child->getMarginForAxis( - YGFlexDirectionColumn, availableInnerWidth)) - .unwrap() - + YGUnwrapFloatOptional(child->getMarginForAxis( + YGFlexDirectionColumn, availableInnerWidth)) - ascent; maxAscentForCurrentLine = YGFloatMax(maxAscentForCurrentLine, ascent); @@ -3307,18 +3334,16 @@ static void YGNodelayoutImpl( case YGAlignFlexStart: { child->setLayoutPosition( currentLead + - (child->getLeadingMargin( - crossAxis, availableInnerWidth)) - .unwrap(), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); break; } case YGAlignFlexEnd: { child->setLayoutPosition( currentLead + lineHeight - - (child->getTrailingMargin( - crossAxis, availableInnerWidth)) - .unwrap() - + YGUnwrapFloatOptional(child->getTrailingMargin( + crossAxis, availableInnerWidth)) - child->getLayout().measuredDimensions[dim[crossAxis]], pos[crossAxis]); break; @@ -3335,9 +3360,8 @@ static void YGNodelayoutImpl( case YGAlignStretch: { child->setLayoutPosition( currentLead + - (child->getLeadingMargin( - crossAxis, availableInnerWidth)) - .unwrap(), + YGUnwrapFloatOptional(child->getLeadingMargin( + crossAxis, availableInnerWidth)), pos[crossAxis]); // Remeasure child with the line height as it as been only @@ -3347,17 +3371,15 @@ static void YGNodelayoutImpl( const float childWidth = isMainAxisRow ? (child->getLayout() .measuredDimensions[YGDimensionWidth] + - (child->getMarginForAxis( - mainAxis, availableInnerWidth)) - .unwrap()) + YGUnwrapFloatOptional(child->getMarginForAxis( + mainAxis, availableInnerWidth))) : lineHeight; const float childHeight = !isMainAxisRow ? (child->getLayout() .measuredDimensions[YGDimensionHeight] + - (child->getMarginForAxis( - crossAxis, availableInnerWidth)) - .unwrap()) + YGUnwrapFloatOptional(child->getMarginForAxis( + crossAxis, availableInnerWidth))) : lineHeight; if (!(YGFloatsEqual( @@ -3387,9 +3409,8 @@ static void YGNodelayoutImpl( case YGAlignBaseline: { child->setLayoutPosition( currentLead + maxAscentForCurrentLine - YGBaseline(child) + - (child->getLeadingPosition( - YGFlexDirectionColumn, availableInnerCrossDim)) - .unwrap(), + YGUnwrapFloatOptional(child->getLeadingPosition( + YGFlexDirectionColumn, availableInnerCrossDim)), YGEdgeTop); break; @@ -3445,12 +3466,8 @@ static void YGNodelayoutImpl( YGFloatMax( YGFloatMin( availableInnerMainDim + paddingAndBorderAxisMain, - (YGNodeBoundAxisWithinMinAndMax( - node, - mainAxis, - YGFloatOptional{maxLineMainDim}, - mainAxisownerSize)) - .unwrap()), + YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( + node, mainAxis, maxLineMainDim, mainAxisownerSize))), paddingAndBorderAxisMain), dim[mainAxis]); } @@ -3476,13 +3493,11 @@ static void YGNodelayoutImpl( YGFloatMax( YGFloatMin( availableInnerCrossDim + paddingAndBorderAxisCross, - (YGNodeBoundAxisWithinMinAndMax( - node, - crossAxis, - YGFloatOptional{totalLineCrossDim + - paddingAndBorderAxisCross}, - crossAxisownerSize)) - .unwrap()), + YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax( + node, + crossAxis, + totalLineCrossDim + paddingAndBorderAxisCross, + crossAxisownerSize))), paddingAndBorderAxisCross), dim[crossAxis]); } @@ -3782,10 +3797,10 @@ bool YGLayoutNodeInternal( // expensive to measure, so it's worth avoiding redundant measurements if at // all possible. if (node->getMeasure() != nullptr) { - const float marginAxisRow = - (node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)).unwrap(); - const float marginAxisColumn = - (node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)).unwrap(); + const float marginAxisRow = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); + const float marginAxisColumn = YGUnwrapFloatOptional( + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); // First, try to use the layout cache. if (YGNodeCanUseCachedMeasurement( @@ -4085,18 +4100,16 @@ void YGNodeCalculateLayout( float width = YGUndefined; YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) { - width = - (YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) + - node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)) - .unwrap(); + width = YGUnwrapFloatOptional( + YGResolveValue( + node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) + + node->getMarginForAxis(YGFlexDirectionRow, ownerWidth)); widthMeasureMode = YGMeasureModeExactly; } else if (!YGResolveValue( node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth) .isUndefined()) { - width = (YGResolveValue( - node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) - .unwrap(); + width = YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)); widthMeasureMode = YGMeasureModeAtMost; } else { width = ownerWidth; @@ -4107,20 +4120,18 @@ void YGNodeCalculateLayout( float height = YGUndefined; YGMeasureMode heightMeasureMode = YGMeasureModeUndefined; if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) { - height = (YGResolveValue( - node->getResolvedDimension(dim[YGFlexDirectionColumn]), - ownerHeight) + - node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)) - .unwrap(); + height = YGUnwrapFloatOptional( + YGResolveValue( + node->getResolvedDimension(dim[YGFlexDirectionColumn]), + ownerHeight) + + node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth)); heightMeasureMode = YGMeasureModeExactly; } else if (!YGResolveValue( node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight) .isUndefined()) { - height = - (YGResolveValue( - node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) - .unwrap(); + height = YGUnwrapFloatOptional(YGResolveValue( + node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)); heightMeasureMode = YGMeasureModeAtMost; } else { height = ownerHeight; diff --git a/yoga/Yoga.h b/yoga/Yoga.h index 787af6df..96e71dc7 100644 --- a/yoga/Yoga.h +++ b/yoga/Yoga.h @@ -17,9 +17,17 @@ #include #endif +/** 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" -#include "YGValue.h" YG_EXTERN_C_BEGIN @@ -28,6 +36,25 @@ typedef struct YGSize { float height; } YGSize; +typedef struct YGValue { + float value; + YGUnit unit; +} YGValue; + +extern const YGValue YGValueUndefined; +extern const YGValue YGValueAuto; + +#ifdef __cplusplus + +YG_EXTERN_C_END + +extern bool operator==(const YGValue& lhs, const YGValue& rhs); +extern bool operator!=(const YGValue& lhs, const YGValue& rhs); + +YG_EXTERN_C_BEGIN + +#endif + typedef struct YGConfig* YGConfigRef; typedef struct YGNode* YGNodeRef;