diff --git a/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h b/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h index b17751ad3319d2..c8247e1390cf4f 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h +++ b/packages/react-native/ReactCommon/yoga/yoga/BitUtils.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include "YGEnums.h" @@ -16,6 +17,10 @@ namespace yoga { namespace detail { +// std::bitset with one bit for each option defined in YG_ENUM_SEQ_DECL +template +using EnumBitset = std::bitset()>; + constexpr size_t log2ceilFn(size_t n) { return n < 1 ? 0 : (1 + log2ceilFn(n / 2)); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp index 915da52af77ac0..3c24ee4775f609 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.cpp @@ -7,9 +7,75 @@ #include "YGConfig.h" +using namespace facebook::yoga::detail; + YGConfig::YGConfig(YGLogger logger) : cloneNodeCallback_{nullptr} { + setLogger(logger); +} + +void YGConfig::setUseWebDefaults(bool useWebDefaults) { + flags_.useWebDefaults = useWebDefaults; +} + +bool YGConfig::useWebDefaults() const { + return flags_.useWebDefaults; +} + +void YGConfig::setShouldPrintTree(bool printTree) { + flags_.printTree = printTree; +} + +bool YGConfig::shouldPrintTree() const { + return flags_.printTree; +} + +void YGConfig::setExperimentalFeatureEnabled( + YGExperimentalFeature feature, + bool enabled) { + experimentalFeatures_.set(feature, enabled); +} + +bool YGConfig::isExperimentalFeatureEnabled( + YGExperimentalFeature feature) const { + return experimentalFeatures_.test(feature); +} + +void YGConfig::setErrata(YGErrata errata) { + errata_ = errata; +} + +YGErrata YGConfig::getErrata() const { + return errata_; +} + +void YGConfig::setPointScaleFactor(float pointScaleFactor) { + pointScaleFactor_ = pointScaleFactor; +} + +float YGConfig::getPointScaleFactor() const { + return pointScaleFactor_; +} + +void YGConfig::setContext(void* context) { + context_ = context; +} + +void* YGConfig::getContext() const { + return context_; +} + +void YGConfig::setLogger(YGLogger logger) { logger_.noContext = logger; - loggerUsesContext_ = false; + flags_.loggerUsesContext = false; +} + +void YGConfig::setLogger(LogWithContextFn logger) { + logger_.withContext = logger; + flags_.loggerUsesContext = true; +} + +void YGConfig::setLogger(std::nullptr_t) { + setLogger(YGLogger{nullptr}); } void YGConfig::log( @@ -18,22 +84,36 @@ void YGConfig::log( YGLogLevel logLevel, void* logContext, const char* format, - va_list args) { - if (loggerUsesContext_) { + va_list args) const { + if (flags_.loggerUsesContext) { logger_.withContext(config, node, logLevel, logContext, format, args); } else { logger_.noContext(config, node, logLevel, format, args); } } +void YGConfig::setCloneNodeCallback(YGCloneNodeFunc cloneNode) { + cloneNodeCallback_.noContext = cloneNode; + flags_.cloneNodeUsesContext = false; +} + +void YGConfig::setCloneNodeCallback(CloneWithContextFn cloneNode) { + cloneNodeCallback_.withContext = cloneNode; + flags_.cloneNodeUsesContext = true; +} + +void YGConfig::setCloneNodeCallback(std::nullptr_t) { + setCloneNodeCallback(YGCloneNodeFunc{nullptr}); +} + YGNodeRef YGConfig::cloneNode( YGNodeRef node, YGNodeRef owner, int childIndex, - void* cloneContext) { + void* cloneContext) const { YGNodeRef clone = nullptr; if (cloneNodeCallback_.noContext != nullptr) { - clone = cloneNodeUsesContext_ + clone = flags_.cloneNodeUsesContext ? cloneNodeCallback_.withContext(node, owner, childIndex, cloneContext) : cloneNodeCallback_.noContext(node, owner, childIndex); } diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h index 77ce16fb2e3422..4d4038de9f6e4d 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h +++ b/packages/react-native/ReactCommon/yoga/yoga/YGConfig.h @@ -9,69 +9,91 @@ #include "Yoga-internal.h" #include "Yoga.h" +#include "BitUtils.h" + +namespace facebook { +namespace yoga { +namespace detail { + +using LogWithContextFn = int (*)( + YGConfigRef config, + YGNodeRef node, + YGLogLevel level, + void* context, + const char* format, + va_list args); +using CloneWithContextFn = YGNodeRef (*)( + YGNodeRef node, + YGNodeRef owner, + int childIndex, + void* cloneContext); + +#pragma pack(push) +#pragma pack(1) +struct YGConfigFlags { + bool useWebDefaults : 1; + bool printTree : 1; + bool cloneNodeUsesContext : 1; + bool loggerUsesContext : 1; +}; +#pragma pack(pop) + +} // namespace detail +} // namespace yoga +} // namespace facebook struct YOGA_EXPORT YGConfig { - using LogWithContextFn = int (*)( - YGConfigRef config, - YGNodeRef node, - YGLogLevel level, - void* context, - const char* format, - va_list args); - using CloneWithContextFn = YGNodeRef (*)( + YGConfig(YGLogger logger); + + void setUseWebDefaults(bool useWebDefaults); + bool useWebDefaults() const; + + void setShouldPrintTree(bool printTree); + bool shouldPrintTree() const; + + void setExperimentalFeatureEnabled( + YGExperimentalFeature feature, + bool enabled); + bool isExperimentalFeatureEnabled(YGExperimentalFeature feature) const; + + void setErrata(YGErrata errata); + YGErrata getErrata() const; + + void setPointScaleFactor(float pointScaleFactor); + float getPointScaleFactor() const; + + void setContext(void* context); + void* getContext() const; + + void setLogger(YGLogger logger); + void setLogger(facebook::yoga::detail::LogWithContextFn logger); + void setLogger(std::nullptr_t); + void log(YGConfig*, YGNode*, YGLogLevel, void*, const char*, va_list) const; + + void setCloneNodeCallback(YGCloneNodeFunc cloneNode); + void setCloneNodeCallback( + facebook::yoga::detail::CloneWithContextFn cloneNode); + void setCloneNodeCallback(std::nullptr_t); + YGNodeRef cloneNode( YGNodeRef node, YGNodeRef owner, int childIndex, - void* cloneContext); + void* cloneContext) const; private: union { - CloneWithContextFn withContext; + facebook::yoga::detail::CloneWithContextFn withContext; YGCloneNodeFunc noContext; } cloneNodeCallback_; union { - LogWithContextFn withContext; + facebook::yoga::detail::LogWithContextFn withContext; YGLogger noContext; } logger_; - bool cloneNodeUsesContext_; - bool loggerUsesContext_; - -public: - bool useWebDefaults = false; - bool useLegacyStretchBehaviour = false; - bool shouldDiffLayoutWithoutLegacyStretchBehaviour = false; - bool printTree = false; - float pointScaleFactor = 1.0f; - std::array()> - experimentalFeatures = {}; - void* context = nullptr; - YGConfig(YGLogger logger); - void log(YGConfig*, YGNode*, YGLogLevel, void*, const char*, va_list); - void setLogger(YGLogger logger) { - logger_.noContext = logger; - loggerUsesContext_ = false; - } - void setLogger(LogWithContextFn logger) { - logger_.withContext = logger; - loggerUsesContext_ = true; - } - void setLogger(std::nullptr_t) { setLogger(YGLogger{nullptr}); } - - YGNodeRef cloneNode( - YGNodeRef node, - YGNodeRef owner, - int childIndex, - void* cloneContext); - void setCloneNodeCallback(YGCloneNodeFunc cloneNode) { - cloneNodeCallback_.noContext = cloneNode; - cloneNodeUsesContext_ = false; - } - void setCloneNodeCallback(CloneWithContextFn cloneNode) { - cloneNodeCallback_.withContext = cloneNode; - cloneNodeUsesContext_ = true; - } - void setCloneNodeCallback(std::nullptr_t) { - setCloneNodeCallback(YGCloneNodeFunc{nullptr}); - } + facebook::yoga::detail::YGConfigFlags flags_{}; + facebook::yoga::detail::EnumBitset + experimentalFeatures_{}; + YGErrata errata_ = YGErrataNone; + float pointScaleFactor_ = 1.0f; + void* context_ = nullptr; }; diff --git a/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp b/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp index 9045037b87381d..d2b3d5c7174edd 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/YGNode.cpp @@ -18,7 +18,7 @@ YGNode::YGNode(const YGConfigRef config) : config_{config} { config != nullptr, "Attempting to construct YGNode with null config"); flags_.hasNewLayout = true; - if (config->useWebDefaults) { + if (config->useWebDefaults()) { useWebDefaults(); } }; @@ -267,7 +267,7 @@ void YGNode::setConfig(YGConfigRef config) { YGAssert(config != nullptr, "Attempting to set a null config on a YGNode"); YGAssertWithConfig( config, - config->useWebDefaults == config_->useWebDefaults, + config->useWebDefaults() == config_->useWebDefaults(), "UseWebDefaults may not be changed after constructing a YGNode"); config_ = config; } @@ -419,7 +419,7 @@ YGValue YGNode::resolveFlexBasisPtr() const { return flexBasis; } if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { - return config_->useWebDefaults ? YGValueAuto : YGValueZero; + return config_->useWebDefaults() ? YGValueAuto : YGValueZero; } return YGValueAuto; } @@ -495,11 +495,11 @@ float YGNode::resolveFlexShrink() const { if (!style_.flexShrink().isUndefined()) { return style_.flexShrink().unwrap(); } - if (!config_->useWebDefaults && !style_.flex().isUndefined() && + if (!config_->useWebDefaults() && !style_.flex().isUndefined() && style_.flex().unwrap() < 0.0f) { return -style_.flex().unwrap(); } - return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink; + return config_->useWebDefaults() ? kWebDefaultFlexShrink : kDefaultFlexShrink; } bool YGNode::isNodeFlexible() { diff --git a/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp b/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp index ddacd6036c8514..6201efb0252ea9 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/Yoga.cpp @@ -169,7 +169,7 @@ YOGA_EXPORT bool YGNodeGetHasNewLayout(YGNodeRef node) { } YOGA_EXPORT void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) { - config->printTree = enabled; + config->setShouldPrintTree(enabled); } YOGA_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) { @@ -464,8 +464,8 @@ YOGA_EXPORT float YGNodeStyleGetFlexGrow(const YGNodeConstRef node) { YOGA_EXPORT float YGNodeStyleGetFlexShrink(const YGNodeConstRef node) { return node->getStyle().flexShrink().isUndefined() - ? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink - : kDefaultFlexShrink) + ? (node->getConfig()->useWebDefaults() ? kWebDefaultFlexShrink + : kDefaultFlexShrink) : node->getStyle().flexShrink().unwrap(); } @@ -1240,8 +1240,8 @@ static void YGNodeComputeFlexBasisForChild( if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) { if (child->getLayout().computedFlexBasis.isUndefined() || - (YGConfigIsExperimentalFeatureEnabled( - child->getConfig(), YGExperimentalFeatureWebFlexBasis) && + (child->getConfig()->isExperimentalFeatureEnabled( + YGExperimentalFeatureWebFlexBasis) && child->getLayout().computedFlexBasisGeneration != generationCount)) { const YGFloatOptional paddingAndBorder = YGFloatOptional( YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth)); @@ -1548,8 +1548,7 @@ static void YGNodeAbsoluteLayoutChild( generationCount); auto trailingMarginOuterSize = - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), + node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureFixAbsoluteTrailingColumnMargin) ? isMainAxisRow ? height : width : width; @@ -1581,8 +1580,7 @@ static void YGNodeAbsoluteLayoutChild( child->getLayout().measuredDimensions[dim[mainAxis]]), leading[mainAxis]); } else if ( - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), + node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && child->isLeadingPositionDefined(mainAxis)) { child->setLayoutPosition( @@ -1628,8 +1626,7 @@ static void YGNodeAbsoluteLayoutChild( child->getLayout().measuredDimensions[dim[crossAxis]]), leading[crossAxis]); } else if ( - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), + node->getConfig()->isExperimentalFeatureEnabled( YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) && child->isLeadingPositionDefined(crossAxis)) { child->setLayoutPosition( @@ -2990,7 +2987,10 @@ static void YGNodelayoutImpl( maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; } else { - if (!node->getConfig()->useLegacyStretchBehaviour && + bool useLegacyStretchBehaviour = + node->getConfig()->getErrata() & YGErrataStretchFlexBasis; + + if (!useLegacyStretchBehaviour && ((!YGFloatIsUndefined( collectedFlexItemsValues.totalFlexGrowFactors) && collectedFlexItemsValues.totalFlexGrowFactors == 0) || @@ -3003,7 +3003,7 @@ static void YGNodelayoutImpl( collectedFlexItemsValues.sizeConsumedOnCurrentLine; } - sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour; + sizeBasedOnContent = !useLegacyStretchBehaviour; } } @@ -3557,18 +3557,18 @@ static void YGNodelayoutImpl( child->getStyle().positionType() != YGPositionTypeAbsolute) { continue; } + const bool absolutePercentageAgainstPaddingEdge = + node->getConfig()->isExperimentalFeatureEnabled( + YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge); + YGNodeAbsoluteLayoutChild( node, child, - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) + absolutePercentageAgainstPaddingEdge ? node->getLayout().measuredDimensions[YGDimensionWidth] : availableInnerWidth, isMainAxisRow ? measureModeMainDim : measureModeCrossDim, - YGConfigIsExperimentalFeatureEnabled( - node->getConfig(), - YGExperimentalFeatureAbsolutePercentageAgainstPaddingEdge) + absolutePercentageAgainstPaddingEdge ? node->getLayout().measuredDimensions[YGDimensionHeight] : availableInnerHeight, direction, @@ -3735,20 +3735,22 @@ YOGA_EXPORT bool YGNodeCanUseCachedMeasurement( return false; } bool useRoundedComparison = - config != nullptr && config->pointScaleFactor != 0; + config != nullptr && config->getPointScaleFactor() != 0; const float effectiveWidth = useRoundedComparison - ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false) + ? YGRoundValueToPixelGrid( + width, config->getPointScaleFactor(), false, false) : width; const float effectiveHeight = useRoundedComparison - ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false) + ? YGRoundValueToPixelGrid( + height, config->getPointScaleFactor(), false, false) : height; const float effectiveLastWidth = useRoundedComparison ? YGRoundValueToPixelGrid( - lastWidth, config->pointScaleFactor, false, false) + lastWidth, config->getPointScaleFactor(), false, false) : lastWidth; const float effectiveLastHeight = useRoundedComparison ? YGRoundValueToPixelGrid( - lastHeight, config->pointScaleFactor, false, false) + lastHeight, config->getPointScaleFactor(), false, false) : lastHeight; const bool hasSameWidthSpec = lastWidthMode == widthMode && @@ -4075,9 +4077,9 @@ YOGA_EXPORT void YGConfigSetPointScaleFactor( // We store points for Pixel as we will use it for rounding if (pixelsInPoint == 0.0f) { // Zero is used to skip rounding - config->pointScaleFactor = 0.0f; + config->setPointScaleFactor(0.0f); } else { - config->pointScaleFactor = pixelsInPoint; + config->setPointScaleFactor(pixelsInPoint); } } @@ -4227,10 +4229,11 @@ YOGA_EXPORT void YGNodeCalculateLayoutWithContext( gCurrentGenerationCount.load(std::memory_order_relaxed))) { node->setPosition( node->getLayout().direction(), ownerWidth, ownerHeight, ownerWidth); - YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f); + YGRoundToPixelGrid( + node, node->getConfig()->getPointScaleFactor(), 0.0f, 0.0f); #ifdef DEBUG - if (node->getConfig()->printTree) { + if (node->getConfig()->shouldPrintTree()) { YGNodePrint( node, (YGPrintOptions) (YGPrintOptionsLayout | YGPrintOptionsChildren | YGPrintOptionsStyle)); @@ -4293,42 +4296,54 @@ YOGA_EXPORT void YGConfigSetExperimentalFeatureEnabled( const YGConfigRef config, const YGExperimentalFeature feature, const bool enabled) { - config->experimentalFeatures[feature] = enabled; + config->setExperimentalFeatureEnabled(feature, enabled); } YOGA_EXPORT bool YGConfigIsExperimentalFeatureEnabled( const YGConfigRef config, const YGExperimentalFeature feature) { - return config->experimentalFeatures[feature]; + return config->isExperimentalFeatureEnabled(feature); } YOGA_EXPORT void YGConfigSetUseWebDefaults( const YGConfigRef config, const bool enabled) { - config->useWebDefaults = enabled; + config->setUseWebDefaults(enabled); } YOGA_EXPORT bool YGConfigGetUseLegacyStretchBehaviour( const YGConfigRef config) { - return config->useLegacyStretchBehaviour; + return config->getErrata() & YGErrataStretchFlexBasis; } YOGA_EXPORT void YGConfigSetUseLegacyStretchBehaviour( const YGConfigRef config, const bool useLegacyStretchBehaviour) { - config->useLegacyStretchBehaviour = useLegacyStretchBehaviour; + if (useLegacyStretchBehaviour) { + config->setErrata(config->getErrata() | YGErrataStretchFlexBasis); + } else { + config->setErrata(config->getErrata() & ~YGErrataStretchFlexBasis); + } } bool YGConfigGetUseWebDefaults(const YGConfigRef config) { - return config->useWebDefaults; + return config->useWebDefaults(); } YOGA_EXPORT void YGConfigSetContext(const YGConfigRef config, void* context) { - config->context = context; + config->setContext(context); } YOGA_EXPORT void* YGConfigGetContext(const YGConfigRef config) { - return config->context; + return config->getContext(); +} + +YOGA_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata) { + config->setErrata(errata); +} + +YOGA_EXPORT YGErrata YGConfigGetErrata(YGConfigRef config) { + return config->getErrata(); } YOGA_EXPORT void YGConfigSetCloneNodeFunc( diff --git a/packages/react-native/ReactCommon/yoga/yoga/Yoga.h b/packages/react-native/ReactCommon/yoga/yoga/Yoga.h index 3eee36928f0651..69901dda9d21ed 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/Yoga.h +++ b/packages/react-native/ReactCommon/yoga/yoga/Yoga.h @@ -357,6 +357,9 @@ WIN_EXPORT YGConfigRef YGConfigGetDefault(void); WIN_EXPORT void YGConfigSetContext(YGConfigRef config, void* context); WIN_EXPORT void* YGConfigGetContext(YGConfigRef config); +WIN_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata); +WIN_EXPORT YGErrata YGConfigGetErrata(YGConfigRef config); + WIN_EXPORT float YGRoundValueToPixelGrid( double value, double pointScaleFactor,