diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.cpp new file mode 100644 index 00000000000000..2f03a82265febf --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.cpp @@ -0,0 +1,353 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include + +namespace facebook::yoga { + +/* + * Absolutely positioned nodes do not participate in flex layout and thus their + * positions can be determined independently from the rest of their siblings. + * For each axis there are essentially two cases: + * + * 1) The node has insets defined. In this case we can just use these to + * determine the position of the node. + * 2) The node does not have insets defined. In this case we look at the style + * of the parent to position the node. Things like justify content and + * align content will move absolute children around. If none of these + * special properties are defined, the child is positioned at the start + * (defined by flex direction) of the leading flex line. + * + * This function does that positioning for the given axis. The spec has more + * information on this topic: https://www.w3.org/TR/css-flexbox-1/#abspos-items + */ +static void positionAbsoluteChild( + const yoga::Node* const containingNode, + const yoga::Node* const parent, + yoga::Node* child, + const Direction direction, + const FlexDirection axis, + const bool isMainAxis, + const float containingBlockWidth, + const float containingBlockHeight) { + const bool isAxisRow = isRow(axis); + const bool shouldCenter = isMainAxis + ? parent->getStyle().justifyContent() == Justify::Center + : resolveChildAlignment(parent, child) == Align::Center; + const bool shouldFlexEnd = isMainAxis + ? parent->getStyle().justifyContent() == Justify::FlexEnd + : ((resolveChildAlignment(parent, child) == Align::FlexEnd) ^ + (parent->getStyle().flexWrap() == Wrap::WrapReverse)); + + if (child->isFlexEndPositionDefined(axis, direction) && + !child->isFlexStartPositionDefined(axis, direction)) { + child->setLayoutPosition( + containingNode->getLayout().measuredDimension(dimension(axis)) - + child->getLayout().measuredDimension(dimension(axis)) - + containingNode->getFlexEndBorder(axis, direction) - + child->getFlexEndMargin( + axis, + direction, + isAxisRow ? containingBlockWidth : containingBlockHeight) - + child->getFlexEndPosition( + axis, + direction, + isAxisRow ? containingBlockWidth : containingBlockHeight), + flexStartEdge(axis)); + } else if ( + !child->isFlexStartPositionDefined(axis, direction) && shouldCenter) { + child->setLayoutPosition( + (parent->getLayout().measuredDimension(dimension(axis)) - + child->getLayout().measuredDimension(dimension(axis))) / + 2.0f, + flexStartEdge(axis)); + } else if ( + !child->isFlexStartPositionDefined(axis, direction) && shouldFlexEnd) { + child->setLayoutPosition( + (parent->getLayout().measuredDimension(dimension(axis)) - + child->getLayout().measuredDimension(dimension(axis))), + flexStartEdge(axis)); + } else if ( + parent->getConfig()->isExperimentalFeatureEnabled( + ExperimentalFeature::AbsolutePercentageAgainstPaddingEdge) && + child->isFlexStartPositionDefined(axis, direction)) { + child->setLayoutPosition( + child->getFlexStartPosition( + axis, + direction, + containingNode->getLayout().measuredDimension(dimension(axis))) + + containingNode->getFlexStartBorder(axis, direction) + + child->getFlexStartMargin( + axis, + direction, + isAxisRow ? containingBlockWidth : containingBlockHeight), + flexStartEdge(axis)); + } +} + +void layoutAbsoluteChild( + const yoga::Node* const containingNode, + const yoga::Node* const node, + yoga::Node* const child, + const float containingBlockWidth, + const float containingBlockHeight, + const SizingMode widthMode, + const Direction direction, + LayoutData& layoutMarkerData, + const uint32_t depth, + const uint32_t generationCount) { + const FlexDirection mainAxis = + resolveDirection(node->getStyle().flexDirection(), direction); + const FlexDirection crossAxis = resolveCrossDirection(mainAxis, direction); + const bool isMainAxisRow = isRow(mainAxis); + + float childWidth = YGUndefined; + float childHeight = YGUndefined; + SizingMode childWidthSizingMode = SizingMode::MaxContent; + SizingMode childHeightSizingMode = SizingMode::MaxContent; + + auto marginRow = + child->getMarginForAxis(FlexDirection::Row, containingBlockWidth); + auto marginColumn = + child->getMarginForAxis(FlexDirection::Column, containingBlockWidth); + + if (child->styleDefinesDimension(FlexDirection::Row, containingBlockWidth)) { + childWidth = + yoga::resolveValue( + child->getResolvedDimension(Dimension::Width), containingBlockWidth) + .unwrap() + + marginRow; + } else { + // If the child doesn't have a specified width, compute the width based on + // the left/right offsets if they're defined. + if (child->isFlexStartPositionDefined(FlexDirection::Row, direction) && + child->isFlexEndPositionDefined(FlexDirection::Row, direction)) { + childWidth = + containingNode->getLayout().measuredDimension(Dimension::Width) - + (containingNode->getFlexStartBorder(FlexDirection::Row, direction) + + containingNode->getFlexEndBorder(FlexDirection::Row, direction)) - + (child->getFlexStartPosition( + FlexDirection::Row, direction, containingBlockWidth) + + child->getFlexEndPosition( + FlexDirection::Row, direction, containingBlockWidth)); + childWidth = boundAxis( + child, + FlexDirection::Row, + childWidth, + containingBlockWidth, + containingBlockWidth); + } + } + + if (child->styleDefinesDimension( + FlexDirection::Column, containingBlockHeight)) { + childHeight = yoga::resolveValue( + child->getResolvedDimension(Dimension::Height), + containingBlockHeight) + .unwrap() + + marginColumn; + } else { + // If the child doesn't have a specified height, compute the height based on + // the top/bottom offsets if they're defined. + if (child->isFlexStartPositionDefined(FlexDirection::Column, direction) && + child->isFlexEndPositionDefined(FlexDirection::Column, direction)) { + childHeight = + containingNode->getLayout().measuredDimension(Dimension::Height) - + (containingNode->getFlexStartBorder( + FlexDirection::Column, direction) + + containingNode->getFlexEndBorder(FlexDirection::Column, direction)) - + (child->getFlexStartPosition( + FlexDirection::Column, direction, containingBlockHeight) + + child->getFlexEndPosition( + FlexDirection::Column, direction, containingBlockHeight)); + childHeight = boundAxis( + child, + FlexDirection::Column, + childHeight, + containingBlockHeight, + containingBlockWidth); + } + } + + // Exactly one dimension needs to be defined for us to be able to do aspect + // ratio calculation. One dimension being the anchor and the other being + // flexible. + const auto& childStyle = child->getStyle(); + if (yoga::isUndefined(childWidth) ^ yoga::isUndefined(childHeight)) { + if (childStyle.aspectRatio().isDefined()) { + if (yoga::isUndefined(childWidth)) { + childWidth = marginRow + + (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); + } else if (yoga::isUndefined(childHeight)) { + childHeight = marginColumn + + (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); + } + } + } + + // If we're still missing one or the other dimension, measure the content. + if (yoga::isUndefined(childWidth) || yoga::isUndefined(childHeight)) { + childWidthSizingMode = yoga::isUndefined(childWidth) + ? SizingMode::MaxContent + : SizingMode::StretchFit; + childHeightSizingMode = yoga::isUndefined(childHeight) + ? SizingMode::MaxContent + : SizingMode::StretchFit; + + // 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 && yoga::isUndefined(childWidth) && + widthMode != SizingMode::MaxContent && + yoga::isDefined(containingBlockWidth) && containingBlockWidth > 0) { + childWidth = containingBlockWidth; + childWidthSizingMode = SizingMode::FitContent; + } + + calculateLayoutInternal( + child, + childWidth, + childHeight, + direction, + childWidthSizingMode, + childHeightSizingMode, + childWidth, + childHeight, + false, + LayoutPassReason::kAbsMeasureChild, + layoutMarkerData, + depth, + generationCount); + childWidth = child->getLayout().measuredDimension(Dimension::Width) + + child->getMarginForAxis(FlexDirection::Row, containingBlockWidth); + childHeight = child->getLayout().measuredDimension(Dimension::Height) + + child->getMarginForAxis(FlexDirection::Column, containingBlockWidth); + } + + calculateLayoutInternal( + child, + childWidth, + childHeight, + direction, + SizingMode::StretchFit, + SizingMode::StretchFit, + childWidth, + childHeight, + true, + LayoutPassReason::kAbsLayout, + layoutMarkerData, + depth, + generationCount); + + positionAbsoluteChild( + containingNode, + node, + child, + direction, + mainAxis, + true /*isMainAxis*/, + containingBlockWidth, + containingBlockHeight); + positionAbsoluteChild( + containingNode, + node, + child, + direction, + crossAxis, + false /*isMainAxis*/, + containingBlockWidth, + containingBlockHeight); +} + +void layoutAbsoluteDescendants( + yoga::Node* containingNode, + yoga::Node* currentNode, + SizingMode widthSizingMode, + Direction currentNodeDirection, + LayoutData& layoutMarkerData, + uint32_t currentDepth, + uint32_t generationCount, + float currentNodeMainOffsetFromContainingBlock, + float currentNodeCrossOffsetFromContainingBlock) { + const FlexDirection mainAxis = resolveDirection( + currentNode->getStyle().flexDirection(), currentNodeDirection); + const FlexDirection crossAxis = + resolveCrossDirection(mainAxis, currentNodeDirection); + for (auto child : currentNode->getChildren()) { + if (child->getStyle().display() == Display::None) { + continue; + } else if (child->getStyle().positionType() == PositionType::Absolute) { + layoutAbsoluteChild( + containingNode, + currentNode, + child, + containingNode->getLayout().measuredDimension(Dimension::Width), + containingNode->getLayout().measuredDimension(Dimension::Height), + widthSizingMode, + currentNodeDirection, + layoutMarkerData, + currentDepth, + generationCount); + + const bool isMainAxisRow = isRow(mainAxis); + const bool mainInsetsDefined = isMainAxisRow + ? child->getStyle().horizontalInsetsDefined() + : child->getStyle().verticalInsetsDefined(); + const bool crossInsetsDefined = isMainAxisRow + ? child->getStyle().verticalInsetsDefined() + : child->getStyle().horizontalInsetsDefined(); + + const float childMainOffsetFromParent = mainInsetsDefined + ? (child->getLayout().position(flexStartEdge(mainAxis)) - + currentNodeMainOffsetFromContainingBlock) + : child->getLayout().position(flexStartEdge(mainAxis)); + const float childCrossOffsetFromParent = crossInsetsDefined + ? (child->getLayout().position(flexStartEdge(crossAxis)) - + currentNodeCrossOffsetFromContainingBlock) + : child->getLayout().position(flexStartEdge(crossAxis)); + + child->setLayoutPosition( + childMainOffsetFromParent, flexStartEdge(mainAxis)); + child->setLayoutPosition( + childCrossOffsetFromParent, flexStartEdge(crossAxis)); + + if (needsTrailingPosition(mainAxis)) { + setChildTrailingPosition(currentNode, child, mainAxis); + } + if (needsTrailingPosition(crossAxis)) { + setChildTrailingPosition(currentNode, child, crossAxis); + } + } else if (child->getStyle().positionType() == PositionType::Static) { + const Direction childDirection = + child->resolveDirection(currentNodeDirection); + const float childMainOffsetFromContainingBlock = + currentNodeMainOffsetFromContainingBlock + + child->getLayout().position(flexStartEdge(mainAxis)); + const float childCrossOffsetFromContainingBlock = + currentNodeCrossOffsetFromContainingBlock + + child->getLayout().position(flexStartEdge(crossAxis)); + + layoutAbsoluteDescendants( + containingNode, + child, + widthSizingMode, + childDirection, + layoutMarkerData, + currentDepth + 1, + generationCount, + childMainOffsetFromContainingBlock, + childCrossOffsetFromContainingBlock); + } + } +} + +} // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.h new file mode 100644 index 00000000000000..8544fa5c567e59 --- /dev/null +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/AbsoluteLayout.h @@ -0,0 +1,38 @@ +/* + * 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 + +namespace facebook::yoga { + +void layoutAbsoluteChild( + const yoga::Node* const containingNode, + const yoga::Node* const node, + yoga::Node* const child, + const float containingBlockWidth, + const float containingBlockHeight, + const SizingMode widthMode, + const Direction direction, + LayoutData& layoutMarkerData, + const uint32_t depth, + const uint32_t generationCount); + +void layoutAbsoluteDescendants( + yoga::Node* containingNode, + yoga::Node* currentNode, + SizingMode widthSizingMode, + Direction currentNodeDirection, + LayoutData& layoutMarkerData, + uint32_t currentDepth, + uint32_t generationCount, + float currentNodeMainOffsetFromContainingBlock, + float currentNodeCrossOffsetFromContainingBlock); + +} // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp index 014cd0f776c236..25665dafc55195 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.cpp @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -50,54 +51,6 @@ bool calculateLayoutInternal( const uint32_t depth, const uint32_t generationCount); -static inline float dimensionWithMargin( - const yoga::Node* const node, - const FlexDirection axis, - const float widthSize) { - return node->getLayout().measuredDimension(dimension(axis)) + - node->getMarginForAxis(axis, widthSize); -} - -static inline bool styleDefinesDimension( - const yoga::Node* const node, - const FlexDirection axis, - const float ownerSize) { - bool isDefined = - yoga::isDefined(node->getResolvedDimension(dimension(axis)).value); - - auto resolvedDimension = node->getResolvedDimension(dimension(axis)); - return !( - resolvedDimension.unit == YGUnitAuto || - resolvedDimension.unit == YGUnitUndefined || - (resolvedDimension.unit == YGUnitPoint && isDefined && - resolvedDimension.value < 0.0f) || - (resolvedDimension.unit == YGUnitPercent && isDefined && - (resolvedDimension.value < 0.0f || yoga::isUndefined(ownerSize)))); -} - -static inline bool isLayoutDimensionDefined( - const yoga::Node* const node, - const FlexDirection axis) { - const float value = node->getLayout().measuredDimension(dimension(axis)); - return yoga::isDefined(value) && value >= 0.0f; -} - -static void setChildTrailingPosition( - const yoga::Node* const node, - yoga::Node* const child, - const FlexDirection axis) { - const float size = child->getLayout().measuredDimension(dimension(axis)); - child->setLayoutPosition( - node->getLayout().measuredDimension(dimension(axis)) - size - - child->getLayout().position(flexStartEdge(axis)), - flexEndEdge(axis)); -} - -static bool needsTrailingPosition(const FlexDirection axis) { - return axis == FlexDirection::RowReverse || - axis == FlexDirection::ColumnReverse; -} - static void constrainMaxSizeForMode( const yoga::Node* const node, const enum FlexDirection axis, @@ -152,9 +105,9 @@ static void computeFlexBasisForChild( const FloatOptional resolvedFlexBasis = yoga::resolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize); const bool isRowStyleDimDefined = - styleDefinesDimension(child, FlexDirection::Row, ownerWidth); + child->styleDefinesDimension(FlexDirection::Row, ownerWidth); const bool isColumnStyleDimDefined = - styleDefinesDimension(child, FlexDirection::Column, ownerHeight); + child->styleDefinesDimension(FlexDirection::Column, ownerHeight); if (resolvedFlexBasis.isDefined() && yoga::isDefined(mainAxisSize)) { if (child->getLayout().computedFlexBasis.isUndefined() || @@ -318,343 +271,6 @@ static void computeFlexBasisForChild( child->setLayoutComputedFlexBasisGeneration(generationCount); } -/* - * Absolutely positioned nodes do not participate in flex layout and thus their - * positions can be determined independently from the rest of their siblings. - * For each axis there are essentially two cases: - * - * 1) The node has insets defined. In this case we can just use these to - * determine the position of the node. - * 2) The node does not have insets defined. In this case we look at the style - * of the parent to position the node. Things like justify content and - * align content will move absolute children around. If none of these - * special properties are defined, the child is positioned at the start - * (defined by flex direction) of the leading flex line. - * - * This function does that positioning for the given axis. The spec has more - * information on this topic: https://www.w3.org/TR/css-flexbox-1/#abspos-items - */ -static void positionAbsoluteChild( - const yoga::Node* const containingNode, - const yoga::Node* const parent, - yoga::Node* child, - const Direction direction, - const FlexDirection axis, - const bool isMainAxis, - const float containingBlockWidth, - const float containingBlockHeight) { - const bool isAxisRow = isRow(axis); - const bool shouldCenter = isMainAxis - ? parent->getStyle().justifyContent() == Justify::Center - : resolveChildAlignment(parent, child) == Align::Center; - const bool shouldFlexEnd = isMainAxis - ? parent->getStyle().justifyContent() == Justify::FlexEnd - : ((resolveChildAlignment(parent, child) == Align::FlexEnd) ^ - (parent->getStyle().flexWrap() == Wrap::WrapReverse)); - - if (child->isFlexEndPositionDefined(axis, direction) && - !child->isFlexStartPositionDefined(axis, direction)) { - child->setLayoutPosition( - containingNode->getLayout().measuredDimension(dimension(axis)) - - child->getLayout().measuredDimension(dimension(axis)) - - containingNode->getFlexEndBorder(axis, direction) - - child->getFlexEndMargin( - axis, - direction, - isAxisRow ? containingBlockWidth : containingBlockHeight) - - child->getFlexEndPosition( - axis, - direction, - isAxisRow ? containingBlockWidth : containingBlockHeight), - flexStartEdge(axis)); - } else if ( - !child->isFlexStartPositionDefined(axis, direction) && shouldCenter) { - child->setLayoutPosition( - (parent->getLayout().measuredDimension(dimension(axis)) - - child->getLayout().measuredDimension(dimension(axis))) / - 2.0f, - flexStartEdge(axis)); - } else if ( - !child->isFlexStartPositionDefined(axis, direction) && shouldFlexEnd) { - child->setLayoutPosition( - (parent->getLayout().measuredDimension(dimension(axis)) - - child->getLayout().measuredDimension(dimension(axis))), - flexStartEdge(axis)); - } else if ( - parent->getConfig()->isExperimentalFeatureEnabled( - ExperimentalFeature::AbsolutePercentageAgainstPaddingEdge) && - child->isFlexStartPositionDefined(axis, direction)) { - child->setLayoutPosition( - child->getFlexStartPosition( - axis, - direction, - containingNode->getLayout().measuredDimension(dimension(axis))) + - containingNode->getFlexStartBorder(axis, direction) + - child->getFlexStartMargin( - axis, - direction, - isAxisRow ? containingBlockWidth : containingBlockHeight), - flexStartEdge(axis)); - } -} - -static void layoutAbsoluteChild( - const yoga::Node* const containingNode, - const yoga::Node* const node, - yoga::Node* const child, - const float containingBlockWidth, - const float containingBlockHeight, - const SizingMode widthMode, - const Direction direction, - LayoutData& layoutMarkerData, - const uint32_t depth, - const uint32_t generationCount) { - const FlexDirection mainAxis = - resolveDirection(node->getStyle().flexDirection(), direction); - const FlexDirection crossAxis = resolveCrossDirection(mainAxis, direction); - const bool isMainAxisRow = isRow(mainAxis); - - float childWidth = YGUndefined; - float childHeight = YGUndefined; - SizingMode childWidthSizingMode = SizingMode::MaxContent; - SizingMode childHeightSizingMode = SizingMode::MaxContent; - - auto marginRow = - child->getMarginForAxis(FlexDirection::Row, containingBlockWidth); - auto marginColumn = - child->getMarginForAxis(FlexDirection::Column, containingBlockWidth); - - if (styleDefinesDimension(child, FlexDirection::Row, containingBlockWidth)) { - childWidth = - yoga::resolveValue( - child->getResolvedDimension(Dimension::Width), containingBlockWidth) - .unwrap() + - marginRow; - } else { - // If the child doesn't have a specified width, compute the width based on - // the left/right offsets if they're defined. - if (child->isFlexStartPositionDefined(FlexDirection::Row, direction) && - child->isFlexEndPositionDefined(FlexDirection::Row, direction)) { - childWidth = - containingNode->getLayout().measuredDimension(Dimension::Width) - - (containingNode->getFlexStartBorder(FlexDirection::Row, direction) + - containingNode->getFlexEndBorder(FlexDirection::Row, direction)) - - (child->getFlexStartPosition( - FlexDirection::Row, direction, containingBlockWidth) + - child->getFlexEndPosition( - FlexDirection::Row, direction, containingBlockWidth)); - childWidth = boundAxis( - child, - FlexDirection::Row, - childWidth, - containingBlockWidth, - containingBlockWidth); - } - } - - if (styleDefinesDimension( - child, FlexDirection::Column, containingBlockHeight)) { - childHeight = yoga::resolveValue( - child->getResolvedDimension(Dimension::Height), - containingBlockHeight) - .unwrap() + - marginColumn; - } else { - // If the child doesn't have a specified height, compute the height based on - // the top/bottom offsets if they're defined. - if (child->isFlexStartPositionDefined(FlexDirection::Column, direction) && - child->isFlexEndPositionDefined(FlexDirection::Column, direction)) { - childHeight = - containingNode->getLayout().measuredDimension(Dimension::Height) - - (containingNode->getFlexStartBorder( - FlexDirection::Column, direction) + - containingNode->getFlexEndBorder(FlexDirection::Column, direction)) - - (child->getFlexStartPosition( - FlexDirection::Column, direction, containingBlockHeight) + - child->getFlexEndPosition( - FlexDirection::Column, direction, containingBlockHeight)); - childHeight = boundAxis( - child, - FlexDirection::Column, - childHeight, - containingBlockHeight, - containingBlockWidth); - } - } - - // Exactly one dimension needs to be defined for us to be able to do aspect - // ratio calculation. One dimension being the anchor and the other being - // flexible. - const auto& childStyle = child->getStyle(); - if (yoga::isUndefined(childWidth) ^ yoga::isUndefined(childHeight)) { - if (childStyle.aspectRatio().isDefined()) { - if (yoga::isUndefined(childWidth)) { - childWidth = marginRow + - (childHeight - marginColumn) * childStyle.aspectRatio().unwrap(); - } else if (yoga::isUndefined(childHeight)) { - childHeight = marginColumn + - (childWidth - marginRow) / childStyle.aspectRatio().unwrap(); - } - } - } - - // If we're still missing one or the other dimension, measure the content. - if (yoga::isUndefined(childWidth) || yoga::isUndefined(childHeight)) { - childWidthSizingMode = yoga::isUndefined(childWidth) - ? SizingMode::MaxContent - : SizingMode::StretchFit; - childHeightSizingMode = yoga::isUndefined(childHeight) - ? SizingMode::MaxContent - : SizingMode::StretchFit; - - // 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 && yoga::isUndefined(childWidth) && - widthMode != SizingMode::MaxContent && - yoga::isDefined(containingBlockWidth) && containingBlockWidth > 0) { - childWidth = containingBlockWidth; - childWidthSizingMode = SizingMode::FitContent; - } - - calculateLayoutInternal( - child, - childWidth, - childHeight, - direction, - childWidthSizingMode, - childHeightSizingMode, - childWidth, - childHeight, - false, - LayoutPassReason::kAbsMeasureChild, - layoutMarkerData, - depth, - generationCount); - childWidth = child->getLayout().measuredDimension(Dimension::Width) + - child->getMarginForAxis(FlexDirection::Row, containingBlockWidth); - childHeight = child->getLayout().measuredDimension(Dimension::Height) + - child->getMarginForAxis(FlexDirection::Column, containingBlockWidth); - } - - calculateLayoutInternal( - child, - childWidth, - childHeight, - direction, - SizingMode::StretchFit, - SizingMode::StretchFit, - childWidth, - childHeight, - true, - LayoutPassReason::kAbsLayout, - layoutMarkerData, - depth, - generationCount); - - positionAbsoluteChild( - containingNode, - node, - child, - direction, - mainAxis, - true /*isMainAxis*/, - containingBlockWidth, - containingBlockHeight); - positionAbsoluteChild( - containingNode, - node, - child, - direction, - crossAxis, - false /*isMainAxis*/, - containingBlockWidth, - containingBlockHeight); -} - -static void layoutAbsoluteDescendants( - yoga::Node* containingNode, - yoga::Node* currentNode, - SizingMode widthSizingMode, - Direction currentNodeDirection, - LayoutData& layoutMarkerData, - uint32_t currentDepth, - uint32_t generationCount, - float currentNodeMainOffsetFromContainingBlock, - float currentNodeCrossOffsetFromContainingBlock) { - const FlexDirection mainAxis = resolveDirection( - currentNode->getStyle().flexDirection(), currentNodeDirection); - const FlexDirection crossAxis = - resolveCrossDirection(mainAxis, currentNodeDirection); - for (auto child : currentNode->getChildren()) { - if (child->getStyle().display() == Display::None) { - continue; - } else if (child->getStyle().positionType() == PositionType::Absolute) { - layoutAbsoluteChild( - containingNode, - currentNode, - child, - containingNode->getLayout().measuredDimension(Dimension::Width), - containingNode->getLayout().measuredDimension(Dimension::Height), - widthSizingMode, - currentNodeDirection, - layoutMarkerData, - currentDepth, - generationCount); - - const bool isMainAxisRow = isRow(mainAxis); - const bool mainInsetsDefined = isMainAxisRow - ? child->getStyle().horizontalInsetsDefined() - : child->getStyle().verticalInsetsDefined(); - const bool crossInsetsDefined = isMainAxisRow - ? child->getStyle().verticalInsetsDefined() - : child->getStyle().horizontalInsetsDefined(); - - const float childMainOffsetFromParent = mainInsetsDefined - ? (child->getLayout().position(flexStartEdge(mainAxis)) - - currentNodeMainOffsetFromContainingBlock) - : child->getLayout().position(flexStartEdge(mainAxis)); - const float childCrossOffsetFromParent = crossInsetsDefined - ? (child->getLayout().position(flexStartEdge(crossAxis)) - - currentNodeCrossOffsetFromContainingBlock) - : child->getLayout().position(flexStartEdge(crossAxis)); - - child->setLayoutPosition( - childMainOffsetFromParent, flexStartEdge(mainAxis)); - child->setLayoutPosition( - childCrossOffsetFromParent, flexStartEdge(crossAxis)); - - if (needsTrailingPosition(mainAxis)) { - setChildTrailingPosition(currentNode, child, mainAxis); - } - if (needsTrailingPosition(crossAxis)) { - setChildTrailingPosition(currentNode, child, crossAxis); - } - } else if (child->getStyle().positionType() == PositionType::Static) { - const Direction childDirection = - child->resolveDirection(currentNodeDirection); - const float childMainOffsetFromContainingBlock = - currentNodeMainOffsetFromContainingBlock + - child->getLayout().position(flexStartEdge(mainAxis)); - const float childCrossOffsetFromContainingBlock = - currentNodeCrossOffsetFromContainingBlock + - child->getLayout().position(flexStartEdge(crossAxis)); - - layoutAbsoluteDescendants( - containingNode, - child, - widthSizingMode, - childDirection, - layoutMarkerData, - currentDepth + 1, - generationCount, - childMainOffsetFromContainingBlock, - childCrossOffsetFromContainingBlock); - } - } -} - static void measureNodeWithMeasureFunc( yoga::Node* const node, float availableWidth, @@ -1066,8 +682,8 @@ static float distributeFreeSpaceSecondPass( childCrossSize += marginCross; } else if ( !std::isnan(availableInnerCrossDim) && - !styleDefinesDimension( - currentLineChild, crossAxis, availableInnerCrossDim) && + !currentLineChild->styleDefinesDimension( + crossAxis, availableInnerCrossDim) && sizingModeCrossDim == SizingMode::StretchFit && !(isNodeFlexWrap && mainAxisOverflows) && resolveChildAlignment(node, currentLineChild) == Align::Stretch && @@ -1076,8 +692,8 @@ static float distributeFreeSpaceSecondPass( currentLineChild->marginTrailingValue(crossAxis).unit != YGUnitAuto) { childCrossSize = availableInnerCrossDim; childCrossSizingMode = SizingMode::StretchFit; - } else if (!styleDefinesDimension( - currentLineChild, crossAxis, availableInnerCrossDim)) { + } else if (!currentLineChild->styleDefinesDimension( + crossAxis, availableInnerCrossDim)) { childCrossSize = availableInnerCrossDim; childCrossSizingMode = yoga::isUndefined(childCrossSize) ? SizingMode::MaxContent @@ -1114,9 +730,8 @@ static float distributeFreeSpaceSecondPass( &childCrossSizingMode, &childCrossSize); - const bool requiresStretchLayout = - !styleDefinesDimension( - currentLineChild, crossAxis, availableInnerCrossDim) && + const bool requiresStretchLayout = !currentLineChild->styleDefinesDimension( + crossAxis, availableInnerCrossDim) && resolveChildAlignment(node, currentLineChild) == Align::Stretch && currentLineChild->getFlexStartMarginValue(crossAxis).unit != YGUnitAuto && @@ -1481,7 +1096,7 @@ static void justifyMainAxis( // The main dimension is the sum of all the elements dimension plus // the spacing. flexLine.layout.mainDim += - dimensionWithMargin(child, mainAxis, availableInnerWidth); + child->dimensionWithMargin(mainAxis, availableInnerWidth); if (isNodeBaselineLayout) { // If the child is baseline aligned then the cross dimension is @@ -1505,7 +1120,7 @@ static void justifyMainAxis( // when the items are not baseline aligned flexLine.layout.crossDim = yoga::maxOrDefined( flexLine.layout.crossDim, - dimensionWithMargin(child, crossAxis, availableInnerWidth)); + child->dimensionWithMargin(crossAxis, availableInnerWidth)); } } } else if (performLayout) { @@ -2014,8 +1629,8 @@ static void calculateLayoutImpl( child->marginTrailingValue(crossAxis).unit != YGUnitAuto) { // If the child defines a definite size for its cross axis, there's // no need to stretch. - if (!styleDefinesDimension( - child, crossAxis, availableInnerCrossDim)) { + if (!child->styleDefinesDimension( + crossAxis, availableInnerCrossDim)) { float childMainSize = child->getLayout().measuredDimension(dimension(mainAxis)); const auto& childStyle = child->getStyle(); @@ -2082,7 +1697,7 @@ static void calculateLayoutImpl( } } else { const float remainingCrossDim = containerCrossAxis - - dimensionWithMargin(child, crossAxis, availableInnerWidth); + child->dimensionWithMargin(crossAxis, availableInnerWidth); if (child->getFlexStartMarginValue(crossAxis).unit == YGUnitAuto && child->marginTrailingValue(crossAxis).unit == YGUnitAuto) { @@ -2192,7 +1807,7 @@ static void calculateLayoutImpl( if (child->getLineIndex() != i) { break; } - if (isLayoutDimensionDefined(child, crossAxis)) { + if (child->isLayoutDimensionDefined(crossAxis)) { lineHeight = yoga::maxOrDefined( lineHeight, child->getLayout().measuredDimension(dimension(crossAxis)) + @@ -2264,8 +1879,8 @@ static void calculateLayoutImpl( // Remeasure child with the line height as it as been only // measured with the owners height yet. - if (!styleDefinesDimension( - child, crossAxis, availableInnerCrossDim)) { + if (!child->styleDefinesDimension( + crossAxis, availableInnerCrossDim)) { const float childWidth = isMainAxisRow ? (child->getLayout().measuredDimension( Dimension::Width) + @@ -2812,7 +2427,7 @@ void calculateLayout( float width = YGUndefined; SizingMode widthSizingMode = SizingMode::MaxContent; const auto& style = node->getStyle(); - if (styleDefinesDimension(node, FlexDirection::Row, ownerWidth)) { + if (node->styleDefinesDimension(FlexDirection::Row, ownerWidth)) { width = (yoga::resolveValue( node->getResolvedDimension(dimension(FlexDirection::Row)), @@ -2834,7 +2449,7 @@ void calculateLayout( float height = YGUndefined; SizingMode heightSizingMode = SizingMode::MaxContent; - if (styleDefinesDimension(node, FlexDirection::Column, ownerHeight)) { + if (node->styleDefinesDimension(FlexDirection::Column, ownerHeight)) { height = (yoga::resolveValue( node->getResolvedDimension(dimension(FlexDirection::Column)), diff --git a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h index 47b05dbe1f4d9a..26f4aa47a9dc6d 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h +++ b/packages/react-native/ReactCommon/yoga/yoga/algorithm/CalculateLayout.h @@ -8,6 +8,8 @@ #pragma once #include +#include +#include #include namespace facebook::yoga { @@ -18,4 +20,35 @@ void calculateLayout( const float ownerHeight, const Direction ownerDirection); +bool calculateLayoutInternal( + yoga::Node* const node, + const float availableWidth, + const float availableHeight, + const Direction ownerDirection, + const SizingMode widthSizingMode, + const SizingMode heightSizingMode, + const float ownerWidth, + const float ownerHeight, + const bool performLayout, + const LayoutPassReason reason, + LayoutData& layoutMarkerData, + const uint32_t depth, + const uint32_t generationCount); + +inline void setChildTrailingPosition( + const yoga::Node* const node, + yoga::Node* const child, + const FlexDirection axis) { + const float size = child->getLayout().measuredDimension(dimension(axis)); + child->setLayoutPosition( + node->getLayout().measuredDimension(dimension(axis)) - size - + child->getLayout().position(flexStartEdge(axis)), + flexEndEdge(axis)); +} + +inline bool needsTrailingPosition(const FlexDirection axis) { + return axis == FlexDirection::RowReverse || + axis == FlexDirection::ColumnReverse; +} + } // namespace facebook::yoga diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp index c10fbfdfe753d3..f26a588e174cc7 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.cpp @@ -404,6 +404,33 @@ float Node::baseline(float width, float height) const { return baselineFunc_(this, width, height); } +float Node::dimensionWithMargin( + const FlexDirection axis, + const float widthSize) { + return getLayout().measuredDimension(dimension(axis)) + + getMarginForAxis(axis, widthSize); +} + +bool Node::isLayoutDimensionDefined(const FlexDirection axis) { + const float value = getLayout().measuredDimension(dimension(axis)); + return yoga::isDefined(value) && value >= 0.0f; +} + +bool Node::styleDefinesDimension( + const FlexDirection axis, + const float ownerSize) { + bool isDefined = yoga::isDefined(getResolvedDimension(dimension(axis)).value); + + auto resolvedDimension = getResolvedDimension(dimension(axis)); + return !( + resolvedDimension.unit == YGUnitAuto || + resolvedDimension.unit == YGUnitUndefined || + (resolvedDimension.unit == YGUnitPoint && isDefined && + resolvedDimension.value < 0.0f) || + (resolvedDimension.unit == YGUnitPercent && isDefined && + (resolvedDimension.value < 0.0f || yoga::isUndefined(ownerSize)))); +} + // Setters void Node::setMeasureFunc(YGMeasureFunc measureFunc) { diff --git a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h index 81036affea05af..aa60b3d8303a70 100644 --- a/packages/react-native/ReactCommon/yoga/yoga/node/Node.h +++ b/packages/react-native/ReactCommon/yoga/yoga/node/Node.h @@ -126,6 +126,12 @@ class YG_EXPORT Node : public ::YGNode { float baseline(float width, float height) const; + float dimensionWithMargin(const FlexDirection axis, const float widthSize); + + bool isLayoutDimensionDefined(const FlexDirection axis); + + bool styleDefinesDimension(const FlexDirection axis, const float ownerSize); + bool hasErrata(Errata errata) const { return config_->hasErrata(errata); }