Skip to content

Commit 34b7ec8

Browse files
priteshrnandgaonkarfacebook-github-bot
authored andcommittedFeb 5, 2018
Moved out logic to calculate size consumed on a line into seperate function
Reviewed By: emilsjolander Differential Revision: D6797640 fbshipit-source-id: ad9757e7d603c0ce57f452b1e5c404037605bed9
1 parent 8235a49 commit 34b7ec8

File tree

4 files changed

+187
-109
lines changed

4 files changed

+187
-109
lines changed
 

‎ReactCommon/yoga/yoga/Utils.h

+35
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,41 @@
1111
#include "YGNode.h"
1212
#include "Yoga-internal.h"
1313

14+
// This struct is an helper model to hold the data for step 4 of flexbox
15+
// algo, which is collecting the flex items in a line.
16+
//
17+
// - itemsOnLine: Number of items which can fit in a line considering the
18+
// available Inner dimension, the flex items computed flexbasis and their
19+
// margin. It may be different than the difference between start and end
20+
// indicates because we skip over absolute-positioned items.
21+
//
22+
// - sizeConsumedOnCurrentLine: It is accumulation of the dimensions and margin
23+
// of all the children on the current line. This will be used in order to either
24+
// set the dimensions of the node if none already exist or to compute the
25+
// remaining space left for the flexible children.
26+
//
27+
// - totalFlexGrowFactors: total flex grow factors of flex items which are to be
28+
// layed in the current line
29+
//
30+
// - totalFlexShrinkFactors: total flex shrink factors of flex items which are
31+
// to be layed in the current line
32+
//
33+
// - endOfLineIndex: Its the end index of the last flex item which was examined
34+
// and it may or may not be part of the current line(as it may be absolutely
35+
// positioned or inculding it may have caused to overshoot availableInnerDim)
36+
//
37+
// - relativeChildren: Maintain a vector of the child nodes that can shrink
38+
// and/or grow.
39+
40+
struct YGCollectFlexItemsRowValues {
41+
uint32_t itemsOnLine;
42+
float sizeConsumedOnCurrentLine;
43+
float totalFlexGrowFactors;
44+
float totalFlexShrinkScaledFactors;
45+
float endOfLineIndex;
46+
std::vector<YGNodeRef> relativeChildren;
47+
};
48+
1449
bool YGValueEqual(const YGValue a, const YGValue b);
1550

