Replaced first pass with a function

Reviewed By: emilsjolander

Differential Revision: D6819719

fbshipit-source-id: e5e77c21d1dca2255433da3388887d9db3f7b642
This commit is contained in:
Pritesh Nandgaonkar 2018-02-05 06:33:01 -08:00 committed by Facebook Github Bot
parent 34b7ec82b5
commit fda861a889
2 changed files with 119 additions and 99 deletions

View File

@ -44,6 +44,7 @@ struct YGCollectFlexItemsRowValues {
float totalFlexShrinkScaledFactors; float totalFlexShrinkScaledFactors;
float endOfLineIndex; float endOfLineIndex;
std::vector<YGNodeRef> relativeChildren; std::vector<YGNodeRef> relativeChildren;
float remainingFreeSpace;
}; };
bool YGValueEqual(const YGValue a, const YGValue b); bool YGValueEqual(const YGValue a, const YGValue b);

View File

@ -1701,6 +1701,87 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
return flexAlgoRowMeasurement; return flexAlgoRowMeasurement;
} }
// It distributes the free space to the flexible items, for those flexible items
// whose min and max constraints are triggered, the clamped size is removed from
// the remaingfreespace.
static void YGDistributeFreeSpaceFirstPass(
YGCollectFlexItemsRowValues& collectedFlexItemsValues,
const YGFlexDirection mainAxis,
const float mainAxisParentSize,
const float availableInnerMainDim,
const float availableInnerWidth) {
float flexShrinkScaledFactor = 0;
float flexGrowFactor = 0;
float baseMainSize = 0;
float boundMainSize = 0;
float deltaFreeSpace = 0;
for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
float childFlexBasis = YGNodeBoundAxisWithinMinAndMax(
currentRelativeChild,
mainAxis,
currentRelativeChild->getLayout().computedFlexBasis,
mainAxisParentSize);
if (collectedFlexItemsValues.remainingFreeSpace < 0) {
flexShrinkScaledFactor =
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
// Is this child able to shrink?
if (flexShrinkScaledFactor != 0) {
baseMainSize = childFlexBasis +
collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexShrinkScaledFactors *
flexShrinkScaledFactor;
boundMainSize = YGNodeBoundAxis(
currentRelativeChild,
mainAxis,
baseMainSize,
availableInnerMainDim,
availableInnerWidth);
if (baseMainSize != boundMainSize) {
// By excluding this item's size and flex factor from remaining,
// this item's
// min/max constraints should also trigger in the second pass
// resulting in the
// item's size calculation being identical in the first and second
// passes.
deltaFreeSpace += boundMainSize - childFlexBasis;
collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
flexShrinkScaledFactor;
}
}
} else if (collectedFlexItemsValues.remainingFreeSpace > 0) {
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
// Is this child able to grow?
if (flexGrowFactor != 0) {
baseMainSize = childFlexBasis +
collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
boundMainSize = YGNodeBoundAxis(
currentRelativeChild,
mainAxis,
baseMainSize,
availableInnerMainDim,
availableInnerWidth);
if (baseMainSize != boundMainSize) {
// By excluding this item's size and flex factor from remaining,
// this item's
// min/max constraints should also trigger in the second pass
// resulting in the
// item's size calculation being identical in the first and second
// passes.
deltaFreeSpace += boundMainSize - childFlexBasis;
collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
}
}
}
}
collectedFlexItemsValues.remainingFreeSpace -= deltaFreeSpace;
}
// //
// This is the main routine that implements a subset of the flexbox layout // This is the main routine that implements a subset of the flexbox layout
// algorithm // algorithm
@ -2033,27 +2114,26 @@ static void YGNodelayoutImpl(const YGNodeRef node,
} }
} }
float remainingFreeSpace = 0;
if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) { if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
remainingFreeSpace = availableInnerMainDim - collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
collectedFlexItemsValues.sizeConsumedOnCurrentLine; collectedFlexItemsValues.sizeConsumedOnCurrentLine;
} else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) { } else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
// availableInnerMainDim is indefinite which means the node is being sized based on its // availableInnerMainDim is indefinite which means the node is being sized based on its
// content. // content.
// sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for // sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine. // its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
remainingFreeSpace = -collectedFlexItemsValues.sizeConsumedOnCurrentLine; collectedFlexItemsValues.remainingFreeSpace =
-collectedFlexItemsValues.sizeConsumedOnCurrentLine;
} }
const float originalRemainingFreeSpace = remainingFreeSpace; const float originalRemainingFreeSpace =
collectedFlexItemsValues.remainingFreeSpace;
float deltaFreeSpace = 0; float deltaFreeSpace = 0;
if (!canSkipFlex) { if (!canSkipFlex) {
float childFlexBasis; float childFlexBasis;
float flexShrinkScaledFactor; float flexShrinkScaledFactor;
float flexGrowFactor; float flexGrowFactor;
float baseMainSize;
float boundMainSize;
// Do two passes over the flex items to figure out how to distribute the // Do two passes over the flex items to figure out how to distribute the
// remaining space. // remaining space.
@ -2078,80 +2158,12 @@ static void YGNodelayoutImpl(const YGNodeRef node,
// concerns because we know exactly how many passes it'll do. // concerns because we know exactly how many passes it'll do.
// First pass: detect the flex items whose min/max constraints trigger // First pass: detect the flex items whose min/max constraints trigger
float deltaFlexShrinkScaledFactors = 0; YGDistributeFreeSpaceFirstPass(
float deltaFlexGrowFactors = 0; collectedFlexItemsValues,
mainAxis,
for (auto currentRelativeChild : mainAxisParentSize,
collectedFlexItemsValues.relativeChildren) { availableInnerMainDim,
childFlexBasis = YGNodeBoundAxisWithinMinAndMax( availableInnerWidth);
currentRelativeChild,
mainAxis,
currentRelativeChild->getLayout().computedFlexBasis,
mainAxisParentSize);
if (remainingFreeSpace < 0) {
flexShrinkScaledFactor =
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
// Is this child able to shrink?
if (flexShrinkScaledFactor != 0) {
baseMainSize = childFlexBasis +
remainingFreeSpace /
collectedFlexItemsValues.totalFlexShrinkScaledFactors *
flexShrinkScaledFactor;
boundMainSize = YGNodeBoundAxis(
currentRelativeChild,
mainAxis,
baseMainSize,
availableInnerMainDim,
availableInnerWidth);
if (baseMainSize != boundMainSize) {
// By excluding this item's size and flex factor from remaining,
// this item's
// min/max constraints should also trigger in the second pass
// resulting in the
// item's size calculation being identical in the first and second
// passes.
deltaFreeSpace -= boundMainSize - childFlexBasis;
deltaFlexShrinkScaledFactors -= flexShrinkScaledFactor;
}
}
} else if (remainingFreeSpace > 0) {
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
// Is this child able to grow?
if (flexGrowFactor != 0) {
baseMainSize = childFlexBasis +
remainingFreeSpace /
collectedFlexItemsValues.totalFlexGrowFactors *
flexGrowFactor;
boundMainSize = YGNodeBoundAxis(
currentRelativeChild,
mainAxis,
baseMainSize,
availableInnerMainDim,
availableInnerWidth);
if (baseMainSize != boundMainSize) {
// By excluding this item's size and flex factor from remaining,
// this item's
// min/max constraints should also trigger in the second pass
// resulting in the
// item's size calculation being identical in the first and second
// passes.
deltaFreeSpace -= boundMainSize - childFlexBasis;
deltaFlexGrowFactors -= flexGrowFactor;
}
}
}
currentRelativeChild = currentRelativeChild->getNextChild();
}
collectedFlexItemsValues.totalFlexShrinkScaledFactors +=
deltaFlexShrinkScaledFactors;
collectedFlexItemsValues.totalFlexGrowFactors += deltaFlexGrowFactors;
remainingFreeSpace += deltaFreeSpace;
// Second pass: resolve the sizes of the flexible items // Second pass: resolve the sizes of the flexible items
deltaFreeSpace = 0; deltaFreeSpace = 0;
@ -2164,7 +2176,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
mainAxisParentSize); mainAxisParentSize);
float updatedMainSize = childFlexBasis; float updatedMainSize = childFlexBasis;
if (remainingFreeSpace < 0) { if (collectedFlexItemsValues.remainingFreeSpace < 0) {
flexShrinkScaledFactor = flexShrinkScaledFactor =
-currentRelativeChild->resolveFlexShrink() * childFlexBasis; -currentRelativeChild->resolveFlexShrink() * childFlexBasis;
// Is this child able to shrink? // Is this child able to shrink?
@ -2175,7 +2187,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
childSize = childFlexBasis + flexShrinkScaledFactor; childSize = childFlexBasis + flexShrinkScaledFactor;
} else { } else {
childSize = childFlexBasis + childSize = childFlexBasis +
(remainingFreeSpace / (collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexShrinkScaledFactors) * collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
flexShrinkScaledFactor; flexShrinkScaledFactor;
} }
@ -2187,7 +2199,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerMainDim, availableInnerMainDim,
availableInnerWidth); availableInnerWidth);
} }
} else if (remainingFreeSpace > 0) { } else if (collectedFlexItemsValues.remainingFreeSpace > 0) {
flexGrowFactor = currentRelativeChild->resolveFlexGrow(); flexGrowFactor = currentRelativeChild->resolveFlexGrow();
// Is this child able to grow? // Is this child able to grow?
@ -2196,7 +2208,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
currentRelativeChild, currentRelativeChild,
mainAxis, mainAxis,
childFlexBasis + childFlexBasis +
remainingFreeSpace / collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexGrowFactors * collectedFlexItemsValues.totalFlexGrowFactors *
flexGrowFactor, flexGrowFactor,
availableInnerMainDim, availableInnerMainDim,
@ -2315,9 +2327,11 @@ static void YGNodelayoutImpl(const YGNodeRef node,
} }
} }
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace; collectedFlexItemsValues.remainingFreeSpace =
originalRemainingFreeSpace + deltaFreeSpace;
node->setLayoutHadOverflow( node->setLayoutHadOverflow(
node->getLayout().hadOverflow | (remainingFreeSpace < 0)); node->getLayout().hadOverflow |
(collectedFlexItemsValues.remainingFreeSpace < 0));
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION // STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
@ -2331,20 +2345,22 @@ static void YGNodelayoutImpl(const YGNodeRef node,
// If we are using "at most" rules in the main axis. Calculate the remaining space when // If we are using "at most" rules in the main axis. Calculate the remaining space when
// constraint by the min size defined for the main axis. // constraint by the min size defined for the main axis.
if (measureModeMainDim == YGMeasureModeAtMost && remainingFreeSpace > 0) { if (measureModeMainDim == YGMeasureModeAtMost &&
collectedFlexItemsValues.remainingFreeSpace > 0) {
if (node->getStyle().minDimensions[dim[mainAxis]].unit != if (node->getStyle().minDimensions[dim[mainAxis]].unit !=
YGUnitUndefined && YGUnitUndefined &&
YGResolveValue( YGResolveValue(
node->getStyle().minDimensions[dim[mainAxis]], node->getStyle().minDimensions[dim[mainAxis]],
mainAxisParentSize) >= 0) { mainAxisParentSize) >= 0) {
remainingFreeSpace = fmaxf( collectedFlexItemsValues.remainingFreeSpace = fmaxf(
0, 0,
YGResolveValue( YGResolveValue(
node->getStyle().minDimensions[dim[mainAxis]], node->getStyle().minDimensions[dim[mainAxis]],
mainAxisParentSize) - mainAxisParentSize) -
(availableInnerMainDim - remainingFreeSpace)); (availableInnerMainDim -
collectedFlexItemsValues.remainingFreeSpace));
} else { } else {
remainingFreeSpace = 0; collectedFlexItemsValues.remainingFreeSpace = 0;
} }
} }
@ -2371,14 +2387,15 @@ static void YGNodelayoutImpl(const YGNodeRef node,
if (numberOfAutoMarginsOnCurrentLine == 0) { if (numberOfAutoMarginsOnCurrentLine == 0) {
switch (justifyContent) { switch (justifyContent) {
case YGJustifyCenter: case YGJustifyCenter:
leadingMainDim = remainingFreeSpace / 2; leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
break; break;
case YGJustifyFlexEnd: case YGJustifyFlexEnd:
leadingMainDim = remainingFreeSpace; leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
break; break;
case YGJustifySpaceBetween: case YGJustifySpaceBetween:
if (collectedFlexItemsValues.itemsOnLine > 1) { if (collectedFlexItemsValues.itemsOnLine > 1) {
betweenMainDim = fmaxf(remainingFreeSpace, 0) / betweenMainDim =
fmaxf(collectedFlexItemsValues.remainingFreeSpace, 0) /
(collectedFlexItemsValues.itemsOnLine - 1); (collectedFlexItemsValues.itemsOnLine - 1);
} else { } else {
betweenMainDim = 0; betweenMainDim = 0;
@ -2386,14 +2403,14 @@ static void YGNodelayoutImpl(const YGNodeRef node,
break; break;
case YGJustifySpaceEvenly: case YGJustifySpaceEvenly:
// Space is distributed evenly across all elements // Space is distributed evenly across all elements
betweenMainDim = betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
remainingFreeSpace / (collectedFlexItemsValues.itemsOnLine + 1); (collectedFlexItemsValues.itemsOnLine + 1);
leadingMainDim = betweenMainDim; leadingMainDim = betweenMainDim;
break; break;
case YGJustifySpaceAround: case YGJustifySpaceAround:
// Space on the edges is half of the space between elements // Space on the edges is half of the space between elements
betweenMainDim = betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
remainingFreeSpace / collectedFlexItemsValues.itemsOnLine; collectedFlexItemsValues.itemsOnLine;
leadingMainDim = betweenMainDim / 2; leadingMainDim = betweenMainDim / 2;
break; break;
case YGJustifyFlexStart: case YGJustifyFlexStart:
@ -2427,7 +2444,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
// do not take part in that phase. // do not take part in that phase.
if (child->getStyle().positionType == YGPositionTypeRelative) { if (child->getStyle().positionType == YGPositionTypeRelative) {
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) { if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine; mainDim += collectedFlexItemsValues.remainingFreeSpace /
numberOfAutoMarginsOnCurrentLine;
} }
if (performLayout) { if (performLayout) {
@ -2437,7 +2455,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
} }
if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) { if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine; mainDim += collectedFlexItemsValues.remainingFreeSpace /
numberOfAutoMarginsOnCurrentLine;
} }
if (canSkipFlex) { if (canSkipFlex) {