Add fast path for simple stack layouts

Change the initial line loop to opportunistically position children in
the in container with simple stacking params i.e. vertical/horizontal
stacking on non-flexible STRETCH/FLEX_START aligned. This allows us to
skip the main and cross axis loops (Loop C and D, respectively)
partially and even completely in many common scenarios.

In my benchamrks, this gives us about ~15% performance win in many
setups.
This commit is contained in:
Lucas Rocha
2015-09-09 11:05:20 +01:00
parent 2d869489ef
commit 765ff8463e
3 changed files with 201 additions and 24 deletions

View File

@@ -590,6 +590,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
bool isNodeFlexWrap = isFlexWrap(node);
css_justify_t justifyContent = node->style.justify_content;
float leadingPaddingAndBorderMain = getLeadingPaddingAndBorder(node, mainAxis);
float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
@@ -636,19 +638,41 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
float totalFlexible = 0;
int nonFlexibleChildrenCount = 0;
// Use the line loop to position children in the main axis for as long
// as they are using a simple stacking behaviour. Children that are
// immediately stacked in the initial loop will not be touched again
// in <Loop C>.
bool isSimpleStackMain =
(isMainDimDefined && justifyContent == CSS_JUSTIFY_FLEX_START) ||
(!isMainDimDefined && justifyContent != CSS_JUSTIFY_CENTER);
int firstComplexMain = (isSimpleStackMain ? childCount : startLine);
// Use the initial line loop to position children in the cross axis for
// as long as they are relatively positioned with alignment STRETCH or
// FLEX_START. Children that are immediately stacked in the initial loop
// will not be touched again in <Loop D>.
bool isSimpleStackCross = true;
int firstComplexCross = childCount;
css_node_t* firstFlexChild = NULL;
css_node_t* currentFlexChild = NULL;
float mainDim = leadingPaddingAndBorderMain;
float crossDim = 0;
float maxWidth;
for (i = startLine; i < childCount; ++i) {
child = node->get_child(node->context, i);
child->line_index = linesCount;
child->next_absolute_child = NULL;
child->next_flex_child = NULL;
css_align_t alignItem = getAlignItem(node, child);
// Pre-fill cross axis dimensions when the child is using stretch before
// we call the recursive layout pass
if (getAlignItem(node, child) == CSS_ALIGN_STRETCH &&
if (alignItem == CSS_ALIGN_STRETCH &&
child->style.position_type == CSS_POSITION_RELATIVE &&
isCrossDimDefined &&
!isDimDefined(child, crossAxis)) {
@@ -753,6 +777,44 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
alreadyComputedNextLayout = 1;
break;
}
// Disable simple stacking in the main axis for the current line as
// we found a non-trivial child-> The remaining children will be laid out
// in <Loop C>.
if (isSimpleStackMain &&
(child->style.position_type != CSS_POSITION_RELATIVE || isFlex(child))) {
isSimpleStackMain = false;
firstComplexMain = i;
}
// Disable simple stacking in the cross axis for the current line as
// we found a non-trivial child-> The remaining children will be laid out
// in <Loop D>.
if (isSimpleStackCross &&
(child->style.position_type != CSS_POSITION_RELATIVE ||
(alignItem != CSS_ALIGN_STRETCH && alignItem != CSS_ALIGN_FLEX_START) ||
isUndefined(child->layout.dimensions[dim[crossAxis]]))) {
isSimpleStackCross = false;
firstComplexCross = i;
}
if (isSimpleStackMain) {
child->layout.position[pos[mainAxis]] += mainDim;
if (isMainDimDefined) {
setTrailingPosition(node, child, mainAxis);
}
mainDim += getDimWithMargin(child, mainAxis);
crossDim = fmaxf(crossDim, boundAxis(child, crossAxis, getDimWithMargin(child, crossAxis)));
}
if (isSimpleStackCross) {
child->layout.position[pos[crossAxis]] += linesCrossDim + leadingPaddingAndBorderCross;
if (isCrossDimDefined) {
setTrailingPosition(node, child, crossAxis);
}
}
alreadyComputedNextLayout = 0;
mainContentDim += nextContentDim;
endLine = i + 1;
@@ -833,8 +895,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
// We use justifyContent to figure out how to allocate the remaining
// space available
} else if (node->style.justify_content != CSS_JUSTIFY_FLEX_START) {
css_justify_t justifyContent = node->style.justify_content;
} else if (justifyContent != CSS_JUSTIFY_FLEX_START) {
if (justifyContent == CSS_JUSTIFY_CENTER) {
leadingMainDim = remainingMainDim / 2;
} else if (justifyContent == CSS_JUSTIFY_FLEX_END) {
@@ -861,12 +922,10 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
// find their position. In order to do that, we accumulate data in
// variables that are also useful to compute the total dimensions of the
// container!
float crossDim = 0;
float mainDim = leadingMainDim + leadingPaddingAndBorderMain;
mainDim += leadingMainDim;
for (i = startLine; i < endLine; ++i) {
for (i = firstComplexMain; i < endLine; ++i) {
child = node->get_child(node->context, i);
child->line_index = linesCount;
if (child->style.position_type == CSS_POSITION_ABSOLUTE &&
isPosDefined(child, leading[mainAxis])) {
@@ -912,7 +971,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
}
// <Loop D> Position elements in the cross axis
for (i = startLine; i < endLine; ++i) {
for (i = firstComplexCross; i < endLine; ++i) {
child = node->get_child(node->context, i);
if (child->style.position_type == CSS_POSITION_ABSOLUTE &&