Separate FlexLine functionality (#1374)
Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1374 X-link: https://github.com/facebook/react-native/pull/39396 Yoga today has a struct `CollectFlexItemsRowValues`, and function `calculateFlexItemsRowValues()`. These names have evolved over time into something not making much sense. The job of `calculateFlexItemsRowValues()` is a flex-wrap container into lines (i.e. line-breaking main-axis content, which may be row or column). It returns line-breaking results, but some other fields on `calculateFlexItemsRowValues()` are set much later in the process, and the struct is acting effectivelty as a holder for the line-specific values. This change: 1. Does some renaming (mainly to FlexLine) 2. Reconciles the count `itemsOnLine` and list `relativeChildren` to list `itemsInFlow` (`relativeChildren` is a lie, as it can include elements with `YGPositionTypeStatic` and exclude relative elements which have `display: "none"`. It really just means children which are included in the layout flow for the line) 3. Makes non-changing algorithm outputs const for clarity of what is a running value, and what is a result of line-breaking values with flex basis. 4. Moves working layout values to a substructure `flexLine.layout` 5. Replaces some dishonest documentation about `endOfLineIndex`. 6. Extracts this logic out of `CalculateLayout()` to a separate file 7. Extracts `boundAxis` wholesale into a separate file, to be usable outside of `CalculateLayout.cpp` Reviewed By: rshest Differential Revision: D49133837 fbshipit-source-id: ec68c5a3d2f01e7c9bd8d26e28298331a3fe2475
This commit is contained in:
committed by
Facebook GitHub Bot
parent
241c5e4baf
commit
a4f36bdb51
72
yoga/algorithm/BoundAxis.h
Normal file
72
yoga/algorithm/BoundAxis.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 <yoga/algorithm/FlexDirection.h>
|
||||
#include <yoga/algorithm/ResolveValue.h>
|
||||
#include <yoga/node/Node.h>
|
||||
#include <yoga/numeric/Comparison.h>
|
||||
#include <yoga/numeric/FloatOptional.h>
|
||||
|
||||
namespace facebook::yoga {
|
||||
|
||||
inline float paddingAndBorderForAxis(
|
||||
const yoga::Node* const node,
|
||||
const YGFlexDirection axis,
|
||||
const float widthSize) {
|
||||
return (node->getLeadingPaddingAndBorder(axis, widthSize) +
|
||||
node->getTrailingPaddingAndBorder(axis, widthSize))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
inline FloatOptional boundAxisWithinMinAndMax(
|
||||
const yoga::Node* const node,
|
||||
const YGFlexDirection axis,
|
||||
const FloatOptional value,
|
||||
const float axisSize) {
|
||||
FloatOptional min;
|
||||
FloatOptional max;
|
||||
|
||||
if (isColumn(axis)) {
|
||||
min = yoga::resolveValue(
|
||||
node->getStyle().minDimensions()[YGDimensionHeight], axisSize);
|
||||
max = yoga::resolveValue(
|
||||
node->getStyle().maxDimensions()[YGDimensionHeight], axisSize);
|
||||
} else if (isRow(axis)) {
|
||||
min = yoga::resolveValue(
|
||||
node->getStyle().minDimensions()[YGDimensionWidth], axisSize);
|
||||
max = yoga::resolveValue(
|
||||
node->getStyle().maxDimensions()[YGDimensionWidth], axisSize);
|
||||
}
|
||||
|
||||
if (max >= FloatOptional{0} && value > max) {
|
||||
return max;
|
||||
}
|
||||
|
||||
if (min >= FloatOptional{0} && value < min) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Like boundAxisWithinMinAndMax but also ensures that the value doesn't
|
||||
// go below the padding and border amount.
|
||||
inline float boundAxis(
|
||||
const yoga::Node* const node,
|
||||
const YGFlexDirection axis,
|
||||
const float value,
|
||||
const float axisSize,
|
||||
const float widthSize) {
|
||||
return yoga::maxOrDefined(
|
||||
boundAxisWithinMinAndMax(node, axis, FloatOptional{value}, axisSize)
|
||||
.unwrap(),
|
||||
paddingAndBorderForAxis(node, axis, widthSize));
|
||||
}
|
||||
|
||||
} // namespace facebook::yoga
|
@@ -15,10 +15,11 @@
|
||||
|
||||
#include <yoga/algorithm/Align.h>
|
||||
#include <yoga/algorithm/Baseline.h>
|
||||
#include <yoga/algorithm/BoundAxis.h>
|
||||
#include <yoga/algorithm/Cache.h>
|
||||
#include <yoga/algorithm/CalculateLayout.h>
|
||||
#include <yoga/algorithm/CollectFlexItemsRowValues.h>
|
||||
#include <yoga/algorithm/FlexDirection.h>
|
||||
#include <yoga/algorithm/FlexLine.h>
|
||||
#include <yoga/algorithm/PixelGrid.h>
|
||||
#include <yoga/algorithm/ResolveValue.h>
|
||||
#include <yoga/debug/AssertFatal.h>
|
||||
@@ -26,6 +27,7 @@
|
||||
#include <yoga/event/event.h>
|
||||
#include <yoga/node/Node.h>
|
||||
#include <yoga/numeric/Comparison.h>
|
||||
#include <yoga/numeric/FloatOptional.h>
|
||||
|
||||
namespace facebook::yoga {
|
||||
|
||||
@@ -58,15 +60,6 @@ static const std::array<YGEdge, 4> pos = {{
|
||||
static const std::array<YGDimension, 4> dim = {
|
||||
{YGDimensionHeight, YGDimensionHeight, YGDimensionWidth, YGDimensionWidth}};
|
||||
|
||||
static inline float paddingAndBorderForAxis(
|
||||
const yoga::Node* const node,
|
||||
const YGFlexDirection axis,
|
||||
const float widthSize) {
|
||||
return (node->getLeadingPaddingAndBorder(axis, widthSize) +
|
||||
node->getTrailingPaddingAndBorder(axis, widthSize))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
static bool isBaselineLayout(const yoga::Node* node) {
|
||||
if (isColumn(node->getStyle().flexDirection())) {
|
||||
return false;
|
||||
@@ -120,51 +113,6 @@ static inline bool isLayoutDimensionDefined(
|
||||
return !yoga::isUndefined(value) && value >= 0.0f;
|
||||
}
|
||||
|
||||
static FloatOptional boundAxisWithinMinAndMax(
|
||||
const yoga::Node* const node,
|
||||
const YGFlexDirection axis,
|
||||
const FloatOptional value,
|
||||
const float axisSize) {
|
||||
FloatOptional min;
|
||||
FloatOptional max;
|
||||
|
||||
if (isColumn(axis)) {
|
||||
min = yoga::resolveValue(
|
||||
node->getStyle().minDimensions()[YGDimensionHeight], axisSize);
|
||||
max = yoga::resolveValue(
|
||||
node->getStyle().maxDimensions()[YGDimensionHeight], axisSize);
|
||||
} else if (isRow(axis)) {
|
||||
min = yoga::resolveValue(
|
||||
node->getStyle().minDimensions()[YGDimensionWidth], axisSize);
|
||||
max = yoga::resolveValue(
|
||||
node->getStyle().maxDimensions()[YGDimensionWidth], axisSize);
|
||||
}
|
||||
|
||||
if (max >= FloatOptional{0} && value > max) {
|
||||
return max;
|
||||
}
|
||||
|
||||
if (min >= FloatOptional{0} && value < min) {
|
||||
return min;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Like boundAxisWithinMinAndMax but also ensures that the value doesn't
|
||||
// go below the padding and border amount.
|
||||
static inline float boundAxis(
|
||||
const yoga::Node* const node,
|
||||
const YGFlexDirection axis,
|
||||
const float value,
|
||||
const float axisSize,
|
||||
const float widthSize) {
|
||||
return yoga::maxOrDefined(
|
||||
boundAxisWithinMinAndMax(node, axis, FloatOptional{value}, axisSize)
|
||||
.unwrap(),
|
||||
paddingAndBorderForAxis(node, axis, widthSize));
|
||||
}
|
||||
|
||||
static void setChildTrailingPosition(
|
||||
const yoga::Node* const node,
|
||||
yoga::Node* const child,
|
||||
@@ -955,103 +903,12 @@ static float computeFlexBasisForChildren(
|
||||
return totalOuterFlexBasis;
|
||||
}
|
||||
|
||||
// This function assumes that all the children of node have their
|
||||
// computedFlexBasis properly computed(To do this use
|
||||
// computeFlexBasisForChildren function). This function calculates
|
||||
// YGCollectFlexItemsRowMeasurement
|
||||
static CollectFlexItemsRowValues calculateCollectFlexItemsRowValues(
|
||||
yoga::Node* const node,
|
||||
const YGDirection ownerDirection,
|
||||
const float mainAxisownerSize,
|
||||
const float availableInnerWidth,
|
||||
const float availableInnerMainDim,
|
||||
const size_t startOfLineIndex,
|
||||
const size_t lineCount) {
|
||||
CollectFlexItemsRowValues flexAlgoRowMeasurement = {};
|
||||
flexAlgoRowMeasurement.relativeChildren.reserve(node->getChildren().size());
|
||||
|
||||
float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
|
||||
const YGFlexDirection mainAxis = resolveDirection(
|
||||
node->getStyle().flexDirection(), node->resolveDirection(ownerDirection));
|
||||
const bool isNodeFlexWrap = node->getStyle().flexWrap() != YGWrapNoWrap;
|
||||
const float gap = node->getGapForAxis(mainAxis, availableInnerWidth).unwrap();
|
||||
|
||||
// Add items to the current line until it's full or we run out of items.
|
||||
size_t endOfLineIndex = startOfLineIndex;
|
||||
for (; endOfLineIndex < node->getChildren().size(); endOfLineIndex++) {
|
||||
auto child = node->getChild(endOfLineIndex);
|
||||
if (child->getStyle().display() == YGDisplayNone ||
|
||||
child->getStyle().positionType() == YGPositionTypeAbsolute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool isFirstElementInLine = (endOfLineIndex - startOfLineIndex) == 0;
|
||||
|
||||
child->setLineIndex(lineCount);
|
||||
const float childMarginMainAxis =
|
||||
child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap();
|
||||
const float childLeadingGapMainAxis = isFirstElementInLine ? 0.0f : gap;
|
||||
const float flexBasisWithMinAndMaxConstraints =
|
||||
boundAxisWithinMinAndMax(
|
||||
child,
|
||||
mainAxis,
|
||||
child->getLayout().computedFlexBasis,
|
||||
mainAxisownerSize)
|
||||
.unwrap();
|
||||
|
||||
// If this is a multi-line flow and this item pushes us over the available
|
||||
// size, we've hit the end of the current line. Break out of the loop and
|
||||
// lay out the current line.
|
||||
if (sizeConsumedOnCurrentLineIncludingMinConstraint +
|
||||
flexBasisWithMinAndMaxConstraints + childMarginMainAxis +
|
||||
childLeadingGapMainAxis >
|
||||
availableInnerMainDim &&
|
||||
isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
sizeConsumedOnCurrentLineIncludingMinConstraint +=
|
||||
flexBasisWithMinAndMaxConstraints + childMarginMainAxis +
|
||||
childLeadingGapMainAxis;
|
||||
flexAlgoRowMeasurement.sizeConsumedOnCurrentLine +=
|
||||
flexBasisWithMinAndMaxConstraints + childMarginMainAxis +
|
||||
childLeadingGapMainAxis;
|
||||
flexAlgoRowMeasurement.itemsOnLine++;
|
||||
|
||||
if (child->isNodeFlexible()) {
|
||||
flexAlgoRowMeasurement.totalFlexGrowFactors += child->resolveFlexGrow();
|
||||
|
||||
// Unlike the grow factor, the shrink factor is scaled relative to the
|
||||
// child dimension.
|
||||
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
|
||||
-child->resolveFlexShrink() *
|
||||
child->getLayout().computedFlexBasis.unwrap();
|
||||
}
|
||||
|
||||
flexAlgoRowMeasurement.relativeChildren.push_back(child);
|
||||
}
|
||||
|
||||
// The total flex factor needs to be floored to 1.
|
||||
if (flexAlgoRowMeasurement.totalFlexGrowFactors > 0 &&
|
||||
flexAlgoRowMeasurement.totalFlexGrowFactors < 1) {
|
||||
flexAlgoRowMeasurement.totalFlexGrowFactors = 1;
|
||||
}
|
||||
|
||||
// The total flex shrink factor needs to be floored to 1.
|
||||
if (flexAlgoRowMeasurement.totalFlexShrinkScaledFactors > 0 &&
|
||||
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors < 1) {
|
||||
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors = 1;
|
||||
}
|
||||
flexAlgoRowMeasurement.endOfLineIndex = endOfLineIndex;
|
||||
return flexAlgoRowMeasurement;
|
||||
}
|
||||
|
||||
// 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 distributeFreeSpaceFirstPass is called.
|
||||
static float distributeFreeSpaceSecondPass(
|
||||
CollectFlexItemsRowValues& collectedFlexItemsValues,
|
||||
FlexLine& flexLine,
|
||||
yoga::Node* const node,
|
||||
const YGFlexDirection mainAxis,
|
||||
const YGFlexDirection crossAxis,
|
||||
@@ -1075,55 +932,53 @@ static float distributeFreeSpaceSecondPass(
|
||||
const bool isMainAxisRow = isRow(mainAxis);
|
||||
const bool isNodeFlexWrap = node->getStyle().flexWrap() != YGWrapNoWrap;
|
||||
|
||||
for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
|
||||
for (auto currentLineChild : flexLine.itemsInFlow) {
|
||||
childFlexBasis = boundAxisWithinMinAndMax(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
mainAxis,
|
||||
currentRelativeChild->getLayout().computedFlexBasis,
|
||||
currentLineChild->getLayout().computedFlexBasis,
|
||||
mainAxisownerSize)
|
||||
.unwrap();
|
||||
float updatedMainSize = childFlexBasis;
|
||||
|
||||
if (!yoga::isUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
|
||||
collectedFlexItemsValues.remainingFreeSpace < 0) {
|
||||
if (!yoga::isUndefined(flexLine.layout.remainingFreeSpace) &&
|
||||
flexLine.layout.remainingFreeSpace < 0) {
|
||||
flexShrinkScaledFactor =
|
||||
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
|
||||
-currentLineChild->resolveFlexShrink() * childFlexBasis;
|
||||
// Is this child able to shrink?
|
||||
if (flexShrinkScaledFactor != 0) {
|
||||
float childSize;
|
||||
|
||||
if (!yoga::isUndefined(
|
||||
collectedFlexItemsValues.totalFlexShrinkScaledFactors) &&
|
||||
collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
|
||||
if (!yoga::isUndefined(flexLine.layout.totalFlexShrinkScaledFactors) &&
|
||||
flexLine.layout.totalFlexShrinkScaledFactors == 0) {
|
||||
childSize = childFlexBasis + flexShrinkScaledFactor;
|
||||
} else {
|
||||
childSize = childFlexBasis +
|
||||
(collectedFlexItemsValues.remainingFreeSpace /
|
||||
collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
|
||||
(flexLine.layout.remainingFreeSpace /
|
||||
flexLine.layout.totalFlexShrinkScaledFactors) *
|
||||
flexShrinkScaledFactor;
|
||||
}
|
||||
|
||||
updatedMainSize = boundAxis(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
mainAxis,
|
||||
childSize,
|
||||
availableInnerMainDim,
|
||||
availableInnerWidth);
|
||||
}
|
||||
} else if (
|
||||
!yoga::isUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
|
||||
collectedFlexItemsValues.remainingFreeSpace > 0) {
|
||||
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
|
||||
!yoga::isUndefined(flexLine.layout.remainingFreeSpace) &&
|
||||
flexLine.layout.remainingFreeSpace > 0) {
|
||||
flexGrowFactor = currentLineChild->resolveFlexGrow();
|
||||
|
||||
// Is this child able to grow?
|
||||
if (!std::isnan(flexGrowFactor) && flexGrowFactor != 0) {
|
||||
updatedMainSize = boundAxis(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
mainAxis,
|
||||
childFlexBasis +
|
||||
collectedFlexItemsValues.remainingFreeSpace /
|
||||
collectedFlexItemsValues.totalFlexGrowFactors *
|
||||
flexGrowFactor,
|
||||
flexLine.layout.remainingFreeSpace /
|
||||
flexLine.layout.totalFlexGrowFactors * flexGrowFactor,
|
||||
availableInnerMainDim,
|
||||
availableInnerWidth);
|
||||
}
|
||||
@@ -1132,10 +987,10 @@ static float distributeFreeSpaceSecondPass(
|
||||
deltaFreeSpace += updatedMainSize - childFlexBasis;
|
||||
|
||||
const float marginMain =
|
||||
currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth)
|
||||
currentLineChild->getMarginForAxis(mainAxis, availableInnerWidth)
|
||||
.unwrap();
|
||||
const float marginCross =
|
||||
currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth)
|
||||
currentLineChild->getMarginForAxis(crossAxis, availableInnerWidth)
|
||||
.unwrap();
|
||||
|
||||
float childCrossSize;
|
||||
@@ -1143,7 +998,7 @@ static float distributeFreeSpaceSecondPass(
|
||||
YGMeasureMode childCrossMeasureMode;
|
||||
YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
|
||||
|
||||
const auto& childStyle = currentRelativeChild->getStyle();
|
||||
const auto& childStyle = currentLineChild->getStyle();
|
||||
if (!childStyle.aspectRatio().isUndefined()) {
|
||||
childCrossSize = isMainAxisRow
|
||||
? (childMainSize - marginMain) / childStyle.aspectRatio().unwrap()
|
||||
@@ -1154,18 +1009,16 @@ static float distributeFreeSpaceSecondPass(
|
||||
} else if (
|
||||
!std::isnan(availableInnerCrossDim) &&
|
||||
!styleDefinesDimension(
|
||||
currentRelativeChild, crossAxis, availableInnerCrossDim) &&
|
||||
currentLineChild, crossAxis, availableInnerCrossDim) &&
|
||||
measureModeCrossDim == YGMeasureModeExactly &&
|
||||
!(isNodeFlexWrap && mainAxisOverflows) &&
|
||||
resolveChildAlignment(node, currentRelativeChild) == YGAlignStretch &&
|
||||
currentRelativeChild->marginLeadingValue(crossAxis).unit !=
|
||||
YGUnitAuto &&
|
||||
currentRelativeChild->marginTrailingValue(crossAxis).unit !=
|
||||
YGUnitAuto) {
|
||||
resolveChildAlignment(node, currentLineChild) == YGAlignStretch &&
|
||||
currentLineChild->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
|
||||
currentLineChild->marginTrailingValue(crossAxis).unit != YGUnitAuto) {
|
||||
childCrossSize = availableInnerCrossDim;
|
||||
childCrossMeasureMode = YGMeasureModeExactly;
|
||||
} else if (!styleDefinesDimension(
|
||||
currentRelativeChild, crossAxis, availableInnerCrossDim)) {
|
||||
currentLineChild, crossAxis, availableInnerCrossDim)) {
|
||||
childCrossSize = availableInnerCrossDim;
|
||||
childCrossMeasureMode = yoga::isUndefined(childCrossSize)
|
||||
? YGMeasureModeUndefined
|
||||
@@ -1173,12 +1026,12 @@ static float distributeFreeSpaceSecondPass(
|
||||
} else {
|
||||
childCrossSize =
|
||||
yoga::resolveValue(
|
||||
currentRelativeChild->getResolvedDimension(dim[crossAxis]),
|
||||
currentLineChild->getResolvedDimension(dim[crossAxis]),
|
||||
availableInnerCrossDim)
|
||||
.unwrap() +
|
||||
marginCross;
|
||||
const bool isLoosePercentageMeasurement =
|
||||
currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
|
||||
currentLineChild->getResolvedDimension(dim[crossAxis]).unit ==
|
||||
YGUnitPercent &&
|
||||
measureModeCrossDim != YGMeasureModeExactly;
|
||||
childCrossMeasureMode =
|
||||
@@ -1188,14 +1041,14 @@ static float distributeFreeSpaceSecondPass(
|
||||
}
|
||||
|
||||
constrainMaxSizeForMode(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
mainAxis,
|
||||
availableInnerMainDim,
|
||||
availableInnerWidth,
|
||||
&childMainMeasureMode,
|
||||
&childMainSize);
|
||||
constrainMaxSizeForMode(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
crossAxis,
|
||||
availableInnerCrossDim,
|
||||
availableInnerWidth,
|
||||
@@ -1204,11 +1057,10 @@ static float distributeFreeSpaceSecondPass(
|
||||
|
||||
const bool requiresStretchLayout =
|
||||
!styleDefinesDimension(
|
||||
currentRelativeChild, crossAxis, availableInnerCrossDim) &&
|
||||
resolveChildAlignment(node, currentRelativeChild) == YGAlignStretch &&
|
||||
currentRelativeChild->marginLeadingValue(crossAxis).unit !=
|
||||
YGUnitAuto &&
|
||||
currentRelativeChild->marginTrailingValue(crossAxis).unit != YGUnitAuto;
|
||||
currentLineChild, crossAxis, availableInnerCrossDim) &&
|
||||
resolveChildAlignment(node, currentLineChild) == YGAlignStretch &&
|
||||
currentLineChild->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
|
||||
currentLineChild->marginTrailingValue(crossAxis).unit != YGUnitAuto;
|
||||
|
||||
const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
|
||||
const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
|
||||
@@ -1222,7 +1074,7 @@ static float distributeFreeSpaceSecondPass(
|
||||
// Recursively call the layout algorithm for this child with the updated
|
||||
// main size.
|
||||
calculateLayoutInternal(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
childWidth,
|
||||
childHeight,
|
||||
node->getLayout().direction(),
|
||||
@@ -1240,7 +1092,7 @@ static float distributeFreeSpaceSecondPass(
|
||||
generationCount);
|
||||
node->setLayoutHadOverflow(
|
||||
node->getLayout().hadOverflow() ||
|
||||
currentRelativeChild->getLayout().hadOverflow());
|
||||
currentLineChild->getLayout().hadOverflow());
|
||||
}
|
||||
return deltaFreeSpace;
|
||||
}
|
||||
@@ -1249,7 +1101,7 @@ static float distributeFreeSpaceSecondPass(
|
||||
// whose min and max constraints are triggered, those flex item's clamped size
|
||||
// is removed from the remaingfreespace.
|
||||
static void distributeFreeSpaceFirstPass(
|
||||
CollectFlexItemsRowValues& collectedFlexItemsValues,
|
||||
FlexLine& flexLine,
|
||||
const YGFlexDirection mainAxis,
|
||||
const float mainAxisownerSize,
|
||||
const float availableInnerMainDim,
|
||||
@@ -1260,28 +1112,27 @@ static void distributeFreeSpaceFirstPass(
|
||||
float boundMainSize = 0;
|
||||
float deltaFreeSpace = 0;
|
||||
|
||||
for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
|
||||
float childFlexBasis =
|
||||
boundAxisWithinMinAndMax(
|
||||
currentRelativeChild,
|
||||
for (auto currentLineChild : flexLine.itemsInFlow) {
|
||||
float childFlexBasis = boundAxisWithinMinAndMax(
|
||||
currentLineChild,
|
||||
mainAxis,
|
||||
currentRelativeChild->getLayout().computedFlexBasis,
|
||||
currentLineChild->getLayout().computedFlexBasis,
|
||||
mainAxisownerSize)
|
||||
.unwrap();
|
||||
|
||||
if (collectedFlexItemsValues.remainingFreeSpace < 0) {
|
||||
if (flexLine.layout.remainingFreeSpace < 0) {
|
||||
flexShrinkScaledFactor =
|
||||
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
|
||||
-currentLineChild->resolveFlexShrink() * childFlexBasis;
|
||||
|
||||
// Is this child able to shrink?
|
||||
if (!yoga::isUndefined(flexShrinkScaledFactor) &&
|
||||
flexShrinkScaledFactor != 0) {
|
||||
baseMainSize = childFlexBasis +
|
||||
collectedFlexItemsValues.remainingFreeSpace /
|
||||
collectedFlexItemsValues.totalFlexShrinkScaledFactors *
|
||||
flexLine.layout.remainingFreeSpace /
|
||||
flexLine.layout.totalFlexShrinkScaledFactors *
|
||||
flexShrinkScaledFactor;
|
||||
boundMainSize = boundAxis(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
mainAxis,
|
||||
baseMainSize,
|
||||
availableInnerMainDim,
|
||||
@@ -1294,23 +1145,23 @@ static void distributeFreeSpaceFirstPass(
|
||||
// resulting in the item's size calculation being identical in the
|
||||
// first and second passes.
|
||||
deltaFreeSpace += boundMainSize - childFlexBasis;
|
||||
collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
|
||||
(-currentRelativeChild->resolveFlexShrink() *
|
||||
currentRelativeChild->getLayout().computedFlexBasis.unwrap());
|
||||
flexLine.layout.totalFlexShrinkScaledFactors -=
|
||||
(-currentLineChild->resolveFlexShrink() *
|
||||
currentLineChild->getLayout().computedFlexBasis.unwrap());
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
!yoga::isUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
|
||||
collectedFlexItemsValues.remainingFreeSpace > 0) {
|
||||
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
|
||||
!yoga::isUndefined(flexLine.layout.remainingFreeSpace) &&
|
||||
flexLine.layout.remainingFreeSpace > 0) {
|
||||
flexGrowFactor = currentLineChild->resolveFlexGrow();
|
||||
|
||||
// Is this child able to grow?
|
||||
if (!yoga::isUndefined(flexGrowFactor) && flexGrowFactor != 0) {
|
||||
baseMainSize = childFlexBasis +
|
||||
collectedFlexItemsValues.remainingFreeSpace /
|
||||
collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
|
||||
flexLine.layout.remainingFreeSpace /
|
||||
flexLine.layout.totalFlexGrowFactors * flexGrowFactor;
|
||||
boundMainSize = boundAxis(
|
||||
currentRelativeChild,
|
||||
currentLineChild,
|
||||
mainAxis,
|
||||
baseMainSize,
|
||||
availableInnerMainDim,
|
||||
@@ -1324,12 +1175,12 @@ static void distributeFreeSpaceFirstPass(
|
||||
// resulting in the item's size calculation being identical in the
|
||||
// first and second passes.
|
||||
deltaFreeSpace += boundMainSize - childFlexBasis;
|
||||
collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
|
||||
flexLine.layout.totalFlexGrowFactors -= flexGrowFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
collectedFlexItemsValues.remainingFreeSpace -= deltaFreeSpace;
|
||||
flexLine.layout.remainingFreeSpace -= deltaFreeSpace;
|
||||
}
|
||||
|
||||
// Do two passes over the flex items to figure out how to distribute the
|
||||
@@ -1356,7 +1207,7 @@ static void distributeFreeSpaceFirstPass(
|
||||
//
|
||||
static void resolveFlexibleLength(
|
||||
yoga::Node* const node,
|
||||
CollectFlexItemsRowValues& collectedFlexItemsValues,
|
||||
FlexLine& flexLine,
|
||||
const YGFlexDirection mainAxis,
|
||||
const YGFlexDirection crossAxis,
|
||||
const float mainAxisownerSize,
|
||||
@@ -1372,10 +1223,10 @@ static void resolveFlexibleLength(
|
||||
void* const layoutContext,
|
||||
const uint32_t depth,
|
||||
const uint32_t generationCount) {
|
||||
const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace;
|
||||
const float originalFreeSpace = flexLine.layout.remainingFreeSpace;
|
||||
// First pass: detect the flex items whose min/max constraints trigger
|
||||
distributeFreeSpaceFirstPass(
|
||||
collectedFlexItemsValues,
|
||||
flexLine,
|
||||
mainAxis,
|
||||
mainAxisownerSize,
|
||||
availableInnerMainDim,
|
||||
@@ -1383,7 +1234,7 @@ static void resolveFlexibleLength(
|
||||
|
||||
// Second pass: resolve the sizes of the flexible items
|
||||
const float distributedFreeSpace = distributeFreeSpaceSecondPass(
|
||||
collectedFlexItemsValues,
|
||||
flexLine,
|
||||
node,
|
||||
mainAxis,
|
||||
crossAxis,
|
||||
@@ -1401,13 +1252,12 @@ static void resolveFlexibleLength(
|
||||
depth,
|
||||
generationCount);
|
||||
|
||||
collectedFlexItemsValues.remainingFreeSpace =
|
||||
originalFreeSpace - distributedFreeSpace;
|
||||
flexLine.layout.remainingFreeSpace = originalFreeSpace - distributedFreeSpace;
|
||||
}
|
||||
|
||||
static void YGJustifyMainAxis(
|
||||
yoga::Node* const node,
|
||||
CollectFlexItemsRowValues& collectedFlexItemsValues,
|
||||
FlexLine& flexLine,
|
||||
const size_t startOfLineIndex,
|
||||
const YGFlexDirection mainAxis,
|
||||
const YGFlexDirection crossAxis,
|
||||
@@ -1429,7 +1279,7 @@ static void YGJustifyMainAxis(
|
||||
// If we are using "at most" rules in the main axis, make sure that
|
||||
// remainingFreeSpace is 0 when min main dimension is not given
|
||||
if (measureModeMainDim == YGMeasureModeAtMost &&
|
||||
collectedFlexItemsValues.remainingFreeSpace > 0) {
|
||||
flexLine.layout.remainingFreeSpace > 0) {
|
||||
if (!style.minDimensions()[dim[mainAxis]].isUndefined() &&
|
||||
!yoga::resolveValue(
|
||||
style.minDimensions()[dim[mainAxis]], mainAxisownerSize)
|
||||
@@ -1447,17 +1297,16 @@ static void YGJustifyMainAxis(
|
||||
.unwrap() -
|
||||
leadingPaddingAndBorderMain - trailingPaddingAndBorderMain;
|
||||
const float occupiedSpaceByChildNodes =
|
||||
availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace;
|
||||
collectedFlexItemsValues.remainingFreeSpace = yoga::maxOrDefined(
|
||||
availableInnerMainDim - flexLine.layout.remainingFreeSpace;
|
||||
flexLine.layout.remainingFreeSpace = yoga::maxOrDefined(
|
||||
0, minAvailableMainDim - occupiedSpaceByChildNodes);
|
||||
} else {
|
||||
collectedFlexItemsValues.remainingFreeSpace = 0;
|
||||
flexLine.layout.remainingFreeSpace = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int numberOfAutoMarginsOnCurrentLine = 0;
|
||||
for (size_t i = startOfLineIndex; i < collectedFlexItemsValues.endOfLineIndex;
|
||||
i++) {
|
||||
for (size_t i = startOfLineIndex; i < flexLine.endOfLineIndex; i++) {
|
||||
auto child = node->getChild(i);
|
||||
if (child->getStyle().positionType() != YGPositionTypeAbsolute) {
|
||||
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
|
||||
@@ -1479,29 +1328,28 @@ static void YGJustifyMainAxis(
|
||||
if (numberOfAutoMarginsOnCurrentLine == 0) {
|
||||
switch (justifyContent) {
|
||||
case YGJustifyCenter:
|
||||
leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
|
||||
leadingMainDim = flexLine.layout.remainingFreeSpace / 2;
|
||||
break;
|
||||
case YGJustifyFlexEnd:
|
||||
leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
|
||||
leadingMainDim = flexLine.layout.remainingFreeSpace;
|
||||
break;
|
||||
case YGJustifySpaceBetween:
|
||||
if (collectedFlexItemsValues.itemsOnLine > 1) {
|
||||
if (flexLine.itemsInFlow.size() > 1) {
|
||||
betweenMainDim +=
|
||||
yoga::maxOrDefined(
|
||||
collectedFlexItemsValues.remainingFreeSpace, 0) /
|
||||
static_cast<float>(collectedFlexItemsValues.itemsOnLine - 1);
|
||||
yoga::maxOrDefined(flexLine.layout.remainingFreeSpace, 0) /
|
||||
static_cast<float>(flexLine.itemsInFlow.size() - 1);
|
||||
}
|
||||
break;
|
||||
case YGJustifySpaceEvenly:
|
||||
// Space is distributed evenly across all elements
|
||||
leadingMainDim = collectedFlexItemsValues.remainingFreeSpace /
|
||||
static_cast<float>(collectedFlexItemsValues.itemsOnLine + 1);
|
||||
leadingMainDim = flexLine.layout.remainingFreeSpace /
|
||||
static_cast<float>(flexLine.itemsInFlow.size() + 1);
|
||||
betweenMainDim += leadingMainDim;
|
||||
break;
|
||||
case YGJustifySpaceAround:
|
||||
// Space on the edges is half of the space between elements
|
||||
leadingMainDim = 0.5f * collectedFlexItemsValues.remainingFreeSpace /
|
||||
static_cast<float>(collectedFlexItemsValues.itemsOnLine);
|
||||
leadingMainDim = 0.5f * flexLine.layout.remainingFreeSpace /
|
||||
static_cast<float>(flexLine.itemsInFlow.size());
|
||||
betweenMainDim += leadingMainDim * 2;
|
||||
break;
|
||||
case YGJustifyFlexStart:
|
||||
@@ -1509,19 +1357,17 @@ static void YGJustifyMainAxis(
|
||||
}
|
||||
}
|
||||
|
||||
collectedFlexItemsValues.mainDim =
|
||||
leadingPaddingAndBorderMain + leadingMainDim;
|
||||
collectedFlexItemsValues.crossDim = 0;
|
||||
flexLine.layout.mainDim = leadingPaddingAndBorderMain + leadingMainDim;
|
||||
flexLine.layout.crossDim = 0;
|
||||
|
||||
float maxAscentForCurrentLine = 0;
|
||||
float maxDescentForCurrentLine = 0;
|
||||
bool isNodeBaselineLayout = isBaselineLayout(node);
|
||||
for (size_t i = startOfLineIndex; i < collectedFlexItemsValues.endOfLineIndex;
|
||||
i++) {
|
||||
for (size_t i = startOfLineIndex; i < flexLine.endOfLineIndex; i++) {
|
||||
const auto child = node->getChild(i);
|
||||
const Style& childStyle = child->getStyle();
|
||||
const LayoutResults& childLayout = child->getLayout();
|
||||
const bool isLastChild = i == collectedFlexItemsValues.endOfLineIndex - 1;
|
||||
const bool isLastChild = i == flexLine.endOfLineIndex - 1;
|
||||
// remove the gap if it is the last element of the line
|
||||
if (isLastChild) {
|
||||
betweenMainDim -= gap;
|
||||
@@ -1548,21 +1394,18 @@ static void YGJustifyMainAxis(
|
||||
// take part in that phase.
|
||||
if (childStyle.positionType() != YGPositionTypeAbsolute) {
|
||||
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
|
||||
collectedFlexItemsValues.mainDim +=
|
||||
collectedFlexItemsValues.remainingFreeSpace /
|
||||
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
|
||||
static_cast<float>(numberOfAutoMarginsOnCurrentLine);
|
||||
}
|
||||
|
||||
if (performLayout) {
|
||||
child->setLayoutPosition(
|
||||
childLayout.position[pos[mainAxis]] +
|
||||
collectedFlexItemsValues.mainDim,
|
||||
childLayout.position[pos[mainAxis]] + flexLine.layout.mainDim,
|
||||
pos[mainAxis]);
|
||||
}
|
||||
|
||||
if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
|
||||
collectedFlexItemsValues.mainDim +=
|
||||
collectedFlexItemsValues.remainingFreeSpace /
|
||||
flexLine.layout.mainDim += flexLine.layout.remainingFreeSpace /
|
||||
static_cast<float>(numberOfAutoMarginsOnCurrentLine);
|
||||
}
|
||||
bool canSkipFlex =
|
||||
@@ -1571,14 +1414,14 @@ static void YGJustifyMainAxis(
|
||||
// If we skipped the flex step, then we can't rely on the measuredDims
|
||||
// because they weren't computed. This means we can't call
|
||||
// dimensionWithMargin.
|
||||
collectedFlexItemsValues.mainDim += betweenMainDim +
|
||||
flexLine.layout.mainDim += betweenMainDim +
|
||||
child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap() +
|
||||
childLayout.computedFlexBasis.unwrap();
|
||||
collectedFlexItemsValues.crossDim = availableInnerCrossDim;
|
||||
flexLine.layout.crossDim = availableInnerCrossDim;
|
||||
} else {
|
||||
// The main dimension is the sum of all the elements dimension plus
|
||||
// the spacing.
|
||||
collectedFlexItemsValues.mainDim += betweenMainDim +
|
||||
flexLine.layout.mainDim += betweenMainDim +
|
||||
dimensionWithMargin(child, mainAxis, availableInnerWidth);
|
||||
|
||||
if (isNodeBaselineLayout) {
|
||||
@@ -1605,8 +1448,8 @@ static void YGJustifyMainAxis(
|
||||
// The cross dimension is the max of the elements dimension since
|
||||
// there can only be one element in that cross dimension in the case
|
||||
// when the items are not baseline aligned
|
||||
collectedFlexItemsValues.crossDim = yoga::maxOrDefined(
|
||||
collectedFlexItemsValues.crossDim,
|
||||
flexLine.layout.crossDim = yoga::maxOrDefined(
|
||||
flexLine.layout.crossDim,
|
||||
dimensionWithMargin(child, crossAxis, availableInnerWidth));
|
||||
}
|
||||
}
|
||||
@@ -1618,10 +1461,10 @@ static void YGJustifyMainAxis(
|
||||
}
|
||||
}
|
||||
}
|
||||
collectedFlexItemsValues.mainDim += trailingPaddingAndBorderMain;
|
||||
flexLine.layout.mainDim += trailingPaddingAndBorderMain;
|
||||
|
||||
if (isNodeBaselineLayout) {
|
||||
collectedFlexItemsValues.crossDim =
|
||||
flexLine.layout.crossDim =
|
||||
maxAscentForCurrentLine + maxDescentForCurrentLine;
|
||||
}
|
||||
}
|
||||
@@ -1918,10 +1761,9 @@ static void calculateLayoutImpl(
|
||||
|
||||
// Max main dimension of all the lines.
|
||||
float maxLineMainDim = 0;
|
||||
CollectFlexItemsRowValues collectedFlexItemsValues;
|
||||
for (; endOfLineIndex < childCount;
|
||||
lineCount++, startOfLineIndex = endOfLineIndex) {
|
||||
collectedFlexItemsValues = calculateCollectFlexItemsRowValues(
|
||||
auto flexLine = calculateFlexLine(
|
||||
node,
|
||||
ownerDirection,
|
||||
mainAxisownerSize,
|
||||
@@ -1929,7 +1771,8 @@ static void calculateLayoutImpl(
|
||||
availableInnerMainDim,
|
||||
startOfLineIndex,
|
||||
lineCount);
|
||||
endOfLineIndex = collectedFlexItemsValues.endOfLineIndex;
|
||||
|
||||
endOfLineIndex = flexLine.endOfLineIndex;
|
||||
|
||||
// If we don't need to measure the cross axis, we can skip the entire flex
|
||||
// step.
|
||||
@@ -1970,29 +1813,25 @@ static void calculateLayoutImpl(
|
||||
isMainAxisRow ? maxInnerWidth : maxInnerHeight;
|
||||
|
||||
if (!yoga::isUndefined(minInnerMainDim) &&
|
||||
collectedFlexItemsValues.sizeConsumedOnCurrentLine <
|
||||
minInnerMainDim) {
|
||||
flexLine.sizeConsumed < minInnerMainDim) {
|
||||
availableInnerMainDim = minInnerMainDim;
|
||||
} else if (
|
||||
!yoga::isUndefined(maxInnerMainDim) &&
|
||||
collectedFlexItemsValues.sizeConsumedOnCurrentLine >
|
||||
maxInnerMainDim) {
|
||||
flexLine.sizeConsumed > maxInnerMainDim) {
|
||||
availableInnerMainDim = maxInnerMainDim;
|
||||
} else {
|
||||
bool useLegacyStretchBehaviour =
|
||||
node->hasErrata(YGErrataStretchFlexBasis);
|
||||
|
||||
if (!useLegacyStretchBehaviour &&
|
||||
((!yoga::isUndefined(
|
||||
collectedFlexItemsValues.totalFlexGrowFactors) &&
|
||||
collectedFlexItemsValues.totalFlexGrowFactors == 0) ||
|
||||
((!yoga::isUndefined(flexLine.layout.totalFlexGrowFactors) &&
|
||||
flexLine.layout.totalFlexGrowFactors == 0) ||
|
||||
(!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
|
||||
// should be shrunk to minimum
|
||||
availableInnerMainDim =
|
||||
collectedFlexItemsValues.sizeConsumedOnCurrentLine;
|
||||
availableInnerMainDim = flexLine.sizeConsumed;
|
||||
}
|
||||
|
||||
sizeBasedOnContent = !useLegacyStretchBehaviour;
|
||||
@@ -2000,21 +1839,20 @@ static void calculateLayoutImpl(
|
||||
}
|
||||
|
||||
if (!sizeBasedOnContent && !yoga::isUndefined(availableInnerMainDim)) {
|
||||
collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
|
||||
collectedFlexItemsValues.sizeConsumedOnCurrentLine;
|
||||
} else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
|
||||
flexLine.layout.remainingFreeSpace =
|
||||
availableInnerMainDim - flexLine.sizeConsumed;
|
||||
} else if (flexLine.sizeConsumed < 0) {
|
||||
// availableInnerMainDim is indefinite which means the node is being sized
|
||||
// based on its content. sizeConsumedOnCurrentLine is negative which means
|
||||
// based on its content. sizeConsumed is negative which means
|
||||
// the node will allocate 0 points for its content. Consequently,
|
||||
// remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
||||
collectedFlexItemsValues.remainingFreeSpace =
|
||||
-collectedFlexItemsValues.sizeConsumedOnCurrentLine;
|
||||
// remainingFreeSpace is 0 - sizeConsumed.
|
||||
flexLine.layout.remainingFreeSpace = -flexLine.sizeConsumed;
|
||||
}
|
||||
|
||||
if (!canSkipFlex) {
|
||||
resolveFlexibleLength(
|
||||
node,
|
||||
collectedFlexItemsValues,
|
||||
flexLine,
|
||||
mainAxis,
|
||||
crossAxis,
|
||||
mainAxisownerSize,
|
||||
@@ -2034,7 +1872,7 @@ static void calculateLayoutImpl(
|
||||
|
||||
node->setLayoutHadOverflow(
|
||||
node->getLayout().hadOverflow() |
|
||||
(collectedFlexItemsValues.remainingFreeSpace < 0));
|
||||
(flexLine.layout.remainingFreeSpace < 0));
|
||||
|
||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||
|
||||
@@ -2045,7 +1883,7 @@ static void calculateLayoutImpl(
|
||||
|
||||
YGJustifyMainAxis(
|
||||
node,
|
||||
collectedFlexItemsValues,
|
||||
flexLine,
|
||||
startOfLineIndex,
|
||||
mainAxis,
|
||||
crossAxis,
|
||||
@@ -2067,7 +1905,7 @@ static void calculateLayoutImpl(
|
||||
boundAxis(
|
||||
node,
|
||||
crossAxis,
|
||||
collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
|
||||
flexLine.layout.crossDim + paddingAndBorderAxisCross,
|
||||
crossAxisownerSize,
|
||||
ownerWidth) -
|
||||
paddingAndBorderAxisCross;
|
||||
@@ -2075,15 +1913,15 @@ static void calculateLayoutImpl(
|
||||
|
||||
// If there's no flex wrap, the cross dimension is defined by the container.
|
||||
if (!isNodeFlexWrap && measureModeCrossDim == YGMeasureModeExactly) {
|
||||
collectedFlexItemsValues.crossDim = availableInnerCrossDim;
|
||||
flexLine.layout.crossDim = availableInnerCrossDim;
|
||||
}
|
||||
|
||||
// Clamp to the min/max size specified on the container.
|
||||
collectedFlexItemsValues.crossDim =
|
||||
flexLine.layout.crossDim =
|
||||
boundAxis(
|
||||
node,
|
||||
crossAxis,
|
||||
collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
|
||||
flexLine.layout.crossDim + paddingAndBorderAxisCross,
|
||||
crossAxisownerSize,
|
||||
ownerWidth) -
|
||||
paddingAndBorderAxisCross;
|
||||
@@ -2148,7 +1986,7 @@ static void calculateLayoutImpl(
|
||||
(isMainAxisRow
|
||||
? childMainSize / childStyle.aspectRatio().unwrap()
|
||||
: childMainSize * childStyle.aspectRatio().unwrap())
|
||||
: collectedFlexItemsValues.crossDim;
|
||||
: flexLine.layout.crossDim;
|
||||
|
||||
childMainSize +=
|
||||
child->getMarginForAxis(mainAxis, availableInnerWidth)
|
||||
@@ -2239,9 +2077,9 @@ static void calculateLayoutImpl(
|
||||
}
|
||||
|
||||
const float appliedCrossGap = lineCount != 0 ? crossAxisGap : 0.0f;
|
||||
totalLineCrossDim += collectedFlexItemsValues.crossDim + appliedCrossGap;
|
||||
totalLineCrossDim += flexLine.layout.crossDim + appliedCrossGap;
|
||||
maxLineMainDim =
|
||||
yoga::maxOrDefined(maxLineMainDim, collectedFlexItemsValues.mainDim);
|
||||
yoga::maxOrDefined(maxLineMainDim, flexLine.layout.mainDim);
|
||||
}
|
||||
|
||||
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
|
||||
|
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* 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 <vector>
|
||||
#include <yoga/node/Node.h>
|
||||
|
||||
namespace facebook::yoga {
|
||||
|
||||
// This struct is an helper model to hold the data for step 4 of flexbox algo,
|
||||
// which is collecting the flex items in a line.
|
||||
//
|
||||
// - itemsOnLine: Number of items which can fit in a line considering the
|
||||
// available Inner dimension, the flex items computed flexbasis and their
|
||||
// margin. It may be different than the difference between start and end
|
||||
// indicates because we skip over absolute-positioned items.
|
||||
//
|
||||
// - sizeConsumedOnCurrentLine: It is accumulation of the dimensions and margin
|
||||
// of all the children on the current line. This will be used in order to
|
||||
// either set the dimensions of the node if none already exist or to compute
|
||||
// the remaining space left for the flexible children.
|
||||
//
|
||||
// - totalFlexGrowFactors: total flex grow factors of flex items which are to be
|
||||
// laid in the current line
|
||||
//
|
||||
// - totalFlexShrinkFactors: total flex shrink factors of flex items which are
|
||||
// to be laid in the current line
|
||||
//
|
||||
// - endOfLineIndex: Its the end index of the last flex item which was examined
|
||||
// and it may or may not be part of the current line(as it may be absolutely
|
||||
// positioned or including it may have caused to overshoot availableInnerDim)
|
||||
//
|
||||
// - relativeChildren: Maintain a vector of the child nodes that can shrink
|
||||
// and/or grow.
|
||||
|
||||
struct CollectFlexItemsRowValues {
|
||||
size_t itemsOnLine;
|
||||
float sizeConsumedOnCurrentLine;
|
||||
float totalFlexGrowFactors;
|
||||
float totalFlexShrinkScaledFactors;
|
||||
size_t endOfLineIndex;
|
||||
std::vector<yoga::Node*> relativeChildren;
|
||||
float remainingFreeSpace;
|
||||
// The size of the mainDim for the row after considering size, padding, margin
|
||||
// and border of flex items. This is used to calculate maxLineDim after going
|
||||
// through all the rows to decide on the main axis size of owner.
|
||||
float mainDim;
|
||||
// The size of the crossDim for the row after considering size, padding,
|
||||
// margin and border of flex items. Used for calculating containers crossSize.
|
||||
float crossDim;
|
||||
};
|
||||
|
||||
} // namespace facebook::yoga
|
107
yoga/algorithm/FlexLine.cpp
Normal file
107
yoga/algorithm/FlexLine.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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 <yoga/Yoga.h>
|
||||
|
||||
#include <yoga/algorithm/BoundAxis.h>
|
||||
#include <yoga/algorithm/FlexDirection.h>
|
||||
#include <yoga/algorithm/FlexLine.h>
|
||||
|
||||
namespace facebook::yoga {
|
||||
|
||||
FlexLine calculateFlexLine(
|
||||
yoga::Node* const node,
|
||||
const YGDirection ownerDirection,
|
||||
const float mainAxisownerSize,
|
||||
const float availableInnerWidth,
|
||||
const float availableInnerMainDim,
|
||||
const size_t startOfLineIndex,
|
||||
const size_t lineCount) {
|
||||
std::vector<yoga::Node*> itemsInFlow;
|
||||
itemsInFlow.reserve(node->getChildren().size());
|
||||
|
||||
float sizeConsumed = 0.0f;
|
||||
float totalFlexGrowFactors = 0.0f;
|
||||
float totalFlexShrinkScaledFactors = 0.0f;
|
||||
size_t endOfLineIndex = startOfLineIndex;
|
||||
|
||||
float sizeConsumedIncludingMinConstraint = 0;
|
||||
const YGFlexDirection mainAxis = resolveDirection(
|
||||
node->getStyle().flexDirection(), node->resolveDirection(ownerDirection));
|
||||
const bool isNodeFlexWrap = node->getStyle().flexWrap() != YGWrapNoWrap;
|
||||
const float gap = node->getGapForAxis(mainAxis, availableInnerWidth).unwrap();
|
||||
|
||||
// Add items to the current line until it's full or we run out of items.
|
||||
for (; endOfLineIndex < node->getChildren().size(); endOfLineIndex++) {
|
||||
auto child = node->getChild(endOfLineIndex);
|
||||
if (child->getStyle().display() == YGDisplayNone ||
|
||||
child->getStyle().positionType() == YGPositionTypeAbsolute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool isFirstElementInLine = (endOfLineIndex - startOfLineIndex) == 0;
|
||||
|
||||
child->setLineIndex(lineCount);
|
||||
const float childMarginMainAxis =
|
||||
child->getMarginForAxis(mainAxis, availableInnerWidth).unwrap();
|
||||
const float childLeadingGapMainAxis = isFirstElementInLine ? 0.0f : gap;
|
||||
const float flexBasisWithMinAndMaxConstraints =
|
||||
boundAxisWithinMinAndMax(
|
||||
child,
|
||||
mainAxis,
|
||||
child->getLayout().computedFlexBasis,
|
||||
mainAxisownerSize)
|
||||
.unwrap();
|
||||
|
||||
// If this is a multi-line flow and this item pushes us over the available
|
||||
// size, we've hit the end of the current line. Break out of the loop and
|
||||
// lay out the current line.
|
||||
if (sizeConsumedIncludingMinConstraint + flexBasisWithMinAndMaxConstraints +
|
||||
childMarginMainAxis + childLeadingGapMainAxis >
|
||||
availableInnerMainDim &&
|
||||
isNodeFlexWrap && itemsInFlow.size() > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
sizeConsumedIncludingMinConstraint += flexBasisWithMinAndMaxConstraints +
|
||||
childMarginMainAxis + childLeadingGapMainAxis;
|
||||
sizeConsumed += flexBasisWithMinAndMaxConstraints + childMarginMainAxis +
|
||||
childLeadingGapMainAxis;
|
||||
|
||||
if (child->isNodeFlexible()) {
|
||||
totalFlexGrowFactors += child->resolveFlexGrow();
|
||||
|
||||
// Unlike the grow factor, the shrink factor is scaled relative to the
|
||||
// child dimension.
|
||||
totalFlexShrinkScaledFactors += -child->resolveFlexShrink() *
|
||||
child->getLayout().computedFlexBasis.unwrap();
|
||||
}
|
||||
|
||||
itemsInFlow.push_back(child);
|
||||
}
|
||||
|
||||
// The total flex factor needs to be floored to 1.
|
||||
if (totalFlexGrowFactors > 0 && totalFlexGrowFactors < 1) {
|
||||
totalFlexGrowFactors = 1;
|
||||
}
|
||||
|
||||
// The total flex shrink factor needs to be floored to 1.
|
||||
if (totalFlexShrinkScaledFactors > 0 && totalFlexShrinkScaledFactors < 1) {
|
||||
totalFlexShrinkScaledFactors = 1;
|
||||
}
|
||||
|
||||
return FlexLine{
|
||||
std::move(itemsInFlow),
|
||||
sizeConsumed,
|
||||
endOfLineIndex,
|
||||
FlexLineRunningLayout{
|
||||
totalFlexGrowFactors,
|
||||
totalFlexShrinkScaledFactors,
|
||||
}};
|
||||
}
|
||||
|
||||
} // namespace facebook::yoga
|
74
yoga/algorithm/FlexLine.h
Normal file
74
yoga/algorithm/FlexLine.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 <vector>
|
||||
|
||||
#include <yoga/Yoga.h>
|
||||
#include <yoga/node/Node.h>
|
||||
|
||||
namespace facebook::yoga {
|
||||
|
||||
struct FlexLineRunningLayout {
|
||||
// Total flex grow factors of flex items which are to be laid in the current
|
||||
// line. This is decremented as free space is distributed.
|
||||
float totalFlexGrowFactors{0.0f};
|
||||
|
||||
// Total flex shrink factors of flex items which are to be laid in the current
|
||||
// line. This is decremented as free space is distributed.
|
||||
float totalFlexShrinkScaledFactors{0.0f};
|
||||
|
||||
// The amount of available space within inner dimensions of the line which may
|
||||
// still be distributed.
|
||||
float remainingFreeSpace{0.0f};
|
||||
|
||||
// The size of the mainDim for the row after considering size, padding, margin
|
||||
// and border of flex items. This is used to calculate maxLineDim after going
|
||||
// through all the rows to decide on the main axis size of owner.
|
||||
float mainDim{0.0f};
|
||||
|
||||
// The size of the crossDim for the row after considering size, padding,
|
||||
// margin and border of flex items. Used for calculating containers crossSize.
|
||||
float crossDim{0.0f};
|
||||
};
|
||||
|
||||
struct FlexLine {
|
||||
// List of children which are part of the line flow. This means they are not
|
||||
// positioned absolutely, or with `display: "none"`, and do not overflow the
|
||||
// available dimensions.
|
||||
const std::vector<yoga::Node*> itemsInFlow{};
|
||||
|
||||
// Accumulation of the dimensions and margin of all the children on the
|
||||
// current line. This will be used in order to either set the dimensions of
|
||||
// the node if none already exist or to compute the remaining space left for
|
||||
// the flexible children.
|
||||
const float sizeConsumed{0.0f};
|
||||
|
||||
// The index of the first item beyond the current line.
|
||||
const size_t endOfLineIndex{0};
|
||||
|
||||
// Layout information about the line computed in steps after line-breaking
|
||||
FlexLineRunningLayout layout{};
|
||||
};
|
||||
|
||||
// Calculates where a line starting at a given index should break, returning
|
||||
// information about the collective children on the liune.
|
||||
//
|
||||
// This function assumes that all the children of node have their
|
||||
// computedFlexBasis properly computed(To do this use
|
||||
// computeFlexBasisForChildren function).
|
||||
FlexLine calculateFlexLine(
|
||||
yoga::Node* const node,
|
||||
YGDirection ownerDirection,
|
||||
float mainAxisownerSize,
|
||||
float availableInnerWidth,
|
||||
float availableInnerMainDim,
|
||||
size_t startOfLineIndex,
|
||||
size_t lineCount);
|
||||
|
||||
} // namespace facebook::yoga
|
Reference in New Issue
Block a user