1651
YGFlexDirection YGFlexDirectionCross(

‎ReactCommon/yoga/yoga/YGNode.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ YGVector YGNode::getChildren() const {
5959
return children_;
6060
}
6161

62+
uint32_t YGNode::getChildrenCount() const {
63+
return static_cast<uint32_t>(children_.size());
64+
}
65+
6266
YGNodeRef YGNode::getChild(uint32_t index) const {
6367
return children_.at(index);
6468
}

‎ReactCommon/yoga/yoga/YGNode.h

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct YGNode {
7272
uint32_t getLineIndex() const;
7373
YGNodeRef getParent() const;
7474
YGVector getChildren() const;
75+
uint32_t getChildrenCount() const;
7576
YGNodeRef getChild(uint32_t index) const;
7677
YGNodeRef getNextChild() const;
7778
YGConfigRef getConfig() const;

‎ReactCommon/yoga/yoga/Yoga.cpp

+147-109
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,88 @@ static void YGNodeComputeFlexBasisForChildren(
16191619
}
16201620
}
16211621

1622+
// This function assumes that all the children of node have their
1623+
// computedFlexBasis properly computed(To do this use
1624+
// YGNodeComputeFlexBasisForChildren function).
1625+
// This function calculates YGCollectFlexItemsRowMeasurement
1626+
static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
1627+
const YGNodeRef& node,
1628+
const YGDirection parentDirection,
1629+
const float mainAxisParentSize,
1630+
const float availableInnerWidth,
1631+
const float availableInnerMainDim,
1632+
const uint32_t startOfLineIndex,
1633+
const uint32_t lineCount) {
1634+
YGCollectFlexItemsRowValues flexAlgoRowMeasurement = {};
1635+
flexAlgoRowMeasurement.relativeChildren.reserve(node->getChildren().size());
1636+
1637+
float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
1638+
const YGFlexDirection mainAxis = YGResolveFlexDirection(
1639+
node->getStyle().flexDirection, node->resolveDirection(parentDirection));
1640+
const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
1641+
1642+
// Add items to the current line until it's full or we run out of items.
1643+
uint32_t endOfLineIndex = startOfLineIndex;
1644+
for (; endOfLineIndex < node->getChildrenCount(); endOfLineIndex++) {
1645+
const YGNodeRef child = node->getChild(endOfLineIndex);
1646+
if (child->getStyle().display == YGDisplayNone ||
1647+
child->getStyle().positionType == YGPositionTypeAbsolute) {
1648+
continue;
1649+
}
1650+
child->setLineIndex(lineCount);
1651+
const float childMarginMainAxis =
1652+
YGNodeMarginForAxis(child, mainAxis, availableInnerWidth);
1653+
const float flexBasisWithMinAndMaxConstraints =
1654+
YGNodeBoundAxisWithinMinAndMax(
1655+
child,
1656+
mainAxis,
1657+
child->getLayout().computedFlexBasis,
1658+
mainAxisParentSize);
1659+
1660+
// If this is a multi-line flow and this item pushes us over the
1661+
// available size, we've
1662+
// hit the end of the current line. Break out of the loop and lay out
1663+
// the current line.
1664+
if (sizeConsumedOnCurrentLineIncludingMinConstraint +
1665+
flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
1666+
availableInnerMainDim &&
1667+
isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) {
1668+
break;
1669+
}
1670+
1671+
sizeConsumedOnCurrentLineIncludingMinConstraint +=
1672+
flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
1673+
flexAlgoRowMeasurement.sizeConsumedOnCurrentLine +=
1674+
flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
1675+
flexAlgoRowMeasurement.itemsOnLine++;
1676+
1677+
if (child->isNodeFlexible()) {
1678+
flexAlgoRowMeasurement.totalFlexGrowFactors += child->resolveFlexGrow();
1679+
1680+
// Unlike the grow factor, the shrink factor is scaled relative to the
1681+
// child dimension.
1682+
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
1683+
-child->resolveFlexShrink() * child->getLayout().computedFlexBasis;
1684+
}
1685+
1686+
flexAlgoRowMeasurement.relativeChildren.push_back(child);
1687+
}
1688+
1689+
// The total flex factor needs to be floored to 1.
1690+
if (flexAlgoRowMeasurement.totalFlexGrowFactors > 0 &&
1691+
flexAlgoRowMeasurement.totalFlexGrowFactors < 1) {
1692+
flexAlgoRowMeasurement.totalFlexGrowFactors = 1;
1693+
}
1694+
1695+
// The total flex shrink factor needs to be floored to 1.
1696+
if (flexAlgoRowMeasurement.totalFlexShrinkScaledFactors > 0 &&
1697+
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors < 1) {
1698+
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors = 1;
1699+
}
1700+
flexAlgoRowMeasurement.endOfLineIndex = endOfLineIndex;
1701+
return flexAlgoRowMeasurement;
1702+
}
1703+
16221704
//
16231705
// This is the main routine that implements a subset of the flexbox layout
16241706
// algorithm
@@ -1803,7 +1885,6 @@ static void YGNodelayoutImpl(const YGNodeRef node,
18031885
YGResolveFlexDirection(node->getStyle().flexDirection, direction);
18041886
const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
18051887
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
1806-
const YGJustify justifyContent = node->getStyle().justifyContent;
18071888
const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
18081889

18091890
const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight;
@@ -1879,9 +1960,10 @@ static void YGNodelayoutImpl(const YGNodeRef node,
18791960
totalOuterFlexBasis);
18801961

18811962
const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
1882-
? false
1883-
: totalOuterFlexBasis > availableInnerMainDim;
1884-
if (isNodeFlexWrap && flexBasisOverflows && measureModeMainDim == YGMeasureModeAtMost) {
1963+
? false
1964+
: totalOuterFlexBasis > availableInnerMainDim;
1965+
if (isNodeFlexWrap && flexBasisOverflows &&
1966+
measureModeMainDim == YGMeasureModeAtMost) {
18851967
measureModeMainDim = YGMeasureModeExactly;
18861968
}
18871969
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
@@ -1898,93 +1980,23 @@ static void YGNodelayoutImpl(const YGNodeRef node,
18981980

18991981
// Max main dimension of all the lines.
19001982
float maxLineMainDim = 0;
1901-
1902-
for (; endOfLineIndex < childCount; lineCount++, startOfLineIndex = endOfLineIndex) {
1903-
// Number of items on the currently line. May be different than the
1904-
// difference
1905-
// between start and end indicates because we skip over absolute-positioned
1906-
// items.
1907-
uint32_t itemsOnLine = 0;
1908-
1909-
// sizeConsumedOnCurrentLine is accumulation of the dimensions and margin
1910-
// of all the children on the current line. This will be used in order to
1911-
// either set the dimensions of the node if none already exist or to compute
1912-
// the remaining space left for the flexible children.
1913-
float sizeConsumedOnCurrentLine = 0;
1914-
float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
1915-
1916-
float totalFlexGrowFactors = 0;
1917-
float totalFlexShrinkScaledFactors = 0;
1918-
1919-
// Maintain a vector of the child nodes that can shrink and/or grow.
1920-
std::vector<YGNodeRef> relativeChildren;
1921-
1922-
// Add items to the current line until it's full or we run out of items.
1923-
for (uint32_t i = startOfLineIndex; i < childCount; i++, endOfLineIndex++) {
1924-
const YGNodeRef child = node->getChild(i);
1925-
if (child->getStyle().display == YGDisplayNone ||
1926-
child->getStyle().positionType == YGPositionTypeAbsolute) {
1927-
continue;
1928-
}
1929-
child->setLineIndex(lineCount);
1930-
const float childMarginMainAxis =
1931-
YGNodeMarginForAxis(child, mainAxis, availableInnerWidth);
1932-
const float flexBasisWithMinAndMaxConstraints =
1933-
YGNodeBoundAxisWithinMinAndMax(
1934-
child,
1935-
mainAxis,
1936-
child->getLayout().computedFlexBasis,
1937-
mainAxisParentSize);
1938-
1939-
// If this is a multi-line flow and this item pushes us over the
1940-
// available size, we've
1941-
// hit the end of the current line. Break out of the loop and lay out
1942-
// the current line.
1943-
if (sizeConsumedOnCurrentLineIncludingMinConstraint +
1944-
flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
1945-
availableInnerMainDim &&
1946-
isNodeFlexWrap && itemsOnLine > 0) {
1947-
break;
1948-
}
1949-
1950-
sizeConsumedOnCurrentLineIncludingMinConstraint +=
1951-
flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
1952-
sizeConsumedOnCurrentLine +=
1953-
flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
1954-
itemsOnLine++;
1955-
1956-
if (child->isNodeFlexible()) {
1957-
totalFlexGrowFactors += child->resolveFlexGrow();
1958-
1959-
// Unlike the grow factor, the shrink factor is scaled relative to the
1960-
// child dimension.
1961-
totalFlexShrinkScaledFactors +=
1962-
-child->resolveFlexShrink() * child->getLayout().computedFlexBasis;
1963-
}
1964-
1965-
// Store a private linked list of children that need to be layed out.
1966-
relativeChildren.push_back(child);
1967-
}
1968-
1969-
// The total flex factor needs to be floored to 1.
1970-
if (totalFlexGrowFactors > 0 && totalFlexGrowFactors < 1) {
1971-
totalFlexGrowFactors = 1;
1972-
}
1973-
1974-
// The total flex shrink factor needs to be floored to 1.
1975-
if (totalFlexShrinkScaledFactors > 0 && totalFlexShrinkScaledFactors < 1) {
1976-
totalFlexShrinkScaledFactors = 1;
1977-
}
1983+
YGCollectFlexItemsRowValues collectedFlexItemsValues;
1984+
for (; endOfLineIndex < childCount;
1985+
lineCount++, startOfLineIndex = endOfLineIndex) {
1986+
collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues(
1987+
node,
1988+
parentDirection,
1989+
mainAxisParentSize,
1990+
availableInnerWidth,
1991+
availableInnerMainDim,
1992+
startOfLineIndex,
1993+
lineCount);
1994+
endOfLineIndex = collectedFlexItemsValues.endOfLineIndex;
19781995

19791996
// If we don't need to measure the cross axis, we can skip the entire flex
19801997
// step.
1981-
const bool canSkipFlex = !performLayout && measureModeCrossDim == YGMeasureModeExactly;
1982-
1983-
// In order to position the elements in the main axis, we have two
1984-
// controls. The space between the beginning and the first element
1985-
// and the space between each two elements.
1986-
float leadingMainDim = 0;
1987-
float betweenMainDim = 0;
1998+
const bool canSkipFlex =
1999+
!performLayout && measureModeCrossDim == YGMeasureModeExactly;
19882000

19892001
// STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
19902002
// Calculate the remaining available space that needs to be allocated.
@@ -1994,18 +2006,24 @@ static void YGNodelayoutImpl(const YGNodeRef node,
19942006
bool sizeBasedOnContent = false;
19952007
// If we don't measure with exact main dimension we want to ensure we don't violate min and max
19962008
if (measureModeMainDim != YGMeasureModeExactly) {
1997-
if (!YGFloatIsUndefined(minInnerMainDim) && sizeConsumedOnCurrentLine < minInnerMainDim) {
2009+
if (!YGFloatIsUndefined(minInnerMainDim) &&
2010+
collectedFlexItemsValues.sizeConsumedOnCurrentLine <
2011+
minInnerMainDim) {
19982012
availableInnerMainDim = minInnerMainDim;
1999-
} else if (!YGFloatIsUndefined(maxInnerMainDim) &&
2000-
sizeConsumedOnCurrentLine > maxInnerMainDim) {
2013+
} else if (
2014+
!YGFloatIsUndefined(maxInnerMainDim) &&
2015+
collectedFlexItemsValues.sizeConsumedOnCurrentLine >
2016+
maxInnerMainDim) {
20012017
availableInnerMainDim = maxInnerMainDim;
20022018
} else {
20032019
if (!node->getConfig()->useLegacyStretchBehaviour &&
2004-
(totalFlexGrowFactors == 0 || node->resolveFlexGrow() == 0)) {
2020+
(collectedFlexItemsValues.totalFlexGrowFactors == 0 ||
2021+
node->resolveFlexGrow() == 0)) {
20052022
// If we don't have any children to flex or we can't flex the node
20062023
// itself, space we've used is all space we need. Root node also
20072024
// should be shrunk to minimum
2008-
availableInnerMainDim = sizeConsumedOnCurrentLine;
2025+
availableInnerMainDim =
2026+
collectedFlexItemsValues.sizeConsumedOnCurrentLine;
20092027
}
20102028

20112029
if (node->getConfig()->useLegacyStretchBehaviour) {
@@ -2017,13 +2035,14 @@ static void YGNodelayoutImpl(const YGNodeRef node,
20172035

20182036
float remainingFreeSpace = 0;
20192037
if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
2020-
remainingFreeSpace = availableInnerMainDim - sizeConsumedOnCurrentLine;
2021-
} else if (sizeConsumedOnCurrentLine < 0) {
2038+
remainingFreeSpace = availableInnerMainDim -
2039+
collectedFlexItemsValues.sizeConsumedOnCurrentLine;
2040+
} else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
20222041
// availableInnerMainDim is indefinite which means the node is being sized based on its
20232042
// content.
20242043
// sizeConsumedOnCurrentLine is negative which means the node will allocate 0 points for
20252044
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
2026-
remainingFreeSpace = -sizeConsumedOnCurrentLine;
2045+
remainingFreeSpace = -collectedFlexItemsValues.sizeConsumedOnCurrentLine;
20272046
}
20282047

20292048
const float originalRemainingFreeSpace = remainingFreeSpace;
@@ -2062,7 +2081,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
20622081
float deltaFlexShrinkScaledFactors = 0;
20632082
float deltaFlexGrowFactors = 0;
20642083

2065-
for (auto currentRelativeChild : relativeChildren) {
2084+
for (auto currentRelativeChild :
2085+
collectedFlexItemsValues.relativeChildren) {
20662086
childFlexBasis = YGNodeBoundAxisWithinMinAndMax(
20672087
currentRelativeChild,
20682088
mainAxis,
@@ -2076,7 +2096,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
20762096
// Is this child able to shrink?
20772097
if (flexShrinkScaledFactor != 0) {
20782098
baseMainSize = childFlexBasis +
2079-
remainingFreeSpace / totalFlexShrinkScaledFactors *
2099+
remainingFreeSpace /
2100+
collectedFlexItemsValues.totalFlexShrinkScaledFactors *
20802101
flexShrinkScaledFactor;
20812102
boundMainSize = YGNodeBoundAxis(
20822103
currentRelativeChild,
@@ -2101,7 +2122,9 @@ static void YGNodelayoutImpl(const YGNodeRef node,
21012122
// Is this child able to grow?
21022123
if (flexGrowFactor != 0) {
21032124
baseMainSize = childFlexBasis +
2104-
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor;
2125+
remainingFreeSpace /
2126+
collectedFlexItemsValues.totalFlexGrowFactors *
2127+
flexGrowFactor;
21052128
boundMainSize = YGNodeBoundAxis(
21062129
currentRelativeChild,
21072130
mainAxis,
@@ -2125,13 +2148,15 @@ static void YGNodelayoutImpl(const YGNodeRef node,
21252148
currentRelativeChild = currentRelativeChild->getNextChild();
21262149
}
21272150

2128-
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
2129-
totalFlexGrowFactors += deltaFlexGrowFactors;
2151+
collectedFlexItemsValues.totalFlexShrinkScaledFactors +=
2152+
deltaFlexShrinkScaledFactors;
2153+
collectedFlexItemsValues.totalFlexGrowFactors += deltaFlexGrowFactors;
21302154
remainingFreeSpace += deltaFreeSpace;
21312155

21322156
// Second pass: resolve the sizes of the flexible items
21332157
deltaFreeSpace = 0;
2134-
for (auto currentRelativeChild : relativeChildren) {
2158+
for (auto currentRelativeChild :
2159+
collectedFlexItemsValues.relativeChildren) {
21352160
childFlexBasis = YGNodeBoundAxisWithinMinAndMax(
21362161
currentRelativeChild,
21372162
mainAxis,
@@ -2146,11 +2171,12 @@ static void YGNodelayoutImpl(const YGNodeRef node,
21462171
if (flexShrinkScaledFactor != 0) {
21472172
float childSize;
21482173

2149-
if (totalFlexShrinkScaledFactors == 0) {
2174+
if (collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
21502175
childSize = childFlexBasis + flexShrinkScaledFactor;
21512176
} else {
21522177
childSize = childFlexBasis +
2153-
(remainingFreeSpace / totalFlexShrinkScaledFactors) *
2178+
(remainingFreeSpace /
2179+
collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
21542180
flexShrinkScaledFactor;
21552181
}
21562182

@@ -2170,7 +2196,9 @@ static void YGNodelayoutImpl(const YGNodeRef node,
21702196
currentRelativeChild,
21712197
mainAxis,
21722198
childFlexBasis +
2173-
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor,
2199+
remainingFreeSpace /
2200+
collectedFlexItemsValues.totalFlexGrowFactors *
2201+
flexGrowFactor,
21742202
availableInnerMainDim,
21752203
availableInnerWidth);
21762204
}
@@ -2333,6 +2361,13 @@ static void YGNodelayoutImpl(const YGNodeRef node,
23332361
}
23342362
}
23352363

2364+
// In order to position the elements in the main axis, we have two
2365+
// controls. The space between the beginning and the first element
2366+
// and the space between each two elements.
2367+
float leadingMainDim = 0;
2368+
float betweenMainDim = 0;
2369+
const YGJustify justifyContent = node->getStyle().justifyContent;
2370+
23362371
if (numberOfAutoMarginsOnCurrentLine == 0) {
23372372
switch (justifyContent) {
23382373
case YGJustifyCenter:
@@ -2342,20 +2377,23 @@ static void YGNodelayoutImpl(const YGNodeRef node,
23422377
leadingMainDim = remainingFreeSpace;
23432378
break;
23442379
case YGJustifySpaceBetween:
2345-
if (itemsOnLine > 1) {
2346-
betweenMainDim = fmaxf(remainingFreeSpace, 0) / (itemsOnLine - 1);
2380+
if (collectedFlexItemsValues.itemsOnLine > 1) {
2381+
betweenMainDim = fmaxf(remainingFreeSpace, 0) /
2382+
(collectedFlexItemsValues.itemsOnLine - 1);
23472383
} else {
23482384
betweenMainDim = 0;
23492385
}
23502386
break;
23512387
case YGJustifySpaceEvenly:
23522388
// Space is distributed evenly across all elements
2353-
betweenMainDim = remainingFreeSpace / (itemsOnLine + 1);
2389+
betweenMainDim =
2390+
remainingFreeSpace / (collectedFlexItemsValues.itemsOnLine + 1);
23542391
leadingMainDim = betweenMainDim;
23552392
break;
23562393
case YGJustifySpaceAround:
23572394
// Space on the edges is half of the space between elements
2358-
betweenMainDim = remainingFreeSpace / itemsOnLine;
2395+
betweenMainDim =
2396+
remainingFreeSpace / collectedFlexItemsValues.itemsOnLine;
23592397
leadingMainDim = betweenMainDim / 2;
23602398
break;
23612399
case YGJustifyFlexStart:

0 commit comments

Comments
 (0)
Please sign in to comment.