Refactored step3 of flexbox algorithm

Reviewed By: emilsjolander

Differential Revision: D6702749

fbshipit-source-id: 15dcc94ae30ac185e4d1c7d6e3744a40cfa47317
This commit is contained in:
Pritesh Nandgaonkar 2018-01-15 10:09:40 -08:00 committed by Facebook Github Bot
parent ac1c8c265e
commit fcf2c7cf61
1 changed files with 111 additions and 74 deletions

View File

@ -1590,6 +1590,87 @@ static float YGNodeCalculateAvailableInnerDim(
return availableInnerDim;
}
static void YGNodeComputeFlexBasisForChildren(
const YGNodeRef node,
const float availableInnerWidth,
const float availableInnerHeight,
YGMeasureMode widthMeasureMode,
YGMeasureMode heightMeasureMode,
YGDirection direction,
YGFlexDirection mainAxis,
const YGConfigRef config,
bool performLayout,
float& totalOuterFlexBasis) {
YGNodeRef singleFlexChild = nullptr;
YGVector children = node->getChildren();
YGMeasureMode measureModeMainDim =
YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode;
// If there is only one child with flexGrow + flexShrink it means we can set
// the computedFlexBasis to 0 instead of measuring and shrinking / flexing the
// child to exactly match the remaining space
if (measureModeMainDim == YGMeasureModeExactly) {
for (auto child : children) {
if (singleFlexChild != nullptr) {
if (YGNodeIsFlex(child)) {
// There is already a flexible child, abort
singleFlexChild = nullptr;
break;
}
} else if (
child->resolveFlexGrow() > 0.0f &&
child->resolveFlexShrink() > 0.0f) {
singleFlexChild = child;
}
}
}
for (auto child : children) {
child->resolveDimension();
if (child->getStyle().display == YGDisplayNone) {
YGZeroOutLayoutRecursivly(child);
child->setHasNewLayout(true);
child->setDirty(false);
continue;
}
if (child->getStyle().positionType == YGPositionTypeAbsolute) {
continue;
}
if (performLayout) {
// Set the initial position (relative to the parent).
const YGDirection childDirection =
YGNodeResolveDirection(child, direction);
const float mainDim = YGFlexDirectionIsRow(mainAxis)
? availableInnerWidth
: availableInnerHeight;
const float crossDim = YGFlexDirectionIsRow(mainAxis)
? availableInnerHeight
: availableInnerWidth;
child->setPosition(
childDirection, mainDim, crossDim, availableInnerWidth);
}
if (child == singleFlexChild) {
child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
child->setLayoutComputedFlexBasis(0);
} else {
YGNodeComputeFlexBasisForChild(
node,
child,
availableInnerWidth,
widthMeasureMode,
availableInnerHeight,
availableInnerWidth,
availableInnerHeight,
heightMeasureMode,
direction,
config);
}
totalOuterFlexBasis += child->getLayout().computedFlexBasis +
YGNodeMarginForAxis(child, mainAxis, availableInnerWidth);
;
}
}
//
// This is the main routine that implements a subset of the flexbox layout
// algorithm
@ -1827,59 +1908,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
// STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
node, YGFlexDirectionRow, availableWidth, parentWidth);
float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
node, YGFlexDirectionColumn, availableHeight, parentHeight);
float availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight;
const float availableInnerCrossDim = isMainAxisRow ? availableInnerHeight : availableInnerWidth;
// If there is only one child with flexGrow + flexShrink it means we can set the
// computedFlexBasis to 0 instead of measuring and shrinking / flexing the child to exactly
// match the remaining space
YGNodeRef singleFlexChild = nullptr;
if (measureModeMainDim == YGMeasureModeExactly) {
for (uint32_t i = 0; i < childCount; i++) {
const YGNodeRef child = YGNodeGetChild(node, i);
if (singleFlexChild) {
if (YGNodeIsFlex(child)) {
// There is already a flexible child, abort.
singleFlexChild = nullptr;
break;
}
} else if (
child->resolveFlexGrow() > 0.0f &&
child->resolveFlexShrink() > 0.0f) {
singleFlexChild = child;
}
}
}
float totalOuterFlexBasis = 0;
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
for (uint32_t i = 0; i < childCount; i++) {
const YGNodeRef child = node->getChild(i);
if (child->getStyle().display == YGDisplayNone) {
YGZeroOutLayoutRecursivly(child);
child->setHasNewLayout(true);
child->setDirty(false);
continue;
}
child->resolveDimension();
if (performLayout) {
// Set the initial position (relative to the parent).
const YGDirection childDirection = YGNodeResolveDirection(child, direction);
child->setPosition(
childDirection,
availableInnerMainDim,
availableInnerCrossDim,
availableInnerWidth);
}
// Make a private linkedlist of absolutely positioned child
for (auto child : node->getChildren()) {
// Absolute-positioned children don't participate in flex layout. Add them
// to a list that we can process later.
if (child->getStyle().positionType == YGPositionTypeAbsolute) {
@ -1893,36 +1923,43 @@ static void YGNodelayoutImpl(const YGNodeRef node,
}
currentAbsoluteChild = child;
child->setNextChild(nullptr);
} else {
if (child == singleFlexChild) {
child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
child->setLayoutComputedFlexBasis(0);
} else {
YGNodeComputeFlexBasisForChild(node,
child,
availableInnerWidth,
widthMeasureMode,
availableInnerHeight,
availableInnerWidth,
availableInnerHeight,
heightMeasureMode,
direction,
config);
}
}
totalOuterFlexBasis += child->getLayout().computedFlexBasis +
YGNodeMarginForAxis(child, mainAxis, availableInnerWidth);
;
}
// STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
node, YGFlexDirectionRow, availableWidth, parentWidth);
float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
node, YGFlexDirectionColumn, availableHeight, parentHeight);
float availableInnerMainDim =
isMainAxisRow ? availableInnerWidth : availableInnerHeight;
const float availableInnerCrossDim =
isMainAxisRow ? availableInnerHeight : availableInnerWidth;
float totalOuterFlexBasis = 0;
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
YGNodeComputeFlexBasisForChildren(
node,
availableInnerWidth,
availableInnerHeight,
widthMeasureMode,
heightMeasureMode,
direction,
mainAxis,
config,
performLayout,
totalOuterFlexBasis);
const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
? false
: totalOuterFlexBasis > availableInnerMainDim;
if (isNodeFlexWrap && flexBasisOverflows && measureModeMainDim == YGMeasureModeAtMost) {
measureModeMainDim = YGMeasureModeExactly;
}
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
// Indexes of children that represent the first and last items in the line.