From 758849c0b7be098c5a8c198ca05ae7682fe1640d Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 4 Sep 2023 03:03:46 -0700 Subject: [PATCH] C++ Cleanup 8/N: Yoga-internal (#1355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1355 X-link: https://github.com/facebook/react-native/pull/39198 ## This diff This splits up `Yoga-internal.h` which has become a grab bag. The actual header is left, with the purpose of being a private C ABI for bindings, but everything else is moved to a place more appropriate or removed. A few notes: 1. `yoga::isUndefined` is replaced with `std::isnan` to avoid a layer of indirection (we will never be able to change its representation anyway). Internal usages of `YGFloatIsUndefined` are also replaced with `std::isnan` since the previous being at a library boundary means I'm not sure it can be inlined/. 2. `leading`, `trailing` arrays are factored into proper functions 3. `Values` is replaced entirely with `std::array`, since most of it was unused. ## This stack The organization of the C++ internals of Yoga are in need of attention. 1. Some of the C++ internals are namespaced, but others not. 2. Some of the namespaces include `detail`, but are meant to be used outside of the translation unit (FB Clang Tidy rules warn on any usage of these) 2. Most of the files are in a flat hierarchy, except for event tracing in its own folder 3. Some files and functions begin with YG, others don’t 4. Some functions are uppercase, others are not 5. Almost all of the interesting logic is in Yoga.cpp, and the file is too large to reason about 6. There are multiple grab bag files where folks put random functions they need in (Utils, BitUtils, Yoga-Internal.h) 7. There is no clear indication from file structure or type naming what is private vs not 8. Handles like `YGNodeRef` and `YGConfigRef` can be used to access internals just by importing headers This stack does some much needed spring cleaning: 1. All non-public headers and C++ implementation details are in separate folders from the root level `yoga`. This will give us room to split up logic and add more files without too large a flat hierarchy 3. All private C++ internals are under the `facebook::yoga` namespace. Details namespaces are only ever used within the same header, as they are intended 4. Utils files are split 5. Most C++ internals drop the YG prefix 6. Most C++ internal function names are all lower camel case 7. We start to split up Yoga.cpp 8. Every header beginning with YG or at the top-level directory is public and C only, with the exception of Yoga-Internal.h which has non-public functions for bindings 9. It is not possible to use private APIs without static casting handles to internal classes This will give us more leeway to continue splitting monolithic files, and consistent guidelines for style in new files as well. These changes should not be breaking to any project using only public Yoga headers. This includes every usage of Yoga in fbsource except for RN Fabric which is currently tied to internals. This refactor should make that boundary clearer. Differential Revision: https://www.internalfb.com/diff/D48769241?entry_point=27 fbshipit-source-id: 7126c9ba5e27d93de0a8c14d31554a768ae2fc91 --- java/jni/YGJNIVanilla.cpp | 2 + yoga/Yoga-internal.h | 120 ---------------------- yoga/Yoga.cpp | 178 +++++++++++++++------------------ yoga/algorithm/FlexDirection.h | 38 +++++++ yoga/algorithm/ResolveValue.h | 2 + yoga/config/Config.h | 2 - yoga/debug/NodeToString.cpp | 1 - yoga/node/CachedMeasurement.h | 50 +++++++++ yoga/node/LayoutResults.cpp | 5 +- yoga/node/LayoutResults.h | 13 ++- yoga/node/Node.cpp | 72 +++++++------ yoga/node/Node.h | 4 +- yoga/numeric/Comparison.h | 23 +++-- yoga/numeric/FloatOptional.h | 1 - yoga/style/Style.h | 9 +- 15 files changed, 251 insertions(+), 269 deletions(-) create mode 100644 yoga/node/CachedMeasurement.h diff --git a/java/jni/YGJNIVanilla.cpp b/java/jni/YGJNIVanilla.cpp index b1cdc2dacf..5a712b0fa6 100644 --- a/java/jni/YGJNIVanilla.cpp +++ b/java/jni/YGJNIVanilla.cpp @@ -15,6 +15,8 @@ #include #include "YogaJniException.h" +#include + // TODO: Reconcile missing layoutContext functionality from callbacks in the C // API and use that #include diff --git a/yoga/Yoga-internal.h b/yoga/Yoga-internal.h index 3403282446..b10cf5d246 100644 --- a/yoga/Yoga-internal.h +++ b/yoga/Yoga-internal.h @@ -8,14 +8,11 @@ #pragma once #include -#include #include #include #include -#include - YG_EXTERN_C_BEGIN void YGNodeCalculateLayoutWithContext( @@ -30,120 +27,3 @@ void YGNodeCalculateLayoutWithContext( void YGNodeDeallocate(YGNodeRef node); YG_EXTERN_C_END - -namespace facebook::yoga { - -inline bool isUndefined(float value) { - return std::isnan(value); -} - -inline bool isUndefined(double value) { - return std::isnan(value); -} - -} // namespace facebook::yoga - -extern const std::array trailing; -extern const std::array leading; -extern const YGValue YGValueUndefined; -extern const YGValue YGValueAuto; -extern const YGValue YGValueZero; - -struct YGCachedMeasurement { - float availableWidth; - float availableHeight; - YGMeasureMode widthMeasureMode; - YGMeasureMode heightMeasureMode; - - float computedWidth; - float computedHeight; - - YGCachedMeasurement() - : availableWidth(-1), - availableHeight(-1), - widthMeasureMode(YGMeasureModeUndefined), - heightMeasureMode(YGMeasureModeUndefined), - computedWidth(-1), - computedHeight(-1) {} - - bool operator==(YGCachedMeasurement measurement) const { - using namespace facebook; - - bool isEqual = widthMeasureMode == measurement.widthMeasureMode && - heightMeasureMode == measurement.heightMeasureMode; - - if (!yoga::isUndefined(availableWidth) || - !yoga::isUndefined(measurement.availableWidth)) { - isEqual = isEqual && availableWidth == measurement.availableWidth; - } - if (!yoga::isUndefined(availableHeight) || - !yoga::isUndefined(measurement.availableHeight)) { - isEqual = isEqual && availableHeight == measurement.availableHeight; - } - if (!yoga::isUndefined(computedWidth) || - !yoga::isUndefined(measurement.computedWidth)) { - isEqual = isEqual && computedWidth == measurement.computedWidth; - } - if (!yoga::isUndefined(computedHeight) || - !yoga::isUndefined(measurement.computedHeight)) { - isEqual = isEqual && computedHeight == measurement.computedHeight; - } - - return isEqual; - } -}; - -// This value was chosen based on empirical data: -// 98% of analyzed layouts require less than 8 entries. -#define YG_MAX_CACHED_RESULT_COUNT 8 - -namespace facebook::yoga::detail { - -template -class Values { -private: - std::array values_; - -public: - Values() = default; - Values(const Values& other) = default; - - explicit Values(const YGValue& defaultValue) noexcept { - values_.fill(defaultValue); - } - - const CompactValue& operator[](size_t i) const noexcept { return values_[i]; } - CompactValue& operator[](size_t i) noexcept { return values_[i]; } - - template - YGValue get() const noexcept { - return std::get(values_); - } - - template - void set(YGValue& value) noexcept { - std::get(values_) = value; - } - - template - void set(YGValue&& value) noexcept { - set(value); - } - - bool operator==(const Values& other) const noexcept { - for (size_t i = 0; i < Size; ++i) { - if (values_[i] != other.values_[i]) { - return false; - } - } - return true; - } - - Values& operator=(const Values& other) = default; -}; - -} // namespace facebook::yoga::detail - -static const float kDefaultFlexGrow = 0.0f; -static const float kDefaultFlexShrink = 0.0f; -static const float kWebDefaultFlexShrink = 1.0f; diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp index dd65a264e4..38415f9ba9 100644 --- a/yoga/Yoga.cpp +++ b/yoga/Yoga.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -102,12 +103,8 @@ static int YGDefaultLog( #undef YG_UNUSED #endif -static inline bool YGDoubleIsUndefined(const double value) { - return facebook::yoga::isUndefined(value); -} - YOGA_EXPORT bool YGFloatIsUndefined(const float value) { - return facebook::yoga::isUndefined(value); + return yoga::isUndefined(value); } YOGA_EXPORT void* YGNodeGetContext(YGNodeRef node) { @@ -483,15 +480,15 @@ YOGA_EXPORT void YGNodeCopyStyle( YOGA_EXPORT float YGNodeStyleGetFlexGrow(const YGNodeConstRef nodeRef) { auto node = static_cast(nodeRef); return node->getStyle().flexGrow().isUndefined() - ? kDefaultFlexGrow + ? Style::DefaultFlexGrow : node->getStyle().flexGrow().unwrap(); } YOGA_EXPORT float YGNodeStyleGetFlexShrink(const YGNodeConstRef nodeRef) { auto node = static_cast(nodeRef); return node->getStyle().flexShrink().isUndefined() - ? (node->getConfig()->useWebDefaults() ? kWebDefaultFlexShrink - : kDefaultFlexShrink) + ? (node->getConfig()->useWebDefaults() ? Style::WebDefaultFlexShrink + : Style::DefaultFlexShrink) : node->getStyle().flexShrink().unwrap(); } @@ -1013,11 +1010,6 @@ YOGA_EXPORT void YGNodePrint( } #endif -const std::array leading = { - {YGEdgeTop, YGEdgeBottom, YGEdgeLeft, YGEdgeRight}}; - -const std::array trailing = { - {YGEdgeBottom, YGEdgeTop, YGEdgeRight, YGEdgeLeft}}; static const std::array pos = {{ YGEdgeTop, YGEdgeBottom, @@ -1063,7 +1055,7 @@ static float YGBaseline(yoga::Node* node, void* layoutContext) { YGAssertWithNode( node, - !YGFloatIsUndefined(baseline), + !yoga::isUndefined(baseline), "Expect custom baseline function to not return NaN"); return baseline; } @@ -1130,8 +1122,7 @@ static inline bool YGNodeIsStyleDimDefined( const yoga::Node* const node, const YGFlexDirection axis, const float ownerSize) { - bool isUndefined = - YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value); + bool isUndefined = yoga::isUndefined(node->getResolvedDimension(dim[axis]).value); return !( node->getResolvedDimension(dim[axis]).unit == YGUnitAuto || node->getResolvedDimension(dim[axis]).unit == YGUnitUndefined || @@ -1140,14 +1131,14 @@ static inline bool YGNodeIsStyleDimDefined( (node->getResolvedDimension(dim[axis]).unit == YGUnitPercent && !isUndefined && (node->getResolvedDimension(dim[axis]).value < 0.0f || - YGFloatIsUndefined(ownerSize)))); + yoga::isUndefined(ownerSize)))); } static inline bool YGNodeIsLayoutDimDefined( const yoga::Node* const node, const YGFlexDirection axis) { const float value = node->getLayout().measuredDimensions[dim[axis]]; - return !YGFloatIsUndefined(value) && value >= 0.0f; + return !yoga::isUndefined(value) && value >= 0.0f; } static FloatOptional YGNodeBoundAxisWithinMinAndMax( @@ -1203,7 +1194,7 @@ static void YGNodeSetChildTrailingPosition( child->setLayoutPosition( node->getLayout().measuredDimensions[dim[axis]] - size - child->getLayout().position[pos[axis]], - trailing[axis]); + trailingEdge(axis)); } static void YGConstrainMaxSizeForMode( @@ -1266,7 +1257,7 @@ static void YGNodeComputeFlexBasisForChild( const bool isColumnStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight); - if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) { + if (!resolvedFlexBasis.isUndefined() && !yoga::isUndefined(mainAxisSize)) { if (child->getLayout().computedFlexBasis.isUndefined() || (child->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureWebFlexBasis) && @@ -1328,7 +1319,7 @@ static void YGNodeComputeFlexBasisForChild( // major browsers appear to implement the following logic. if ((!isMainAxisRow && node->getStyle().overflow() == YGOverflowScroll) || node->getStyle().overflow() != YGOverflowScroll) { - if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) { + if (yoga::isUndefined(childWidth) && !yoga::isUndefined(width)) { childWidth = width; childWidthMeasureMode = YGMeasureModeAtMost; } @@ -1336,7 +1327,7 @@ static void YGNodeComputeFlexBasisForChild( if ((isMainAxisRow && node->getStyle().overflow() == YGOverflowScroll) || node->getStyle().overflow() != YGOverflowScroll) { - if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) { + if (yoga::isUndefined(childHeight) && !yoga::isUndefined(height)) { childHeight = height; childHeightMeasureMode = YGMeasureModeAtMost; } @@ -1360,7 +1351,7 @@ static void YGNodeComputeFlexBasisForChild( // the cross axis to be measured exactly with the available inner width const bool hasExactWidth = - !YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly; + !yoga::isUndefined(width) && widthMode == YGMeasureModeExactly; const bool childWidthStretch = YGNodeAlignItem(node, child) == YGAlignStretch && childWidthMeasureMode != YGMeasureModeExactly; @@ -1376,7 +1367,7 @@ static void YGNodeComputeFlexBasisForChild( } const bool hasExactHeight = - !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly; + !yoga::isUndefined(height) && heightMode == YGMeasureModeExactly; const bool childHeightStretch = YGNodeAlignItem(node, child) == YGAlignStretch && childHeightMeasureMode != YGMeasureModeExactly; @@ -1504,12 +1495,12 @@ static void YGNodeAbsoluteLayoutChild( // ratio calculation. One dimension being the anchor and the other being // flexible. const auto& childStyle = child->getStyle(); - if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) { + if (yoga::isUndefined(childWidth) ^ yoga::isUndefined(childHeight)) { if (!childStyle.aspectRatio().isUndefined()) { - if (YGFloatIsUndefined(childWidth)) { + if (yoga::isUndefined(childWidth)) { childWidth = marginRow + (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); - } else if (YGFloatIsUndefined(childHeight)) { + } else if (yoga::isUndefined(childHeight)) { childHeight = marginColumn + (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); } @@ -1517,20 +1508,18 @@ static void YGNodeAbsoluteLayoutChild( } // If we're still missing one or the other dimension, measure the content. - if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) { - childWidthMeasureMode = YGFloatIsUndefined(childWidth) - ? YGMeasureModeUndefined - : YGMeasureModeExactly; - childHeightMeasureMode = YGFloatIsUndefined(childHeight) - ? YGMeasureModeUndefined - : YGMeasureModeExactly; + if (yoga::isUndefined(childWidth) || yoga::isUndefined(childHeight)) { + childWidthMeasureMode = + yoga::isUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly; + childHeightMeasureMode = + yoga::isUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly; // If the size of the owner 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 owner. This is the same behavior as many browsers // implement. - if (!isMainAxisRow && YGFloatIsUndefined(childWidth) && - widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) && + if (!isMainAxisRow && yoga::isUndefined(childWidth) && + widthMode != YGMeasureModeUndefined && !yoga::isUndefined(width) && width > 0) { childWidth = width; childWidthMeasureMode = YGMeasureModeAtMost; @@ -1585,7 +1574,7 @@ static void YGNodeAbsoluteLayoutChild( .unwrap() - child->getTrailingPosition(mainAxis, isMainAxisRow ? width : height) .unwrap(), - leading[mainAxis]); + leadingEdge(mainAxis)); } else if ( !child->isLeadingPositionDefined(mainAxis) && node->getStyle().justifyContent() == YGJustifyCenter) { @@ -1593,14 +1582,14 @@ static void YGNodeAbsoluteLayoutChild( (node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]]) / 2.0f, - leading[mainAxis]); + leadingEdge(mainAxis)); } else if ( !child->isLeadingPositionDefined(mainAxis) && node->getStyle().justifyContent() == YGJustifyFlexEnd) { child->setLayoutPosition( (node->getLayout().measuredDimensions[dim[mainAxis]] - child->getLayout().measuredDimensions[dim[mainAxis]]), - leading[mainAxis]); + leadingEdge(mainAxis)); } else if ( node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && @@ -1615,7 +1604,7 @@ static void YGNodeAbsoluteLayoutChild( mainAxis, node->getLayout().measuredDimensions[dim[mainAxis]]) .unwrap(), - leading[mainAxis]); + leadingEdge(mainAxis)); } if (child->isTrailingPosDefined(crossAxis) && @@ -1629,7 +1618,7 @@ static void YGNodeAbsoluteLayoutChild( child ->getTrailingPosition(crossAxis, isMainAxisRow ? height : width) .unwrap(), - leading[crossAxis]); + leadingEdge(crossAxis)); } else if ( !child->isLeadingPositionDefined(crossAxis) && @@ -1638,7 +1627,7 @@ static void YGNodeAbsoluteLayoutChild( (node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().measuredDimensions[dim[crossAxis]]) / 2.0f, - leading[crossAxis]); + leadingEdge(crossAxis)); } else if ( !child->isLeadingPositionDefined(crossAxis) && ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^ @@ -1646,7 +1635,7 @@ static void YGNodeAbsoluteLayoutChild( child->setLayoutPosition( (node->getLayout().measuredDimensions[dim[crossAxis]] - child->getLayout().measuredDimensions[dim[crossAxis]]), - leading[crossAxis]); + leadingEdge(crossAxis)); } else if ( node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && @@ -1662,7 +1651,7 @@ static void YGNodeAbsoluteLayoutChild( crossAxis, node->getLayout().measuredDimensions[dim[crossAxis]]) .unwrap(), - leading[crossAxis]); + leadingEdge(crossAxis)); } } @@ -1697,10 +1686,10 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions( padding[YGEdgeBottom] + border[YGEdgeTop] + border[YGEdgeBottom]; // We want to make sure we don't call measure with negative size - const float innerWidth = YGFloatIsUndefined(availableWidth) + const float innerWidth = yoga::isUndefined(availableWidth) ? availableWidth : yoga::maxOrDefined(0, availableWidth - paddingAndBorderAxisRow); - const float innerHeight = YGFloatIsUndefined(availableHeight) + const float innerHeight = yoga::isUndefined(availableHeight) ? availableHeight : yoga::maxOrDefined(0, availableHeight - paddingAndBorderAxisColumn); @@ -1814,9 +1803,9 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( const YGMeasureMode heightMeasureMode, const float ownerWidth, const float ownerHeight) { - if ((!YGFloatIsUndefined(availableWidth) && - widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) || - (!YGFloatIsUndefined(availableHeight) && + if ((!yoga::isUndefined(availableWidth) && widthMeasureMode == YGMeasureModeAtMost && + availableWidth <= 0.0f) || + (!yoga::isUndefined(availableHeight) && heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) || (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) { @@ -1824,7 +1813,7 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( YGNodeBoundAxis( node, YGFlexDirectionRow, - YGFloatIsUndefined(availableWidth) || + yoga::isUndefined(availableWidth) || (widthMeasureMode == YGMeasureModeAtMost && availableWidth < 0.0f) ? 0.0f @@ -1837,7 +1826,7 @@ static bool YGNodeFixedSizeSetMeasuredDimensions( YGNodeBoundAxis( node, YGFlexDirectionColumn, - YGFloatIsUndefined(availableHeight) || + yoga::isUndefined(availableHeight) || (heightMeasureMode == YGMeasureModeAtMost && availableHeight < 0.0f) ? 0.0f @@ -1872,7 +1861,7 @@ static float YGNodeCalculateAvailableInnerDim( float availableInnerDim = availableDim - paddingAndBorder; // Max dimension overrides predefined dimension value; Min dimension in turn // overrides both of the above - if (!YGFloatIsUndefined(availableInnerDim)) { + if (!yoga::isUndefined(availableInnerDim)) { // We want to make sure our available height does not violate min and max // constraints const FloatOptional minDimensionOptional = yoga::resolveValue( @@ -2114,7 +2103,7 @@ static float YGDistributeFreeSpaceSecondPass( .unwrap(); float updatedMainSize = childFlexBasis; - if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && + if (!yoga::isUndefined(collectedFlexItemsValues.remainingFreeSpace) && collectedFlexItemsValues.remainingFreeSpace < 0) { flexShrinkScaledFactor = -currentRelativeChild->resolveFlexShrink() * childFlexBasis; @@ -2122,7 +2111,7 @@ static float YGDistributeFreeSpaceSecondPass( if (flexShrinkScaledFactor != 0) { float childSize; - if (!YGFloatIsUndefined( + if (!yoga::isUndefined( collectedFlexItemsValues.totalFlexShrinkScaledFactors) && collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) { childSize = childFlexBasis + flexShrinkScaledFactor; @@ -2141,12 +2130,12 @@ static float YGDistributeFreeSpaceSecondPass( availableInnerWidth); } } else if ( - !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && + !yoga::isUndefined(collectedFlexItemsValues.remainingFreeSpace) && collectedFlexItemsValues.remainingFreeSpace > 0) { flexGrowFactor = currentRelativeChild->resolveFlexGrow(); // Is this child able to grow? - if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) { + if (!yoga::isUndefined(flexGrowFactor) && flexGrowFactor != 0) { updatedMainSize = YGNodeBoundAxis( currentRelativeChild, mainAxis, @@ -2182,7 +2171,7 @@ static float YGDistributeFreeSpaceSecondPass( childCrossSize += marginCross; } else if ( - !YGFloatIsUndefined(availableInnerCrossDim) && + !yoga::isUndefined(availableInnerCrossDim) && !YGNodeIsStyleDimDefined( currentRelativeChild, crossAxis, availableInnerCrossDim) && measureModeCrossDim == YGMeasureModeExactly && @@ -2197,7 +2186,7 @@ static float YGDistributeFreeSpaceSecondPass( } else if (!YGNodeIsStyleDimDefined( currentRelativeChild, crossAxis, availableInnerCrossDim)) { childCrossSize = availableInnerCrossDim; - childCrossMeasureMode = YGFloatIsUndefined(childCrossSize) + childCrossMeasureMode = yoga::isUndefined(childCrossSize) ? YGMeasureModeUndefined : YGMeasureModeAtMost; } else { @@ -2212,7 +2201,7 @@ static float YGDistributeFreeSpaceSecondPass( YGUnitPercent && measureModeCrossDim != YGMeasureModeExactly; childCrossMeasureMode = - YGFloatIsUndefined(childCrossSize) || isLoosePercentageMeasurement + yoga::isUndefined(childCrossSize) || isLoosePercentageMeasurement ? YGMeasureModeUndefined : YGMeasureModeExactly; } @@ -2304,8 +2293,7 @@ static void YGDistributeFreeSpaceFirstPass( -currentRelativeChild->resolveFlexShrink() * childFlexBasis; // Is this child able to shrink? - if (!YGFloatIsUndefined(flexShrinkScaledFactor) && - flexShrinkScaledFactor != 0) { + if (!yoga::isUndefined(flexShrinkScaledFactor) && flexShrinkScaledFactor != 0) { baseMainSize = childFlexBasis + collectedFlexItemsValues.remainingFreeSpace / collectedFlexItemsValues.totalFlexShrinkScaledFactors * @@ -2316,8 +2304,7 @@ static void YGDistributeFreeSpaceFirstPass( baseMainSize, availableInnerMainDim, availableInnerWidth); - if (!YGFloatIsUndefined(baseMainSize) && - !YGFloatIsUndefined(boundMainSize) && + if (!yoga::isUndefined(baseMainSize) && !yoga::isUndefined(boundMainSize) && baseMainSize != boundMainSize) { // By excluding this item's size and flex factor from remaining, this // item's min/max constraints should also trigger in the second pass @@ -2330,12 +2317,12 @@ static void YGDistributeFreeSpaceFirstPass( } } } else if ( - !YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) && + !yoga::isUndefined(collectedFlexItemsValues.remainingFreeSpace) && collectedFlexItemsValues.remainingFreeSpace > 0) { flexGrowFactor = currentRelativeChild->resolveFlexGrow(); // Is this child able to grow? - if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) { + if (!yoga::isUndefined(flexGrowFactor) && flexGrowFactor != 0) { baseMainSize = childFlexBasis + collectedFlexItemsValues.remainingFreeSpace / collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor; @@ -2346,8 +2333,7 @@ static void YGDistributeFreeSpaceFirstPass( availableInnerMainDim, availableInnerWidth); - if (!YGFloatIsUndefined(baseMainSize) && - !YGFloatIsUndefined(boundMainSize) && + if (!yoga::isUndefined(baseMainSize) && !yoga::isUndefined(boundMainSize) && baseMainSize != boundMainSize) { // By excluding this item's size and flex factor from remaining, this // item's min/max constraints should also trigger in the second pass @@ -2741,16 +2727,14 @@ static void YGNodelayoutImpl( const LayoutPassReason reason) { YGAssertWithNode( node, - YGFloatIsUndefined(availableWidth) - ? widthMeasureMode == YGMeasureModeUndefined - : true, + yoga::isUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined + : true, "availableWidth is indefinite so widthMeasureMode must be " "YGMeasureModeUndefined"); YGAssertWithNode( node, - YGFloatIsUndefined(availableHeight) - ? heightMeasureMode == YGMeasureModeUndefined - : true, + yoga::isUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined + : true, "availableHeight is indefinite so heightMeasureMode must be " "YGMeasureModeUndefined"); @@ -3001,12 +2985,12 @@ static void YGNodelayoutImpl( const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight; - if (!YGFloatIsUndefined(minInnerMainDim) && + if (!yoga::isUndefined(minInnerMainDim) && collectedFlexItemsValues.sizeConsumedOnCurrentLine < minInnerMainDim) { availableInnerMainDim = minInnerMainDim; } else if ( - !YGFloatIsUndefined(maxInnerMainDim) && + !yoga::isUndefined(maxInnerMainDim) && collectedFlexItemsValues.sizeConsumedOnCurrentLine > maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; @@ -3015,10 +2999,9 @@ static void YGNodelayoutImpl( node->hasErrata(YGErrataStretchFlexBasis); if (!useLegacyStretchBehaviour && - ((!YGFloatIsUndefined( - collectedFlexItemsValues.totalFlexGrowFactors) && + ((!yoga::isUndefined(collectedFlexItemsValues.totalFlexGrowFactors) && collectedFlexItemsValues.totalFlexGrowFactors == 0) || - (!YGFloatIsUndefined(node->resolveFlexGrow()) && + (!yoga::isUndefined(node->resolveFlexGrow()) && node->resolveFlexGrow() == 0))) { // If we don't have any children to flex or we can't flex the node // itself, space we've used is all space we need. Root node also @@ -3031,7 +3014,7 @@ static void YGNodelayoutImpl( } } - if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) { + if (!sizeBasedOnContent && !yoga::isUndefined(availableInnerMainDim)) { collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim - collectedFlexItemsValues.sizeConsumedOnCurrentLine; } else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) { @@ -3146,7 +3129,7 @@ static void YGNodelayoutImpl( // If leading position is not defined or calculations result in Nan, // default to border + margin if (!isChildLeadingPosDefined || - YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) { + yoga::isUndefined(child->getLayout().position[pos[crossAxis]])) { child->setLayoutPosition( node->getLeadingBorder(crossAxis) + child->getLeadingMargin(crossAxis, availableInnerWidth) @@ -3212,12 +3195,12 @@ static void YGNodelayoutImpl( auto crossAxisDoesNotGrow = alignContent != YGAlignStretch && isNodeFlexWrap; const YGMeasureMode childWidthMeasureMode = - YGFloatIsUndefined(childWidth) || + yoga::isUndefined(childWidth) || (!isMainAxisRow && crossAxisDoesNotGrow) ? YGMeasureModeUndefined : YGMeasureModeExactly; const YGMeasureMode childHeightMeasureMode = - YGFloatIsUndefined(childHeight) || + yoga::isUndefined(childHeight) || (isMainAxisRow && crossAxisDoesNotGrow) ? YGMeasureModeUndefined : YGMeasureModeExactly; @@ -3281,7 +3264,7 @@ static void YGNodelayoutImpl( if (performLayout && (isNodeFlexWrap || YGIsBaselineLayout(node))) { float crossDimLead = 0; float currentLead = leadingPaddingAndBorderCross; - if (!YGFloatIsUndefined(availableInnerCrossDim)) { + if (!yoga::isUndefined(availableInnerCrossDim)) { const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim; switch (node->getStyle().alignContent()) { @@ -3684,9 +3667,8 @@ static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid( float lastSize, float lastComputedSize) { return lastSizeMode == YGMeasureModeAtMost && - sizeMode == YGMeasureModeAtMost && !YGFloatIsUndefined(lastSize) && - !YGFloatIsUndefined(size) && !YGFloatIsUndefined(lastComputedSize) && - lastSize > size && + sizeMode == YGMeasureModeAtMost && !yoga::isUndefined(lastSize) && + !yoga::isUndefined(size) && !yoga::isUndefined(lastComputedSize) && lastSize > size && (lastComputedSize <= size || yoga::inexactEquals(size, lastComputedSize)); } @@ -3730,13 +3712,12 @@ YOGA_EXPORT float YGRoundValueToPixelGrid( } else { // Finally we just round the value scaledValue = scaledValue - fractial + - (!YGDoubleIsUndefined(fractial) && + (!yoga::isUndefined(fractial) && (fractial > 0.5 || yoga::inexactEquals(fractial, 0.5)) ? 1.0 : 0.0); } - return (YGDoubleIsUndefined(scaledValue) || - YGDoubleIsUndefined(pointScaleFactor)) + return (yoga::isUndefined(scaledValue) || yoga::isUndefined(pointScaleFactor)) ? YGUndefined : (float) (scaledValue / pointScaleFactor); } @@ -3755,8 +3736,8 @@ YOGA_EXPORT bool YGNodeCanUseCachedMeasurement( const float marginRow, const float marginColumn, const YGConfigRef config) { - if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) || - (!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) { + if ((!yoga::isUndefined(lastComputedHeight) && lastComputedHeight < 0) || + (!yoga::isUndefined(lastComputedWidth) && lastComputedWidth < 0)) { return false; } bool useRoundedComparison = @@ -3858,7 +3839,7 @@ bool YGLayoutNodeInternal( layout->cachedLayout.computedHeight = -1; } - YGCachedMeasurement* cachedResults = nullptr; + CachedMeasurement* cachedResults = nullptr; // Determine whether the results are already cached. We maintain a separate // cache for layouts and measurements. A layout operation modifies the @@ -4036,7 +4017,8 @@ bool YGLayoutNodeInternal( layoutMarkerData.maxMeasureCache = layout->nextCachedMeasurementsIndex + 1; } - if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) { + if (layout->nextCachedMeasurementsIndex == + LayoutResults::MaxCachedMeasurements) { if (gPrintChanges) { yoga::log( node, YGLogLevelVerbose, nullptr, "Out of cache entries!\n"); @@ -4044,7 +4026,7 @@ bool YGLayoutNodeInternal( layout->nextCachedMeasurementsIndex = 0; } - YGCachedMeasurement* newCacheEntry; + CachedMeasurement* newCacheEntry; if (performLayout) { // Use the single layout cache entry. newCacheEntry = &layout->cachedLayout; @@ -4218,8 +4200,8 @@ YOGA_EXPORT void YGNodeCalculateLayoutWithContext( widthMeasureMode = YGMeasureModeAtMost; } else { width = ownerWidth; - widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined - : YGMeasureModeExactly; + widthMeasureMode = + yoga::isUndefined(width) ? YGMeasureModeUndefined : YGMeasureModeExactly; } float height = YGUndefined; @@ -4238,8 +4220,8 @@ YOGA_EXPORT void YGNodeCalculateLayoutWithContext( heightMeasureMode = YGMeasureModeAtMost; } else { height = ownerHeight; - heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined - : YGMeasureModeExactly; + heightMeasureMode = + yoga::isUndefined(height) ? YGMeasureModeUndefined : YGMeasureModeExactly; } if (YGLayoutNodeInternal( node, diff --git a/yoga/algorithm/FlexDirection.h b/yoga/algorithm/FlexDirection.h index ed17ce2bc9..9cb87462aa 100644 --- a/yoga/algorithm/FlexDirection.h +++ b/yoga/algorithm/FlexDirection.h @@ -43,4 +43,42 @@ inline YGFlexDirection resolveCrossDirection( : YGFlexDirectionColumn; } +inline YGEdge leadingEdge(const YGFlexDirection flexDirection) { + switch (flexDirection) { + case YGFlexDirectionColumn: + return YGEdgeTop; + case YGFlexDirectionColumnReverse: + return YGEdgeBottom; + case YGFlexDirectionRow: + return YGEdgeLeft; + case YGFlexDirectionRowReverse: + return YGEdgeRight; + } + + YGAssert(false, "Invalid YGFlexDirection"); + + // Avoid "not all control paths return a value" warning until next diff adds + // assert with [[noreturn]] + return YGEdgeTop; +} + +inline YGEdge trailingEdge(const YGFlexDirection flexDirection) { + switch (flexDirection) { + case YGFlexDirectionColumn: + return YGEdgeBottom; + case YGFlexDirectionColumnReverse: + return YGEdgeTop; + case YGFlexDirectionRow: + return YGEdgeRight; + case YGFlexDirectionRowReverse: + return YGEdgeLeft; + } + + YGAssert(false, "Invalid YGFlexDirection"); + + // Avoid "not all control paths return a value" warning until next diff adds + // assert with [[noreturn]] + return YGEdgeTop; +} + } // namespace facebook::yoga diff --git a/yoga/algorithm/ResolveValue.h b/yoga/algorithm/ResolveValue.h index 2ba4bfef5b..af04025d4c 100644 --- a/yoga/algorithm/ResolveValue.h +++ b/yoga/algorithm/ResolveValue.h @@ -8,7 +8,9 @@ #pragma once #include + #include +#include namespace facebook::yoga { diff --git a/yoga/config/Config.h b/yoga/config/Config.h index d0894b86be..ebf3f77f79 100644 --- a/yoga/config/Config.h +++ b/yoga/config/Config.h @@ -8,9 +8,7 @@ #pragma once #include - #include -#include // Tag struct used to form the opaque YGConfigRef for the public C API struct YGConfig {}; diff --git a/yoga/debug/NodeToString.cpp b/yoga/debug/NodeToString.cpp index 1b6d01d380..756f480098 100644 --- a/yoga/debug/NodeToString.cpp +++ b/yoga/debug/NodeToString.cpp @@ -13,7 +13,6 @@ #include #include -#include namespace facebook::yoga { diff --git a/yoga/node/CachedMeasurement.h b/yoga/node/CachedMeasurement.h new file mode 100644 index 0000000000..7542f0e519 --- /dev/null +++ b/yoga/node/CachedMeasurement.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) Meta Platforms, Inc. and 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 +#include + +namespace facebook::yoga { + +struct CachedMeasurement { + float availableWidth{-1}; + float availableHeight{-1}; + YGMeasureMode widthMeasureMode{YGMeasureModeUndefined}; + YGMeasureMode heightMeasureMode{YGMeasureModeUndefined}; + + float computedWidth{-1}; + float computedHeight{-1}; + + bool operator==(CachedMeasurement measurement) const { + bool isEqual = widthMeasureMode == measurement.widthMeasureMode && + heightMeasureMode == measurement.heightMeasureMode; + + if (!yoga::isUndefined(availableWidth) || + !yoga::isUndefined(measurement.availableWidth)) { + isEqual = isEqual && availableWidth == measurement.availableWidth; + } + if (!yoga::isUndefined(availableHeight) || + !yoga::isUndefined(measurement.availableHeight)) { + isEqual = isEqual && availableHeight == measurement.availableHeight; + } + if (!yoga::isUndefined(computedWidth) || !yoga::isUndefined(measurement.computedWidth)) { + isEqual = isEqual && computedWidth == measurement.computedWidth; + } + if (!yoga::isUndefined(computedHeight) || + !yoga::isUndefined(measurement.computedHeight)) { + isEqual = isEqual && computedHeight == measurement.computedHeight; + } + + return isEqual; + } +}; + +} // namespace facebook::yoga diff --git a/yoga/node/LayoutResults.cpp b/yoga/node/LayoutResults.cpp index 6446b8cbc9..fb8b8527c5 100644 --- a/yoga/node/LayoutResults.cpp +++ b/yoga/node/LayoutResults.cpp @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +#include + #include #include @@ -23,7 +25,8 @@ bool LayoutResults::operator==(LayoutResults layout) const { cachedLayout == layout.cachedLayout && computedFlexBasis == layout.computedFlexBasis; - for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) { + for (uint32_t i = 0; i < LayoutResults::MaxCachedMeasurements && isEqual; + ++i) { isEqual = isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i]; } diff --git a/yoga/node/LayoutResults.h b/yoga/node/LayoutResults.h index c0d2bee26d..95b4a21bf8 100644 --- a/yoga/node/LayoutResults.h +++ b/yoga/node/LayoutResults.h @@ -7,13 +7,19 @@ #pragma once +#include + #include #include -#include +#include namespace facebook::yoga { struct LayoutResults { + // This value was chosen based on empirical data: + // 98% of analyzed layouts require less than 8 entries. + static constexpr int32_t MaxCachedMeasurements = 8; + std::array position = {}; std::array dimensions = {{YGUndefined, YGUndefined}}; std::array margin = {}; @@ -36,11 +42,10 @@ struct LayoutResults { YGDirection lastOwnerDirection = YGDirectionInherit; uint32_t nextCachedMeasurementsIndex = 0; - std::array - cachedMeasurements = {}; + std::array cachedMeasurements = {}; std::array measuredDimensions = {{YGUndefined, YGUndefined}}; - YGCachedMeasurement cachedLayout = YGCachedMeasurement(); + CachedMeasurement cachedLayout{}; YGDirection direction() const { return getEnumData(flags, directionOffset); diff --git a/yoga/node/Node.cpp b/yoga/node/Node.cpp index 82132f54cb..0eca4e115e 100644 --- a/yoga/node/Node.cpp +++ b/yoga/node/Node.cpp @@ -117,10 +117,10 @@ FloatOptional Node::getLeadingPosition( ? computeEdgeValueForRow( style_.position(), YGEdgeStart, - leading[axis], + leadingEdge(axis), CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.position(), leading[axis], CompactValue::ofZero()); + style_.position(), leadingEdge(axis), CompactValue::ofZero()); return yoga::resolveValue(leadingPosition, axisSize); } @@ -131,10 +131,10 @@ FloatOptional Node::getTrailingPosition( ? computeEdgeValueForRow( style_.position(), YGEdgeEnd, - trailing[axis], + trailingEdge(axis), CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.position(), trailing[axis], CompactValue::ofZero()); + style_.position(), trailingEdge(axis), CompactValue::ofZero()); return yoga::resolveValue(trailingPosition, axisSize); } @@ -143,10 +143,10 @@ bool Node::isLeadingPositionDefined(const YGFlexDirection axis) const { ? computeEdgeValueForRow( style_.position(), YGEdgeStart, - leading[axis], + leadingEdge(axis), CompactValue::ofUndefined()) : computeEdgeValueForColumn( - style_.position(), leading[axis], CompactValue::ofUndefined()); + style_.position(), leadingEdge(axis), CompactValue::ofUndefined()); return !leadingPosition.isUndefined(); } @@ -155,10 +155,10 @@ bool Node::isTrailingPosDefined(const YGFlexDirection axis) const { ? computeEdgeValueForRow( style_.position(), YGEdgeEnd, - trailing[axis], + trailingEdge(axis), CompactValue::ofUndefined()) : computeEdgeValueForColumn( - style_.position(), trailing[axis], CompactValue::ofUndefined()); + style_.position(), trailingEdge(axis), CompactValue::ofUndefined()); return !trailingPosition.isUndefined(); } @@ -167,9 +167,12 @@ FloatOptional Node::getLeadingMargin( const float widthSize) const { auto leadingMargin = isRow(axis) ? computeEdgeValueForRow( - style_.margin(), YGEdgeStart, leading[axis], CompactValue::ofZero()) + style_.margin(), + YGEdgeStart, + leadingEdge(axis), + CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.margin(), leading[axis], CompactValue::ofZero()); + style_.margin(), leadingEdge(axis), CompactValue::ofZero()); return leadingMargin.isAuto() ? FloatOptional{0} : yoga::resolveValue(leadingMargin, widthSize); } @@ -179,9 +182,12 @@ FloatOptional Node::getTrailingMargin( const float widthSize) const { auto trailingMargin = isRow(axis) ? computeEdgeValueForRow( - style_.margin(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) + style_.margin(), + YGEdgeEnd, + trailingEdge(axis), + CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.margin(), trailing[axis], CompactValue::ofZero()); + style_.margin(), trailingEdge(axis), CompactValue::ofZero()); return trailingMargin.isAuto() ? FloatOptional{0} : yoga::resolveValue(trailingMargin, widthSize); @@ -390,25 +396,25 @@ void Node::setPosition( setLayoutPosition( (getLeadingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), - leading[mainAxis]); + leadingEdge(mainAxis)); setLayoutPosition( (getTrailingMargin(mainAxis, ownerWidth) + relativePositionMain).unwrap(), - trailing[mainAxis]); + trailingEdge(mainAxis)); setLayoutPosition( (getLeadingMargin(crossAxis, ownerWidth) + relativePositionCross) .unwrap(), - leading[crossAxis]); + leadingEdge(crossAxis)); setLayoutPosition( (getTrailingMargin(crossAxis, ownerWidth) + relativePositionCross) .unwrap(), - trailing[crossAxis]); + trailingEdge(crossAxis)); } YGValue Node::marginLeadingValue(const YGFlexDirection axis) const { if (isRow(axis) && !style_.margin()[YGEdgeStart].isUndefined()) { return style_.margin()[YGEdgeStart]; } else { - return style_.margin()[leading[axis]]; + return style_.margin()[leadingEdge(axis)]; } } @@ -416,7 +422,7 @@ YGValue Node::marginTrailingValue(const YGFlexDirection axis) const { if (isRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) { return style_.margin()[YGEdgeEnd]; } else { - return style_.margin()[trailing[axis]]; + return style_.margin()[trailingEdge(axis)]; } } @@ -493,7 +499,7 @@ float Node::resolveFlexGrow() const { if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { return style_.flex().unwrap(); } - return kDefaultFlexGrow; + return Style::DefaultFlexGrow; } float Node::resolveFlexShrink() const { @@ -507,7 +513,8 @@ float Node::resolveFlexShrink() const { style_.flex().unwrap() < 0.0f) { return -style_.flex().unwrap(); } - return config_->useWebDefaults() ? kWebDefaultFlexShrink : kDefaultFlexShrink; + return config_->useWebDefaults() ? Style::WebDefaultFlexShrink + : Style::DefaultFlexShrink; } bool Node::isNodeFlexible() { @@ -519,18 +526,24 @@ bool Node::isNodeFlexible() { float Node::getLeadingBorder(const YGFlexDirection axis) const { YGValue leadingBorder = isRow(axis) ? computeEdgeValueForRow( - style_.border(), YGEdgeStart, leading[axis], CompactValue::ofZero()) + style_.border(), + YGEdgeStart, + leadingEdge(axis), + CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.border(), leading[axis], CompactValue::ofZero()); + style_.border(), leadingEdge(axis), CompactValue::ofZero()); return fmaxf(leadingBorder.value, 0.0f); } float Node::getTrailingBorder(const YGFlexDirection axis) const { YGValue trailingBorder = isRow(axis) ? computeEdgeValueForRow( - style_.border(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) + style_.border(), + YGEdgeEnd, + trailingEdge(axis), + CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.border(), trailing[axis], CompactValue::ofZero()); + style_.border(), trailingEdge(axis), CompactValue::ofZero()); return fmaxf(trailingBorder.value, 0.0f); } @@ -541,10 +554,10 @@ FloatOptional Node::getLeadingPadding( ? computeEdgeValueForRow( style_.padding(), YGEdgeStart, - leading[axis], + leadingEdge(axis), CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.padding(), leading[axis], CompactValue::ofZero()); + style_.padding(), leadingEdge(axis), CompactValue::ofZero()); return yoga::maxOrDefined( yoga::resolveValue(leadingPadding, widthSize), FloatOptional(0.0f)); } @@ -554,9 +567,12 @@ FloatOptional Node::getTrailingPadding( const float widthSize) const { auto trailingPadding = isRow(axis) ? computeEdgeValueForRow( - style_.padding(), YGEdgeEnd, trailing[axis], CompactValue::ofZero()) + style_.padding(), + YGEdgeEnd, + trailingEdge(axis), + CompactValue::ofZero()) : computeEdgeValueForColumn( - style_.padding(), trailing[axis], CompactValue::ofZero()); + style_.padding(), trailingEdge(axis), CompactValue::ofZero()); return yoga::maxOrDefined( yoga::resolveValue(trailingPadding, widthSize), FloatOptional(0.0f)); } diff --git a/yoga/node/Node.h b/yoga/node/Node.h index 542d7c08ea..5401d90b6b 100644 --- a/yoga/node/Node.h +++ b/yoga/node/Node.h @@ -9,10 +9,10 @@ #include #include +#include + #include #include -#include - #include #include diff --git a/yoga/numeric/Comparison.h b/yoga/numeric/Comparison.h index 86ed16fa50..aa9f933efd 100644 --- a/yoga/numeric/Comparison.h +++ b/yoga/numeric/Comparison.h @@ -15,19 +15,24 @@ namespace facebook::yoga { +template +inline bool isUndefined(FloatT value) { + return std::isnan(value); +} + inline float maxOrDefined(const float a, const float b) { - if (!std::isnan(a) && !std::isnan(b)) { + if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { return fmaxf(a, b); } - return std::isnan(a) ? b : a; + return yoga::isUndefined(a) ? b : a; } inline float minOrDefined(const float a, const float b) { - if (!std::isnan(a) && !std::isnan(b)) { + if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { return fminf(a, b); } - return std::isnan(a) ? b : a; + return yoga::isUndefined(a) ? b : a; } inline FloatOptional maxOrDefined(FloatOptional op1, FloatOptional op2) { @@ -43,17 +48,17 @@ inline FloatOptional maxOrDefined(FloatOptional op1, FloatOptional op2) { // Custom equality functions using a hardcoded epsilon of 0.0001f, or returning // true if both floats are NaN. inline bool inexactEquals(const float a, const float b) { - if (!std::isnan(a) && !std::isnan(b)) { + if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { return fabs(a - b) < 0.0001f; } - return std::isnan(a) && std::isnan(b); + return yoga::isUndefined(a) && yoga::isUndefined(b); } inline bool inexactEquals(const double a, const double b) { - if (!std::isnan(a) && !std::isnan(b)) { + if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) { return fabs(a - b) < 0.0001; } - return std::isnan(a) && std::isnan(b); + return yoga::isUndefined(a) && yoga::isUndefined(b); } inline bool inexactEquals(const YGValue& a, const YGValue& b) { @@ -62,7 +67,7 @@ inline bool inexactEquals(const YGValue& a, const YGValue& b) { } if (a.unit == YGUnitUndefined || - (std::isnan(a.value) && std::isnan(b.value))) { + (yoga::isUndefined(a.value) && yoga::isUndefined(b.value))) { return true; } diff --git a/yoga/numeric/FloatOptional.h b/yoga/numeric/FloatOptional.h index 89eff3b882..a36befe609 100644 --- a/yoga/numeric/FloatOptional.h +++ b/yoga/numeric/FloatOptional.h @@ -9,7 +9,6 @@ #include #include -#include namespace facebook::yoga { diff --git a/yoga/style/Style.h b/yoga/style/Style.h index 10854fd6fb..7b3ca9dd2d 100644 --- a/yoga/style/Style.h +++ b/yoga/style/Style.h @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -23,13 +22,17 @@ namespace facebook::yoga { class YOGA_EXPORT Style { template - using Values = detail::Values()>; + using Values = std::array()>; public: using Dimensions = Values; using Edges = Values; using Gutters = Values; + static constexpr float DefaultFlexGrow = 0.0f; + static constexpr float DefaultFlexShrink = 0.0f; + static constexpr float WebDefaultFlexShrink = 1.0f; + template struct BitfieldRef { Style& style; @@ -112,7 +115,7 @@ class YOGA_EXPORT Style { Edges padding_ = {}; Edges border_ = {}; Gutters gap_ = {}; - Dimensions dimensions_{CompactValue::ofAuto()}; + Dimensions dimensions_{CompactValue::ofAuto(), CompactValue::ofAuto()}; Dimensions minDimensions_ = {}; Dimensions maxDimensions_ = {}; // Yoga specific properties, not compatible with flexbox specification