// It distributes the free space to the flexible items and ensures that the size
        // of the flex items abide the min and max constraints. At the end of this
        // function the child nodes would have proper size. Prior using this function
        // please ensure that YGDistributeFreeSpaceFirstPass is called.

        private float DistributeFreeSpaceSecondPass(
            YogaNode node,
            FlexDirectionType mainAxis,
            FlexDirectionType crossAxis,
            float mainAxisOwnerSize,
            float availableInnerMainDim,
            float availableInnerCrossDim,
            float availableInnerWidth,
            float availableInnerHeight,
            bool flexBasisOverflows,
            MeasureMode measureModeCrossDim,
            bool performLayout,
            YogaConfig config)
        {
            float deltaFreeSpace = 0;
            var   isMainAxisRow  = mainAxis.IsRow();
            var   isNodeFlexWrap = node.FlexWrap != WrapType.NoWrap;

            foreach (var currentRelativeChild in RelativeChildren)
            {
                var childFlexBasis = currentRelativeChild.BoundAxisWithinMinAndMax(
                    mainAxis,
                    currentRelativeChild.Layout.ComputedFlexBasis.Unwrap(),
                    mainAxisOwnerSize);
                var updatedMainSize = childFlexBasis;

                if (RemainingFreeSpace.HasValue() && RemainingFreeSpace < 0)
                {
                    var flexShrinkScaledFactor = -currentRelativeChild.ResolveFlexShrink() * childFlexBasis;
                    // Is this child able to shrink?
                    if (flexShrinkScaledFactor != 0f)
                    {
                        float childSize;

                        if (TotalFlexShrinkScaledFactors.HasValue() && TotalFlexShrinkScaledFactors == 0f)
                        {
                            childSize = childFlexBasis + flexShrinkScaledFactor;
                        }
                        else
                        {
                            childSize = childFlexBasis + RemainingFreeSpace / TotalFlexShrinkScaledFactors * flexShrinkScaledFactor;
                        }

                        updatedMainSize = currentRelativeChild.BoundAxis(
                            mainAxis,
                            childSize,
                            availableInnerMainDim,
                            availableInnerWidth);
                    }
                }
                else if (RemainingFreeSpace.HasValue() && RemainingFreeSpace > 0)
                {
                    var flexGrowFactor = currentRelativeChild.ResolveFlexGrow();

                    // Is this child able to grow?
                    if (flexGrowFactor.HasValue() && flexGrowFactor != 0)
                    {
                        updatedMainSize = currentRelativeChild.BoundAxis(
                            mainAxis,
                            childFlexBasis + RemainingFreeSpace / TotalFlexGrowFactors * flexGrowFactor,
                            availableInnerMainDim,
                            availableInnerWidth);
                    }
                }

                deltaFreeSpace += updatedMainSize - childFlexBasis;

                var marginMain  = currentRelativeChild.GetMarginForAxis(mainAxis, availableInnerWidth);
                var marginCross = currentRelativeChild.GetMarginForAxis(crossAxis, availableInnerWidth);

                float       childCrossSize;
                var         childMainSize = updatedMainSize + marginMain;
                MeasureMode childCrossMeasureMode;
                var         childMainMeasureMode = MeasureMode.Exactly;

                if (currentRelativeChild.AspectRatio.HasValue)
                {
                    childCrossSize = isMainAxisRow
                        ? (childMainSize - marginMain) / currentRelativeChild.AspectRatio.Value
                        : (childMainSize - marginMain) * currentRelativeChild.AspectRatio.Value;
                    childCrossMeasureMode = MeasureMode.Exactly;

                    childCrossSize += marginCross;
                }
                else if (
                    availableInnerCrossDim.HasValue() &&
                    !currentRelativeChild.IsStyleDimensionDefined(crossAxis, availableInnerCrossDim) &&
                    measureModeCrossDim == MeasureMode.Exactly &&
                    !(isNodeFlexWrap && flexBasisOverflows) &&
                    node.AlignChild(currentRelativeChild) == AlignType.Stretch &&
                    currentRelativeChild.MarginLeadingValue(crossAxis).Unit !=
                    ValueUnit.Auto &&
                    currentRelativeChild.MarginTrailingValue(crossAxis).Unit !=
                    ValueUnit.Auto)
                {
                    childCrossSize        = availableInnerCrossDim;
                    childCrossMeasureMode = MeasureMode.Exactly;
                }
                else if (!currentRelativeChild.IsStyleDimensionDefined(crossAxis, availableInnerCrossDim))
                {
                    childCrossSize        = availableInnerCrossDim;
                    childCrossMeasureMode = childCrossSize.IsNaN()
                        ? MeasureMode.Undefined
                        : MeasureMode.AtMost;
                }
                else
                {
                    childCrossSize =
                        currentRelativeChild.ResolvedDimension[crossAxis.ToDimension()].ResolveValue(availableInnerCrossDim) + marginCross;
                    var isLoosePercentageMeasurement =
                        currentRelativeChild.ResolvedDimension[crossAxis.ToDimension()].Unit == ValueUnit.Percent &&
                        measureModeCrossDim != MeasureMode.Exactly;
                    childCrossMeasureMode =
                        childCrossSize.IsNaN() || isLoosePercentageMeasurement
                            ? MeasureMode.Undefined
                            : MeasureMode.Exactly;
                }

                currentRelativeChild.Calc.ConstrainMaxSizeForMode(
                    mainAxis,
                    availableInnerMainDim,
                    availableInnerWidth,
                    ref childMainMeasureMode,
                    ref childMainSize);
                currentRelativeChild.Calc.ConstrainMaxSizeForMode(
                    crossAxis,
                    availableInnerCrossDim,
                    availableInnerWidth,
                    ref childCrossMeasureMode,
                    ref childCrossSize);

                var requiresStretchLayout =
                    !currentRelativeChild.IsStyleDimensionDefined(crossAxis, availableInnerCrossDim) &&
                    node.AlignChild(currentRelativeChild) == AlignType.Stretch &&
                    currentRelativeChild.MarginLeadingValue(crossAxis).Unit !=
                    ValueUnit.Auto &&
                    currentRelativeChild.MarginTrailingValue(crossAxis).Unit != ValueUnit.Auto;

                var childWidth  = isMainAxisRow ? childMainSize : childCrossSize;
                var childHeight = !isMainAxisRow ? childMainSize : childCrossSize;

                var childWidthMeasureMode  = isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
                var childHeightMeasureMode = !isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;

                // Recursively call the layout algorithm for this child with the updated main size.
                currentRelativeChild.Calc.LayoutInternal(
                    childWidth,
                    childHeight,
                    node.Layout.Direction,
                    childWidthMeasureMode,
                    childHeightMeasureMode,
                    availableInnerWidth,
                    availableInnerHeight,
                    performLayout && !requiresStretchLayout,
                    "flex",
                    config);
                node.Layout.HadOverflow = node.Layout.HadOverflow | currentRelativeChild.Layout.HadOverflow;
            }

            return(deltaFreeSpace);
        }
 private static void Log(YogaConfig config, LogLevel level, string message)
 {
     Log(config, null, level, message);
 }