Skip to content

Commit

Permalink
Replaced first pass with a function
Browse files Browse the repository at this point in the history
Reviewed By: emilsjolander

Differential Revision: D6819719

fbshipit-source-id: e5e77c21d1dca2255433da3388887d9db3f7b642
  • Loading branch information
priteshrnandgaonkar authored and facebook-github-bot committed Feb 5, 2018
1 parent 34b7ec8 commit fda861a
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 99 deletions.
1 change: 1 addition & 0 deletions ReactCommon/yoga/yoga/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct YGCollectFlexItemsRowValues {
float totalFlexShrinkScaledFactors;
float endOfLineIndex;
std::vector<YGNodeRef> relativeChildren;
float remainingFreeSpace;
};

bool YGValueEqual(const YGValue a, const YGValue b);
Expand Down
217 changes: 118 additions & 99 deletions ReactCommon/yoga/yoga/Yoga.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,87 @@ static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
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
// algorithm
Expand Down Expand Up @@ -2033,27 +2114,26 @@ static void YGNodelayoutImpl(const YGNodeRef node,
}
}

float remainingFreeSpace = 0;
if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
remainingFreeSpace = availableInnerMainDim -
collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
collectedFlexItemsValues.sizeConsumedOnCurrentLine;
} else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
// availableInnerMainDim is indefinite which means the node is being sized based on its
// content.
// sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for
// 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;

if (!canSkipFlex) {
float childFlexBasis;
float flexShrinkScaledFactor;
float flexGrowFactor;
float baseMainSize;
float boundMainSize;

// Do two passes over the flex items to figure out how to distribute the
// remaining space.
Expand All @@ -2078,80 +2158,12 @@ static void YGNodelayoutImpl(const YGNodeRef node,
// concerns because we know exactly how many passes it'll do.

// First pass: detect the flex items whose min/max constraints trigger
float deltaFlexShrinkScaledFactors = 0;
float deltaFlexGrowFactors = 0;

for (auto currentRelativeChild :
collectedFlexItemsValues.relativeChildren) {
childFlexBasis = YGNodeBoundAxisWithinMinAndMax(
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;
YGDistributeFreeSpaceFirstPass(
collectedFlexItemsValues,
mainAxis,
mainAxisParentSize,
availableInnerMainDim,
availableInnerWidth);

// Second pass: resolve the sizes of the flexible items
deltaFreeSpace = 0;
Expand All @@ -2164,7 +2176,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
mainAxisParentSize);
float updatedMainSize = childFlexBasis;

if (remainingFreeSpace < 0) {
if (collectedFlexItemsValues.remainingFreeSpace < 0) {
flexShrinkScaledFactor =
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
// Is this child able to shrink?
Expand All @@ -2175,7 +2187,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
childSize = childFlexBasis + flexShrinkScaledFactor;
} else {
childSize = childFlexBasis +
(remainingFreeSpace /
(collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
flexShrinkScaledFactor;
}
Expand All @@ -2187,7 +2199,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
availableInnerMainDim,
availableInnerWidth);
}
} else if (remainingFreeSpace > 0) {
} else if (collectedFlexItemsValues.remainingFreeSpace > 0) {
flexGrowFactor = currentRelativeChild->resolveFlexGrow();

// Is this child able to grow?
Expand All @@ -2196,7 +2208,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
currentRelativeChild,
mainAxis,
childFlexBasis +
remainingFreeSpace /
collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.totalFlexGrowFactors *
flexGrowFactor,
availableInnerMainDim,
Expand Down Expand Up @@ -2315,9 +2327,11 @@ static void YGNodelayoutImpl(const YGNodeRef node,
}
}

remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
collectedFlexItemsValues.remainingFreeSpace =
originalRemainingFreeSpace + deltaFreeSpace;
node->setLayoutHadOverflow(
node->getLayout().hadOverflow | (remainingFreeSpace < 0));
node->getLayout().hadOverflow |
(collectedFlexItemsValues.remainingFreeSpace < 0));

// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION

Expand All @@ -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
// 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 !=
YGUnitUndefined &&
YGResolveValue(
node->getStyle().minDimensions[dim[mainAxis]],
mainAxisParentSize) >= 0) {
remainingFreeSpace = fmaxf(
collectedFlexItemsValues.remainingFreeSpace = fmaxf(
0,
YGResolveValue(
node->getStyle().minDimensions[dim[mainAxis]],
mainAxisParentSize) -
(availableInnerMainDim - remainingFreeSpace));
(availableInnerMainDim -
collectedFlexItemsValues.remainingFreeSpace));
} else {
remainingFreeSpace = 0;
collectedFlexItemsValues.remainingFreeSpace = 0;
}
}

Expand All @@ -2371,29 +2387,30 @@ static void YGNodelayoutImpl(const YGNodeRef node,
if (numberOfAutoMarginsOnCurrentLine == 0) {
switch (justifyContent) {
case YGJustifyCenter:
leadingMainDim = remainingFreeSpace / 2;
leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
break;
case YGJustifyFlexEnd:
leadingMainDim = remainingFreeSpace;
leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
break;
case YGJustifySpaceBetween:
if (collectedFlexItemsValues.itemsOnLine > 1) {
betweenMainDim = fmaxf(remainingFreeSpace, 0) /
betweenMainDim =
fmaxf(collectedFlexItemsValues.remainingFreeSpace, 0) /
(collectedFlexItemsValues.itemsOnLine - 1);
} else {
betweenMainDim = 0;
}
break;
case YGJustifySpaceEvenly:
// Space is distributed evenly across all elements
betweenMainDim =
remainingFreeSpace / (collectedFlexItemsValues.itemsOnLine + 1);
betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
(collectedFlexItemsValues.itemsOnLine + 1);
leadingMainDim = betweenMainDim;
break;
case YGJustifySpaceAround:
// Space on the edges is half of the space between elements
betweenMainDim =
remainingFreeSpace / collectedFlexItemsValues.itemsOnLine;
betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
collectedFlexItemsValues.itemsOnLine;
leadingMainDim = betweenMainDim / 2;
break;
case YGJustifyFlexStart:
Expand Down Expand Up @@ -2427,7 +2444,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
// do not take part in that phase.
if (child->getStyle().positionType == YGPositionTypeRelative) {
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine;
mainDim += collectedFlexItemsValues.remainingFreeSpace /
numberOfAutoMarginsOnCurrentLine;
}

if (performLayout) {
Expand All @@ -2437,7 +2455,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
}

if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine;
mainDim += collectedFlexItemsValues.remainingFreeSpace /
numberOfAutoMarginsOnCurrentLine;
}

if (canSkipFlex) {
Expand Down

0 comments on commit fda861a

Please sign in to comment.