Reduce search range of flexible children
We were traversing all children to only perform calculations/changes to flexible children in order to avoid new allocations during layout. This diff ensures we only visit flexible children during layout calculations if any are present. We accomplish this by keeping a private linked list of flexible children.
This commit is contained in:
56
src/Layout.c
56
src/Layout.c
@@ -636,11 +636,15 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
|
|||||||
float totalFlexible = 0;
|
float totalFlexible = 0;
|
||||||
int nonFlexibleChildrenCount = 0;
|
int nonFlexibleChildrenCount = 0;
|
||||||
|
|
||||||
|
css_node_t* firstFlexChild = NULL;
|
||||||
|
css_node_t* currentFlexChild = NULL;
|
||||||
|
|
||||||
float maxWidth;
|
float maxWidth;
|
||||||
for (i = startLine; i < childCount; ++i) {
|
for (i = startLine; i < childCount; ++i) {
|
||||||
child = node->get_child(node->context, i);
|
child = node->get_child(node->context, i);
|
||||||
|
|
||||||
child->next_absolute_child = NULL;
|
child->next_absolute_child = NULL;
|
||||||
|
child->next_flex_child = NULL;
|
||||||
|
|
||||||
// Pre-fill cross axis dimensions when the child is using stretch before
|
// Pre-fill cross axis dimensions when the child is using stretch before
|
||||||
// we call the recursive layout pass
|
// we call the recursive layout pass
|
||||||
@@ -694,6 +698,16 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
|
|||||||
flexibleChildrenCount++;
|
flexibleChildrenCount++;
|
||||||
totalFlexible += child->style.flex;
|
totalFlexible += child->style.flex;
|
||||||
|
|
||||||
|
// Store a private linked list of flexible children so that we can
|
||||||
|
// efficiently traverse them later.
|
||||||
|
if (firstFlexChild == NULL) {
|
||||||
|
firstFlexChild = child;
|
||||||
|
}
|
||||||
|
if (currentFlexChild != NULL) {
|
||||||
|
currentFlexChild->next_flex_child = child;
|
||||||
|
}
|
||||||
|
currentFlexChild = child;
|
||||||
|
|
||||||
// Even if we don't know its exact size yet, we already know the padding,
|
// Even if we don't know its exact size yet, we already know the padding,
|
||||||
// border and margin. We'll use this partial information, which represents
|
// border and margin. We'll use this partial information, which represents
|
||||||
// the smallest possible size for the child, to compute the remaining
|
// the smallest possible size for the child, to compute the remaining
|
||||||
@@ -767,21 +781,20 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
|
|||||||
float baseMainDim;
|
float baseMainDim;
|
||||||
float boundMainDim;
|
float boundMainDim;
|
||||||
|
|
||||||
// Iterate over every child in the axis. If the flex share of remaining
|
// If the flex share of remaining space doesn't meet min/max bounds,
|
||||||
// space doesn't meet min/max bounds, remove this child from flex
|
// remove this child from flex calculations.
|
||||||
// calculations.
|
currentFlexChild = firstFlexChild;
|
||||||
for (i = startLine; i < endLine; ++i) {
|
while (currentFlexChild != NULL) {
|
||||||
child = node->get_child(node->context, i);
|
baseMainDim = flexibleMainDim * currentFlexChild->style.flex +
|
||||||
if (isFlex(child)) {
|
getPaddingAndBorderAxis(currentFlexChild, mainAxis);
|
||||||
baseMainDim = flexibleMainDim * child->style.flex +
|
boundMainDim = boundAxis(currentFlexChild, mainAxis, baseMainDim);
|
||||||
getPaddingAndBorderAxis(child, mainAxis);
|
|
||||||
boundMainDim = boundAxis(child, mainAxis, baseMainDim);
|
|
||||||
|
|
||||||
if (baseMainDim != boundMainDim) {
|
if (baseMainDim != boundMainDim) {
|
||||||
remainingMainDim -= boundMainDim;
|
remainingMainDim -= boundMainDim;
|
||||||
totalFlexible -= child->style.flex;
|
totalFlexible -= currentFlexChild->style.flex;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentFlexChild = currentFlexChild->next_flex_child;
|
||||||
}
|
}
|
||||||
flexibleMainDim = remainingMainDim / totalFlexible;
|
flexibleMainDim = remainingMainDim / totalFlexible;
|
||||||
|
|
||||||
@@ -790,16 +803,14 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
|
|||||||
if (flexibleMainDim < 0) {
|
if (flexibleMainDim < 0) {
|
||||||
flexibleMainDim = 0;
|
flexibleMainDim = 0;
|
||||||
}
|
}
|
||||||
// We iterate over the full array and only apply the action on flexible
|
|
||||||
// children. This is faster than actually allocating a new array that
|
currentFlexChild = firstFlexChild;
|
||||||
// contains only flexible children.
|
while (currentFlexChild != NULL) {
|
||||||
for (i = startLine; i < endLine; ++i) {
|
|
||||||
child = node->get_child(node->context, i);
|
|
||||||
if (isFlex(child)) {
|
|
||||||
// At this point we know the final size of the element in the main
|
// At this point we know the final size of the element in the main
|
||||||
// dimension
|
// dimension
|
||||||
child->layout.dimensions[dim[mainAxis]] = boundAxis(child, mainAxis,
|
currentFlexChild->layout.dimensions[dim[mainAxis]] = boundAxis(currentFlexChild, mainAxis,
|
||||||
flexibleMainDim * child->style.flex + getPaddingAndBorderAxis(child, mainAxis)
|
flexibleMainDim * currentFlexChild->style.flex +
|
||||||
|
getPaddingAndBorderAxis(currentFlexChild, mainAxis)
|
||||||
);
|
);
|
||||||
|
|
||||||
maxWidth = CSS_UNDEFINED;
|
maxWidth = CSS_UNDEFINED;
|
||||||
@@ -813,8 +824,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
|
|||||||
}
|
}
|
||||||
|
|
||||||
// And we recursively call the layout algorithm for this child
|
// And we recursively call the layout algorithm for this child
|
||||||
layoutNode(child, maxWidth, direction);
|
layoutNode(currentFlexChild, maxWidth, direction);
|
||||||
}
|
|
||||||
|
child = currentFlexChild;
|
||||||
|
currentFlexChild = currentFlexChild->next_flex_child;
|
||||||
|
child->next_flex_child = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use justifyContent to figure out how to allocate the remaining
|
// We use justifyContent to figure out how to allocate the remaining
|
||||||
|
@@ -137,6 +137,7 @@ struct css_node {
|
|||||||
int line_index;
|
int line_index;
|
||||||
|
|
||||||
css_node_t* next_absolute_child;
|
css_node_t* next_absolute_child;
|
||||||
|
css_node_t* next_flex_child;
|
||||||
|
|
||||||
css_dim_t (*measure)(void *context, float width);
|
css_dim_t (*measure)(void *context, float width);
|
||||||
void (*print)(void *context);
|
void (*print)(void *context);
|
||||||
|
@@ -504,11 +504,15 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ totalFlexible = 0;
|
var/*float*/ totalFlexible = 0;
|
||||||
var/*int*/ nonFlexibleChildrenCount = 0;
|
var/*int*/ nonFlexibleChildrenCount = 0;
|
||||||
|
|
||||||
|
var/*css_node_t**/ firstFlexChild = null;
|
||||||
|
var/*css_node_t**/ currentFlexChild = null;
|
||||||
|
|
||||||
var/*float*/ maxWidth;
|
var/*float*/ maxWidth;
|
||||||
for (i = startLine; i < childCount; ++i) {
|
for (i = startLine; i < childCount; ++i) {
|
||||||
child = node.children[i];
|
child = node.children[i];
|
||||||
|
|
||||||
child.nextAbsoluteChild = null;
|
child.nextAbsoluteChild = null;
|
||||||
|
child.nextFlexChild = null;
|
||||||
|
|
||||||
// Pre-fill cross axis dimensions when the child is using stretch before
|
// Pre-fill cross axis dimensions when the child is using stretch before
|
||||||
// we call the recursive layout pass
|
// we call the recursive layout pass
|
||||||
@@ -562,6 +566,16 @@ var computeLayout = (function() {
|
|||||||
flexibleChildrenCount++;
|
flexibleChildrenCount++;
|
||||||
totalFlexible += child.style.flex;
|
totalFlexible += child.style.flex;
|
||||||
|
|
||||||
|
// Store a private linked list of flexible children so that we can
|
||||||
|
// efficiently traverse them later.
|
||||||
|
if (firstFlexChild === null) {
|
||||||
|
firstFlexChild = child;
|
||||||
|
}
|
||||||
|
if (currentFlexChild !== null) {
|
||||||
|
currentFlexChild.nextFlexChild = child;
|
||||||
|
}
|
||||||
|
currentFlexChild = child;
|
||||||
|
|
||||||
// Even if we don't know its exact size yet, we already know the padding,
|
// Even if we don't know its exact size yet, we already know the padding,
|
||||||
// border and margin. We'll use this partial information, which represents
|
// border and margin. We'll use this partial information, which represents
|
||||||
// the smallest possible size for the child, to compute the remaining
|
// the smallest possible size for the child, to compute the remaining
|
||||||
@@ -635,21 +649,20 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ baseMainDim;
|
var/*float*/ baseMainDim;
|
||||||
var/*float*/ boundMainDim;
|
var/*float*/ boundMainDim;
|
||||||
|
|
||||||
// Iterate over every child in the axis. If the flex share of remaining
|
// If the flex share of remaining space doesn't meet min/max bounds,
|
||||||
// space doesn't meet min/max bounds, remove this child from flex
|
// remove this child from flex calculations.
|
||||||
// calculations.
|
currentFlexChild = firstFlexChild;
|
||||||
for (i = startLine; i < endLine; ++i) {
|
while (currentFlexChild !== null) {
|
||||||
child = node.children[i];
|
baseMainDim = flexibleMainDim * currentFlexChild.style.flex +
|
||||||
if (isFlex(child)) {
|
getPaddingAndBorderAxis(currentFlexChild, mainAxis);
|
||||||
baseMainDim = flexibleMainDim * child.style.flex +
|
boundMainDim = boundAxis(currentFlexChild, mainAxis, baseMainDim);
|
||||||
getPaddingAndBorderAxis(child, mainAxis);
|
|
||||||
boundMainDim = boundAxis(child, mainAxis, baseMainDim);
|
|
||||||
|
|
||||||
if (baseMainDim !== boundMainDim) {
|
if (baseMainDim !== boundMainDim) {
|
||||||
remainingMainDim -= boundMainDim;
|
remainingMainDim -= boundMainDim;
|
||||||
totalFlexible -= child.style.flex;
|
totalFlexible -= currentFlexChild.style.flex;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentFlexChild = currentFlexChild.nextFlexChild;
|
||||||
}
|
}
|
||||||
flexibleMainDim = remainingMainDim / totalFlexible;
|
flexibleMainDim = remainingMainDim / totalFlexible;
|
||||||
|
|
||||||
@@ -658,16 +671,14 @@ var computeLayout = (function() {
|
|||||||
if (flexibleMainDim < 0) {
|
if (flexibleMainDim < 0) {
|
||||||
flexibleMainDim = 0;
|
flexibleMainDim = 0;
|
||||||
}
|
}
|
||||||
// We iterate over the full array and only apply the action on flexible
|
|
||||||
// children. This is faster than actually allocating a new array that
|
currentFlexChild = firstFlexChild;
|
||||||
// contains only flexible children.
|
while (currentFlexChild !== null) {
|
||||||
for (i = startLine; i < endLine; ++i) {
|
|
||||||
child = node.children[i];
|
|
||||||
if (isFlex(child)) {
|
|
||||||
// At this point we know the final size of the element in the main
|
// At this point we know the final size of the element in the main
|
||||||
// dimension
|
// dimension
|
||||||
child.layout[dim[mainAxis]] = boundAxis(child, mainAxis,
|
currentFlexChild.layout[dim[mainAxis]] = boundAxis(currentFlexChild, mainAxis,
|
||||||
flexibleMainDim * child.style.flex + getPaddingAndBorderAxis(child, mainAxis)
|
flexibleMainDim * currentFlexChild.style.flex +
|
||||||
|
getPaddingAndBorderAxis(currentFlexChild, mainAxis)
|
||||||
);
|
);
|
||||||
|
|
||||||
maxWidth = CSS_UNDEFINED;
|
maxWidth = CSS_UNDEFINED;
|
||||||
@@ -681,8 +692,11 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// And we recursively call the layout algorithm for this child
|
// And we recursively call the layout algorithm for this child
|
||||||
layoutNode(/*(java)!layoutContext, */child, maxWidth, direction);
|
layoutNode(/*(java)!layoutContext, */currentFlexChild, maxWidth, direction);
|
||||||
}
|
|
||||||
|
child = currentFlexChild;
|
||||||
|
currentFlexChild = currentFlexChild.nextFlexChild;
|
||||||
|
child.nextFlexChild = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use justifyContent to figure out how to allocate the remaining
|
// We use justifyContent to figure out how to allocate the remaining
|
||||||
|
@@ -64,6 +64,7 @@ public class CSSNode {
|
|||||||
public int lineIndex = 0;
|
public int lineIndex = 0;
|
||||||
|
|
||||||
CSSNode nextAbsoluteChild;
|
CSSNode nextAbsoluteChild;
|
||||||
|
CSSNode nextFlexChild;
|
||||||
|
|
||||||
private @Nullable ArrayList<CSSNode> mChildren;
|
private @Nullable ArrayList<CSSNode> mChildren;
|
||||||
private @Nullable CSSNode mParent;
|
private @Nullable CSSNode mParent;
|
||||||
|
@@ -453,11 +453,15 @@ public class LayoutEngine {
|
|||||||
float totalFlexible = 0;
|
float totalFlexible = 0;
|
||||||
int nonFlexibleChildrenCount = 0;
|
int nonFlexibleChildrenCount = 0;
|
||||||
|
|
||||||
|
CSSNode firstFlexChild = null;
|
||||||
|
CSSNode currentFlexChild = null;
|
||||||
|
|
||||||
float maxWidth;
|
float maxWidth;
|
||||||
for (i = startLine; i < childCount; ++i) {
|
for (i = startLine; i < childCount; ++i) {
|
||||||
child = node.getChildAt(i);
|
child = node.getChildAt(i);
|
||||||
|
|
||||||
child.nextAbsoluteChild = null;
|
child.nextAbsoluteChild = null;
|
||||||
|
child.nextFlexChild = null;
|
||||||
|
|
||||||
// Pre-fill cross axis dimensions when the child is using stretch before
|
// Pre-fill cross axis dimensions when the child is using stretch before
|
||||||
// we call the recursive layout pass
|
// we call the recursive layout pass
|
||||||
@@ -511,6 +515,16 @@ public class LayoutEngine {
|
|||||||
flexibleChildrenCount++;
|
flexibleChildrenCount++;
|
||||||
totalFlexible += child.style.flex;
|
totalFlexible += child.style.flex;
|
||||||
|
|
||||||
|
// Store a private linked list of flexible children so that we can
|
||||||
|
// efficiently traverse them later.
|
||||||
|
if (firstFlexChild == null) {
|
||||||
|
firstFlexChild = child;
|
||||||
|
}
|
||||||
|
if (currentFlexChild != null) {
|
||||||
|
currentFlexChild.nextFlexChild = child;
|
||||||
|
}
|
||||||
|
currentFlexChild = child;
|
||||||
|
|
||||||
// Even if we don't know its exact size yet, we already know the padding,
|
// Even if we don't know its exact size yet, we already know the padding,
|
||||||
// border and margin. We'll use this partial information, which represents
|
// border and margin. We'll use this partial information, which represents
|
||||||
// the smallest possible size for the child, to compute the remaining
|
// the smallest possible size for the child, to compute the remaining
|
||||||
@@ -584,21 +598,20 @@ public class LayoutEngine {
|
|||||||
float baseMainDim;
|
float baseMainDim;
|
||||||
float boundMainDim;
|
float boundMainDim;
|
||||||
|
|
||||||
// Iterate over every child in the axis. If the flex share of remaining
|
// If the flex share of remaining space doesn't meet min/max bounds,
|
||||||
// space doesn't meet min/max bounds, remove this child from flex
|
// remove this child from flex calculations.
|
||||||
// calculations.
|
currentFlexChild = firstFlexChild;
|
||||||
for (i = startLine; i < endLine; ++i) {
|
while (currentFlexChild != null) {
|
||||||
child = node.getChildAt(i);
|
baseMainDim = flexibleMainDim * currentFlexChild.style.flex +
|
||||||
if (isFlex(child)) {
|
getPaddingAndBorderAxis(currentFlexChild, mainAxis);
|
||||||
baseMainDim = flexibleMainDim * child.style.flex +
|
boundMainDim = boundAxis(currentFlexChild, mainAxis, baseMainDim);
|
||||||
getPaddingAndBorderAxis(child, mainAxis);
|
|
||||||
boundMainDim = boundAxis(child, mainAxis, baseMainDim);
|
|
||||||
|
|
||||||
if (baseMainDim != boundMainDim) {
|
if (baseMainDim != boundMainDim) {
|
||||||
remainingMainDim -= boundMainDim;
|
remainingMainDim -= boundMainDim;
|
||||||
totalFlexible -= child.style.flex;
|
totalFlexible -= currentFlexChild.style.flex;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentFlexChild = currentFlexChild.nextFlexChild;
|
||||||
}
|
}
|
||||||
flexibleMainDim = remainingMainDim / totalFlexible;
|
flexibleMainDim = remainingMainDim / totalFlexible;
|
||||||
|
|
||||||
@@ -607,16 +620,14 @@ public class LayoutEngine {
|
|||||||
if (flexibleMainDim < 0) {
|
if (flexibleMainDim < 0) {
|
||||||
flexibleMainDim = 0;
|
flexibleMainDim = 0;
|
||||||
}
|
}
|
||||||
// We iterate over the full array and only apply the action on flexible
|
|
||||||
// children. This is faster than actually allocating a new array that
|
currentFlexChild = firstFlexChild;
|
||||||
// contains only flexible children.
|
while (currentFlexChild != null) {
|
||||||
for (i = startLine; i < endLine; ++i) {
|
|
||||||
child = node.getChildAt(i);
|
|
||||||
if (isFlex(child)) {
|
|
||||||
// At this point we know the final size of the element in the main
|
// At this point we know the final size of the element in the main
|
||||||
// dimension
|
// dimension
|
||||||
child.layout.dimensions[dim[mainAxis]] = boundAxis(child, mainAxis,
|
currentFlexChild.layout.dimensions[dim[mainAxis]] = boundAxis(currentFlexChild, mainAxis,
|
||||||
flexibleMainDim * child.style.flex + getPaddingAndBorderAxis(child, mainAxis)
|
flexibleMainDim * currentFlexChild.style.flex +
|
||||||
|
getPaddingAndBorderAxis(currentFlexChild, mainAxis)
|
||||||
);
|
);
|
||||||
|
|
||||||
maxWidth = CSSConstants.UNDEFINED;
|
maxWidth = CSSConstants.UNDEFINED;
|
||||||
@@ -630,8 +641,11 @@ public class LayoutEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// And we recursively call the layout algorithm for this child
|
// And we recursively call the layout algorithm for this child
|
||||||
layoutNode(layoutContext, child, maxWidth, direction);
|
layoutNode(layoutContext, currentFlexChild, maxWidth, direction);
|
||||||
}
|
|
||||||
|
child = currentFlexChild;
|
||||||
|
currentFlexChild = currentFlexChild.nextFlexChild;
|
||||||
|
child.nextFlexChild = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use justifyContent to figure out how to allocate the remaining
|
// We use justifyContent to figure out how to allocate the remaining
|
||||||
|
@@ -253,6 +253,7 @@ function transpileAnnotatedJStoC(jsCode) {
|
|||||||
.replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]')
|
.replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]')
|
||||||
.replace(/\.lineIndex/g, '.line_index')
|
.replace(/\.lineIndex/g, '.line_index')
|
||||||
.replace(/\.nextAbsoluteChild/g, '.next_absolute_child')
|
.replace(/\.nextAbsoluteChild/g, '.next_absolute_child')
|
||||||
|
.replace(/\.nextFlexChild/g, '.next_flex_child')
|
||||||
.replace(/layout\[dim/g, 'layout.dimensions[dim')
|
.replace(/layout\[dim/g, 'layout.dimensions[dim')
|
||||||
.replace(/layout\[pos/g, 'layout.position[pos')
|
.replace(/layout\[pos/g, 'layout.position[pos')
|
||||||
.replace(/layout\[leading/g, 'layout.position[leading')
|
.replace(/layout\[leading/g, 'layout.position[leading')
|
||||||
@@ -264,6 +265,7 @@ function transpileAnnotatedJStoC(jsCode) {
|
|||||||
.replace(/child\./g, 'child->')
|
.replace(/child\./g, 'child->')
|
||||||
.replace(/parent\./g, 'parent->')
|
.replace(/parent\./g, 'parent->')
|
||||||
.replace(/currentAbsoluteChild\./g, 'currentAbsoluteChild->')
|
.replace(/currentAbsoluteChild\./g, 'currentAbsoluteChild->')
|
||||||
|
.replace(/currentFlexChild\./g, 'currentFlexChild->')
|
||||||
.replace(/getPositionType\((.+?)\)/g, '$1->style.position_type')
|
.replace(/getPositionType\((.+?)\)/g, '$1->style.position_type')
|
||||||
.replace(/getJustifyContent\((.+?)\)/g, '$1->style.justify_content')
|
.replace(/getJustifyContent\((.+?)\)/g, '$1->style.justify_content')
|
||||||
.replace(/getAlignContent\((.+?)\)/g, '$1->style.align_content')
|
.replace(/getAlignContent\((.+?)\)/g, '$1->style.align_content')
|
||||||
|
Reference in New Issue
Block a user