mirror of
https://github.com/status-im/react-native.git
synced 2025-02-28 17:10:50 +00:00
Add support for flex-grow, flex-shrink, and flex-basis
Reviewed By: lucasr Differential Revision: D3714520 fbshipit-source-id: 80d3a9a1e2b6f74b863bbe22357f2c9865fa290e
This commit is contained in:
parent
451cc2dee7
commit
0ea4198009
@ -33,7 +33,7 @@ typedef struct CSSLayout {
|
|||||||
float dimensions[2];
|
float dimensions[2];
|
||||||
CSSDirection direction;
|
CSSDirection direction;
|
||||||
|
|
||||||
float flexBasis;
|
float computedFlexBasis;
|
||||||
|
|
||||||
// Instead of recomputing the entire layout every single time, we
|
// Instead of recomputing the entire layout every single time, we
|
||||||
// cache some information to break early when nothing changed
|
// cache some information to break early when nothing changed
|
||||||
@ -57,7 +57,9 @@ typedef struct CSSStyle {
|
|||||||
CSSPositionType positionType;
|
CSSPositionType positionType;
|
||||||
CSSWrapType flexWrap;
|
CSSWrapType flexWrap;
|
||||||
CSSOverflow overflow;
|
CSSOverflow overflow;
|
||||||
float flex;
|
float flexGrow;
|
||||||
|
float flexShrink;
|
||||||
|
float flexBasis;
|
||||||
float margin[6];
|
float margin[6];
|
||||||
float position[6];
|
float position[6];
|
||||||
/**
|
/**
|
||||||
|
@ -23,8 +23,6 @@ __forceinline const float fmaxf(const float a, const float b) {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define POSITIVE_FLEX_IS_AUTO 0
|
|
||||||
|
|
||||||
CSSNodeRef CSSNodeNew() {
|
CSSNodeRef CSSNodeNew() {
|
||||||
CSSNodeRef node = calloc(1, sizeof(CSSNode));
|
CSSNodeRef node = calloc(1, sizeof(CSSNode));
|
||||||
CSS_ASSERT(node, "Could not allocate memory for node");
|
CSS_ASSERT(node, "Could not allocate memory for node");
|
||||||
@ -44,6 +42,10 @@ void CSSNodeInit(CSSNodeRef node) {
|
|||||||
node->hasNewLayout = true;
|
node->hasNewLayout = true;
|
||||||
node->isDirty = false;
|
node->isDirty = false;
|
||||||
|
|
||||||
|
node->style.flexGrow = 0;
|
||||||
|
node->style.flexShrink = 0;
|
||||||
|
node->style.flexBasis = CSSUndefined;
|
||||||
|
|
||||||
node->style.alignItems = CSSAlignStretch;
|
node->style.alignItems = CSSAlignStretch;
|
||||||
node->style.alignContent = CSSAlignFlexStart;
|
node->style.alignContent = CSSAlignFlexStart;
|
||||||
|
|
||||||
@ -130,6 +132,32 @@ bool CSSNodeIsDirty(CSSNodeRef node) {
|
|||||||
return node->isDirty;
|
return node->isDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSSNodeStyleSetFlex(CSSNodeRef node, float flex) {
|
||||||
|
if (CSSValueIsUndefined(flex) || flex == 0) {
|
||||||
|
CSSNodeStyleSetFlexGrow(node, 0);
|
||||||
|
CSSNodeStyleSetFlexShrink(node, 0);
|
||||||
|
CSSNodeStyleSetFlexBasis(node, CSSUndefined);
|
||||||
|
} else if (flex > 0) {
|
||||||
|
CSSNodeStyleSetFlexGrow(node, flex);
|
||||||
|
CSSNodeStyleSetFlexShrink(node, 0);
|
||||||
|
CSSNodeStyleSetFlexBasis(node, 0);
|
||||||
|
} else {
|
||||||
|
CSSNodeStyleSetFlexGrow(node, 0);
|
||||||
|
CSSNodeStyleSetFlexShrink(node, -flex);
|
||||||
|
CSSNodeStyleSetFlexBasis(node, CSSUndefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float CSSNodeStyleGetFlex(CSSNodeRef node) {
|
||||||
|
if (node->style.flexGrow > 0) {
|
||||||
|
return node->style.flexGrow;
|
||||||
|
} else if (node->style.flexShrink > 0) {
|
||||||
|
return -node->style.flexShrink;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define CSS_NODE_PROPERTY_IMPL(type, name, paramName, instanceName) \
|
#define CSS_NODE_PROPERTY_IMPL(type, name, paramName, instanceName) \
|
||||||
void CSSNodeSet##name(CSSNodeRef node, type paramName) { \
|
void CSSNodeSet##name(CSSNodeRef node, type paramName) { \
|
||||||
node->instanceName = paramName; \
|
node->instanceName = paramName; \
|
||||||
@ -171,7 +199,9 @@ CSS_NODE_STYLE_PROPERTY_IMPL(CSSAlign, AlignSelf, alignSelf, alignSelf);
|
|||||||
CSS_NODE_STYLE_PROPERTY_IMPL(CSSPositionType, PositionType, positionType, positionType);
|
CSS_NODE_STYLE_PROPERTY_IMPL(CSSPositionType, PositionType, positionType, positionType);
|
||||||
CSS_NODE_STYLE_PROPERTY_IMPL(CSSWrapType, FlexWrap, flexWrap, flexWrap);
|
CSS_NODE_STYLE_PROPERTY_IMPL(CSSWrapType, FlexWrap, flexWrap, flexWrap);
|
||||||
CSS_NODE_STYLE_PROPERTY_IMPL(CSSOverflow, Overflow, overflow, overflow);
|
CSS_NODE_STYLE_PROPERTY_IMPL(CSSOverflow, Overflow, overflow, overflow);
|
||||||
CSS_NODE_STYLE_PROPERTY_IMPL(float, Flex, flex, flex);
|
CSS_NODE_STYLE_PROPERTY_IMPL(float, FlexGrow, flexGrow, flexGrow);
|
||||||
|
CSS_NODE_STYLE_PROPERTY_IMPL(float, FlexShrink, flexShrink, flexShrink);
|
||||||
|
CSS_NODE_STYLE_PROPERTY_IMPL(float, FlexBasis, flexBasis, flexBasis);
|
||||||
|
|
||||||
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionLeft, positionLeft, position[CSSPositionLeft]);
|
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionLeft, positionLeft, position[CSSPositionLeft]);
|
||||||
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionTop, positionTop, position[CSSPositionTop]);
|
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionTop, positionTop, position[CSSPositionTop]);
|
||||||
@ -324,7 +354,9 @@ static void print_css_node_rec(CSSNode *node, CSSPrintOptions options, uint32_t
|
|||||||
printf("alignSelf: 'stretch', ");
|
printf("alignSelf: 'stretch', ");
|
||||||
}
|
}
|
||||||
|
|
||||||
print_number_nan("flex", node->style.flex);
|
print_number_nan("flexGrow", node->style.flexGrow);
|
||||||
|
print_number_nan("flexShrink", node->style.flexShrink);
|
||||||
|
print_number_nan("flexBasis", node->style.flexBasis);
|
||||||
|
|
||||||
if (node->style.overflow == CSSOverflowHidden) {
|
if (node->style.overflow == CSSOverflowHidden) {
|
||||||
printf("overflow: 'hidden', ");
|
printf("overflow: 'hidden', ");
|
||||||
@ -432,40 +464,6 @@ static bool isColumnDirection(CSSFlexDirection flexDirection) {
|
|||||||
return flexDirection == CSSFlexDirectionColumn || flexDirection == CSSFlexDirectionColumnReverse;
|
return flexDirection == CSSFlexDirectionColumn || flexDirection == CSSFlexDirectionColumnReverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isFlexBasisAuto(CSSNode *node) {
|
|
||||||
#if POSITIVE_FLEX_IS_AUTO
|
|
||||||
// All flex values are auto.
|
|
||||||
(void) node;
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
// A flex value > 0 implies a basis of zero.
|
|
||||||
return node->style.flex <= 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getFlexGrowFactor(CSSNode *node) {
|
|
||||||
// Flex grow is implied by positive values for flex.
|
|
||||||
if (node->style.flex > 0) {
|
|
||||||
return node->style.flex;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getFlexShrinkFactor(CSSNode *node) {
|
|
||||||
#if POSITIVE_FLEX_IS_AUTO
|
|
||||||
// A flex shrink factor of 1 is implied by non-zero values for flex.
|
|
||||||
if (node->style.flex != 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// A flex shrink factor of 1 is implied by negative values for flex.
|
|
||||||
if (node->style.flex < 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getLeadingMargin(CSSNode *node, CSSFlexDirection axis) {
|
static float getLeadingMargin(CSSNode *node, CSSFlexDirection axis) {
|
||||||
if (isRowDirection(axis) && !CSSValueIsUndefined(node->style.margin[CSSPositionStart])) {
|
if (isRowDirection(axis) && !CSSValueIsUndefined(node->style.margin[CSSPositionStart])) {
|
||||||
return node->style.margin[CSSPositionStart];
|
return node->style.margin[CSSPositionStart];
|
||||||
@ -592,12 +590,9 @@ static CSSFlexDirection getCrossFlexDirection(CSSFlexDirection flexDirection,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static float getFlex(CSSNode *node) {
|
|
||||||
return node->style.flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isFlex(CSSNode *node) {
|
static bool isFlex(CSSNode *node) {
|
||||||
return (node->style.positionType == CSSPositionTypeRelative && getFlex(node) != 0);
|
return (node->style.positionType == CSSPositionTypeRelative &&
|
||||||
|
(node->style.flexGrow != 0 || node->style.flexShrink != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isFlexWrap(CSSNode *node) {
|
static bool isFlexWrap(CSSNode *node) {
|
||||||
@ -1022,15 +1017,18 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
} else {
|
} else {
|
||||||
if (isMainAxisRow && isStyleDimDefined(child, CSSFlexDirectionRow)) {
|
if (isMainAxisRow && isStyleDimDefined(child, CSSFlexDirectionRow)) {
|
||||||
// The width is definite, so use that as the flex basis.
|
// The width is definite, so use that as the flex basis.
|
||||||
child->layout.flexBasis = fmaxf(child->style.dimensions[CSSDimensionWidth],
|
child->layout.computedFlexBasis =
|
||||||
getPaddingAndBorderAxis(child, CSSFlexDirectionRow));
|
fmaxf(child->style.dimensions[CSSDimensionWidth],
|
||||||
|
getPaddingAndBorderAxis(child, CSSFlexDirectionRow));
|
||||||
} else if (!isMainAxisRow && isStyleDimDefined(child, CSSFlexDirectionColumn)) {
|
} else if (!isMainAxisRow && isStyleDimDefined(child, CSSFlexDirectionColumn)) {
|
||||||
// The height is definite, so use that as the flex basis.
|
// The height is definite, so use that as the flex basis.
|
||||||
child->layout.flexBasis = fmaxf(child->style.dimensions[CSSDimensionHeight],
|
child->layout.computedFlexBasis =
|
||||||
getPaddingAndBorderAxis(child, CSSFlexDirectionColumn));
|
fmaxf(child->style.dimensions[CSSDimensionHeight],
|
||||||
} else if (!isFlexBasisAuto(child) && !CSSValueIsUndefined(availableInnerMainDim)) {
|
getPaddingAndBorderAxis(child, CSSFlexDirectionColumn));
|
||||||
// If the basis isn't 'auto', it is assumed to be zero.
|
} else if (!CSSValueIsUndefined(child->style.flexBasis) &&
|
||||||
child->layout.flexBasis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
!CSSValueIsUndefined(availableInnerMainDim)) {
|
||||||
|
child->layout.computedFlexBasis =
|
||||||
|
fmaxf(child->style.flexBasis, getPaddingAndBorderAxis(child, mainAxis));
|
||||||
} else {
|
} else {
|
||||||
// Compute the flex basis and hypothetical main size (i.e. the clamped
|
// Compute the flex basis and hypothetical main size (i.e. the clamped
|
||||||
// flex basis).
|
// flex basis).
|
||||||
@ -1098,7 +1096,7 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
false,
|
false,
|
||||||
"measure");
|
"measure");
|
||||||
|
|
||||||
child->layout.flexBasis =
|
child->layout.computedFlexBasis =
|
||||||
fmaxf(isMainAxisRow ? child->layout.measuredDimensions[CSSDimensionWidth]
|
fmaxf(isMainAxisRow ? child->layout.measuredDimensions[CSSDimensionWidth]
|
||||||
: child->layout.measuredDimensions[CSSDimensionHeight],
|
: child->layout.measuredDimensions[CSSDimensionHeight],
|
||||||
getPaddingAndBorderAxis(child, mainAxis));
|
getPaddingAndBorderAxis(child, mainAxis));
|
||||||
@ -1149,7 +1147,7 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
child->lineIndex = lineCount;
|
child->lineIndex = lineCount;
|
||||||
|
|
||||||
if (child->style.positionType != CSSPositionTypeAbsolute) {
|
if (child->style.positionType != CSSPositionTypeAbsolute) {
|
||||||
float outerFlexBasis = child->layout.flexBasis + getMarginAxis(child, mainAxis);
|
float outerFlexBasis = child->layout.computedFlexBasis + getMarginAxis(child, mainAxis);
|
||||||
|
|
||||||
// If this is a multi-line flow and this item pushes us over the
|
// If this is a multi-line flow and this item pushes us over the
|
||||||
// available size, we've
|
// available size, we've
|
||||||
@ -1164,12 +1162,13 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
itemsOnLine++;
|
itemsOnLine++;
|
||||||
|
|
||||||
if (isFlex(child)) {
|
if (isFlex(child)) {
|
||||||
totalFlexGrowFactors += getFlexGrowFactor(child);
|
totalFlexGrowFactors += child->style.flexGrow;
|
||||||
|
|
||||||
// Unlike the grow factor, the shrink factor is scaled relative to the
|
// Unlike the grow factor, the shrink factor is scaled relative to the
|
||||||
// child
|
// child
|
||||||
// dimension.
|
// dimension.
|
||||||
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child->layout.flexBasis;
|
totalFlexShrinkScaledFactors +=
|
||||||
|
-child->style.flexShrink * child->layout.computedFlexBasis;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store a private linked list of children that need to be layed out.
|
// Store a private linked list of children that need to be layed out.
|
||||||
@ -1252,10 +1251,10 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
float deltaFlexGrowFactors = 0;
|
float deltaFlexGrowFactors = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
while (currentRelativeChild != NULL) {
|
while (currentRelativeChild != NULL) {
|
||||||
childFlexBasis = currentRelativeChild->layout.flexBasis;
|
childFlexBasis = currentRelativeChild->layout.computedFlexBasis;
|
||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = -currentRelativeChild->style.flexShrink * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
@ -1275,7 +1274,7 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (remainingFreeSpace > 0) {
|
} else if (remainingFreeSpace > 0) {
|
||||||
flexGrowFactor = getFlexGrowFactor(currentRelativeChild);
|
flexGrowFactor = currentRelativeChild->style.flexGrow;
|
||||||
|
|
||||||
// Is this child able to grow?
|
// Is this child able to grow?
|
||||||
if (flexGrowFactor != 0) {
|
if (flexGrowFactor != 0) {
|
||||||
@ -1306,11 +1305,11 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
deltaFreeSpace = 0;
|
deltaFreeSpace = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
while (currentRelativeChild != NULL) {
|
while (currentRelativeChild != NULL) {
|
||||||
childFlexBasis = currentRelativeChild->layout.flexBasis;
|
childFlexBasis = currentRelativeChild->layout.computedFlexBasis;
|
||||||
float updatedMainSize = childFlexBasis;
|
float updatedMainSize = childFlexBasis;
|
||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = -currentRelativeChild->style.flexShrink * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
@ -1321,7 +1320,7 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
flexShrinkScaledFactor);
|
flexShrinkScaledFactor);
|
||||||
}
|
}
|
||||||
} else if (remainingFreeSpace > 0) {
|
} else if (remainingFreeSpace > 0) {
|
||||||
flexGrowFactor = getFlexGrowFactor(currentRelativeChild);
|
flexGrowFactor = currentRelativeChild->style.flexGrow;
|
||||||
|
|
||||||
// Is this child able to grow?
|
// Is this child able to grow?
|
||||||
if (flexGrowFactor != 0) {
|
if (flexGrowFactor != 0) {
|
||||||
@ -1463,7 +1462,8 @@ static void layoutNodeImpl(CSSNode *node,
|
|||||||
// If we skipped the flex step, then we can't rely on the
|
// If we skipped the flex step, then we can't rely on the
|
||||||
// measuredDims because
|
// measuredDims because
|
||||||
// they weren't computed. This means we can't call getDimWithMargin.
|
// they weren't computed. This means we can't call getDimWithMargin.
|
||||||
mainDim += betweenMainDim + getMarginAxis(child, mainAxis) + child->layout.flexBasis;
|
mainDim +=
|
||||||
|
betweenMainDim + getMarginAxis(child, mainAxis) + child->layout.computedFlexBasis;
|
||||||
crossDim = availableInnerCrossDim;
|
crossDim = availableInnerCrossDim;
|
||||||
} else {
|
} else {
|
||||||
// The main dimension is the sum of all the elements dimension plus
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
|
@ -174,6 +174,9 @@ CSS_NODE_STYLE_PROPERTY(CSSPositionType, PositionType, positionType);
|
|||||||
CSS_NODE_STYLE_PROPERTY(CSSWrapType, FlexWrap, flexWrap);
|
CSS_NODE_STYLE_PROPERTY(CSSWrapType, FlexWrap, flexWrap);
|
||||||
CSS_NODE_STYLE_PROPERTY(CSSOverflow, Overflow, overflow);
|
CSS_NODE_STYLE_PROPERTY(CSSOverflow, Overflow, overflow);
|
||||||
CSS_NODE_STYLE_PROPERTY(float, Flex, flex);
|
CSS_NODE_STYLE_PROPERTY(float, Flex, flex);
|
||||||
|
CSS_NODE_STYLE_PROPERTY(float, FlexGrow, flexGrow);
|
||||||
|
CSS_NODE_STYLE_PROPERTY(float, FlexShrink, flexShrink);
|
||||||
|
CSS_NODE_STYLE_PROPERTY(float, FlexBasis, flexBasis);
|
||||||
|
|
||||||
CSS_NODE_STYLE_PROPERTY(float, PositionLeft, positionLeft);
|
CSS_NODE_STYLE_PROPERTY(float, PositionLeft, positionLeft);
|
||||||
CSS_NODE_STYLE_PROPERTY(float, PositionTop, positionTop);
|
CSS_NODE_STYLE_PROPERTY(float, PositionTop, positionTop);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user