Merge pull request #196 from emilsjolander/styling
Remove whitespace on empty lines etc.
This commit is contained in:
@@ -150,7 +150,7 @@ module.exports = function(grunt) {
|
|||||||
command: 'xbuild /verbosity:m /nologo src/csharp/Facebook.CSSLayout.sln /p:Configuration=Release /t:"Facebook_CSSLayout:Rebuild;Facebook_CSSLayout_Tests:Rebuild"'
|
command: 'xbuild /verbosity:m /nologo src/csharp/Facebook.CSSLayout.sln /p:Configuration=Release /t:"Facebook_CSSLayout:Rebuild;Facebook_CSSLayout_Tests:Rebuild"'
|
||||||
},
|
},
|
||||||
csharpTestExecute: {
|
csharpTestExecute: {
|
||||||
command: 'nunit-console -nologo src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll'
|
command: 'nunit-console -nologo src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ var nodeTree = {
|
|||||||
computeLayout(nodeTree);
|
computeLayout(nodeTree);
|
||||||
|
|
||||||
// the layout information is written back to the node tree, with
|
// the layout information is written back to the node tree, with
|
||||||
// each node now having a layout property:
|
// each node now having a layout property:
|
||||||
|
|
||||||
// JSON.stringify(nodeTree, null, 2);
|
// JSON.stringify(nodeTree, null, 2);
|
||||||
{
|
{
|
||||||
@@ -104,7 +104,7 @@ overflow | 'visible', 'hidden'
|
|||||||
n (where n > 0) | n 0 0
|
n (where n > 0) | n 0 0
|
||||||
0 | 0 0 auto
|
0 | 0 0 auto
|
||||||
-1 | 0 1 auto
|
-1 | 0 1 auto
|
||||||
|
|
||||||
- `inherit` value is not implemented because it's a way to disambiguate between multiple colliding rules. This should be done in a pre-processing step, not in the actual layout algorithm.
|
- `inherit` value is not implemented because it's a way to disambiguate between multiple colliding rules. This should be done in a pre-processing step, not in the actual layout algorithm.
|
||||||
|
|
||||||
|
|
||||||
|
146
dist/css-layout.h
vendored
146
dist/css-layout.h
vendored
@@ -259,7 +259,7 @@ void init_css_node(css_node_t* node) {
|
|||||||
|
|
||||||
node->style.direction = CSS_DIRECTION_INHERIT;
|
node->style.direction = CSS_DIRECTION_INHERIT;
|
||||||
node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
|
node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
|
||||||
|
|
||||||
node->style.overflow = CSS_OVERFLOW_VISIBLE;
|
node->style.overflow = CSS_OVERFLOW_VISIBLE;
|
||||||
|
|
||||||
// Some of the fields default to undefined and not 0
|
// Some of the fields default to undefined and not 0
|
||||||
@@ -291,7 +291,7 @@ void init_css_node(css_node_t* node) {
|
|||||||
node->layout.last_parent_direction = (css_direction_t)-1;
|
node->layout.last_parent_direction = (css_direction_t)-1;
|
||||||
node->layout.should_update = true;
|
node->layout.should_update = true;
|
||||||
node->layout.next_cached_measurements_index = 0;
|
node->layout.next_cached_measurements_index = 0;
|
||||||
|
|
||||||
node->layout.measured_dimensions[CSS_WIDTH] = CSS_UNDEFINED;
|
node->layout.measured_dimensions[CSS_WIDTH] = CSS_UNDEFINED;
|
||||||
node->layout.measured_dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
|
node->layout.measured_dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
|
||||||
node->layout.cached_layout.width_measure_mode = (css_measure_mode_t)-1;
|
node->layout.cached_layout.width_measure_mode = (css_measure_mode_t)-1;
|
||||||
@@ -771,7 +771,7 @@ static float getRelativePosition(css_node_t* node, css_flex_direction_t axis) {
|
|||||||
static void setPosition(css_node_t* node, css_direction_t direction) {
|
static void setPosition(css_node_t* node, css_direction_t direction) {
|
||||||
css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);
|
css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);
|
||||||
css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction);
|
css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction);
|
||||||
|
|
||||||
node->layout.position[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
node->layout.position[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
||||||
getRelativePosition(node, mainAxis);
|
getRelativePosition(node, mainAxis);
|
||||||
node->layout.position[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
node->layout.position[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
||||||
@@ -818,8 +818,8 @@ static void setPosition(css_node_t* node, css_direction_t direction) {
|
|||||||
//
|
//
|
||||||
// Deviations from standard:
|
// Deviations from standard:
|
||||||
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
||||||
// main size. For text blocks, for example, this is the width of the widest word.
|
// main size. For text blocks, for example, this is the width of the widest word.
|
||||||
// Calculating the minimum width is expensive, so we forego it and assume a default
|
// Calculating the minimum width is expensive, so we forego it and assume a default
|
||||||
// minimum main size of 0.
|
// minimum main size of 0.
|
||||||
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
||||||
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
||||||
@@ -853,7 +853,7 @@ static void setPosition(css_node_t* node, css_direction_t direction) {
|
|||||||
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
||||||
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
||||||
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
||||||
//
|
//
|
||||||
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
||||||
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
||||||
//
|
//
|
||||||
@@ -863,7 +863,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
assert(isUndefined(availableWidth) ? widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
assert(isUndefined(availableWidth) ? widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
||||||
assert(isUndefined(availableHeight) ? heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
assert(isUndefined(availableHeight) ? heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
||||||
|
|
||||||
float paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
float paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
@@ -877,7 +877,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
||||||
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
||||||
|
|
||||||
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
||||||
|
|
||||||
// Don't bother sizing the text if both dimensions are already defined.
|
// Don't bother sizing the text if both dimensions are already defined.
|
||||||
@@ -909,7 +909,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
measureDim.dimensions[CSS_HEIGHT] + paddingAndBorderAxisColumn :
|
measureDim.dimensions[CSS_HEIGHT] + paddingAndBorderAxisColumn :
|
||||||
availableHeight - marginAxisColumn);
|
availableHeight - marginAxisColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -939,7 +939,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widthMeasureMode == CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
if (widthMeasureMode == CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
||||||
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
||||||
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
||||||
@@ -951,7 +951,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
||||||
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
||||||
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
||||||
@@ -975,7 +975,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
||||||
float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
||||||
float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
||||||
|
|
||||||
css_measure_mode_t measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
css_measure_mode_t measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
||||||
css_measure_mode_t measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
css_measure_mode_t measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
||||||
|
|
||||||
@@ -1000,7 +1000,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
css_direction_t childDirection = resolveDirection(child, direction);
|
css_direction_t childDirection = resolveDirection(child, direction);
|
||||||
setPosition(child, childDirection);
|
setPosition(child, childDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute-positioned children don't participate in flex layout. Add them
|
// Absolute-positioned children don't participate in flex layout. Add them
|
||||||
// to a list that we can process later.
|
// to a list that we can process later.
|
||||||
if (child->style.position_type == CSS_POSITION_ABSOLUTE) {
|
if (child->style.position_type == CSS_POSITION_ABSOLUTE) {
|
||||||
@@ -1016,27 +1016,27 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentAbsoluteChild = child;
|
currentAbsoluteChild = child;
|
||||||
child->next_child = NULL;
|
child->next_child = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
|
|
||||||
// The width is definite, so use that as the flex basis.
|
// The width is definite, so use that as the flex basis.
|
||||||
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_WIDTH], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_WIDTH], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
||||||
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
|
|
||||||
// The height is definite, so use that as the flex basis.
|
// The height is definite, so use that as the flex basis.
|
||||||
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
||||||
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
||||||
|
|
||||||
// If the basis isn't 'auto', it is assumed to be zero.
|
// If the basis isn't 'auto', it is assumed to be zero.
|
||||||
child->layout.flex_basis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
child->layout.flex_basis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
||||||
childWidth = CSS_UNDEFINED;
|
childWidth = CSS_UNDEFINED;
|
||||||
childHeight = CSS_UNDEFINED;
|
childHeight = CSS_UNDEFINED;
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
|
|
||||||
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -1045,7 +1045,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -1066,21 +1066,21 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
// Measure the child
|
// Measure the child
|
||||||
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
||||||
|
|
||||||
child->layout.flex_basis = fmaxf(isMainAxisRow ? child->layout.measured_dimensions[CSS_WIDTH] : child->layout.measured_dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, mainAxis));
|
child->layout.flex_basis = fmaxf(isMainAxisRow ? child->layout.measured_dimensions[CSS_WIDTH] : child->layout.measured_dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, mainAxis));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
||||||
|
|
||||||
// Indexes of children that represent the first and last items in the line.
|
// Indexes of children that represent the first and last items in the line.
|
||||||
int startOfLineIndex = 0;
|
int startOfLineIndex = 0;
|
||||||
int endOfLineIndex = 0;
|
int endOfLineIndex = 0;
|
||||||
|
|
||||||
// Number of lines.
|
// Number of lines.
|
||||||
int lineCount = 0;
|
int lineCount = 0;
|
||||||
|
|
||||||
// Accumulated cross dimensions of all lines so far.
|
// Accumulated cross dimensions of all lines so far.
|
||||||
float totalLineCrossDim = 0;
|
float totalLineCrossDim = 0;
|
||||||
|
|
||||||
@@ -1088,7 +1088,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
float maxLineMainDim = 0;
|
float maxLineMainDim = 0;
|
||||||
|
|
||||||
while (endOfLineIndex < childCount) {
|
while (endOfLineIndex < childCount) {
|
||||||
|
|
||||||
// Number of items on the currently line. May be different than the difference
|
// Number of items on the currently line. May be different than the difference
|
||||||
// between start and end indicates because we skip over absolute-positioned items.
|
// between start and end indicates because we skip over absolute-positioned items.
|
||||||
int itemsOnLine = 0;
|
int itemsOnLine = 0;
|
||||||
@@ -1115,7 +1115,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (child->style.position_type != CSS_POSITION_ABSOLUTE) {
|
if (child->style.position_type != CSS_POSITION_ABSOLUTE) {
|
||||||
float outerFlexBasis = child->layout.flex_basis + getMarginAxis(child, mainAxis);
|
float outerFlexBasis = child->layout.flex_basis + getMarginAxis(child, mainAxis);
|
||||||
|
|
||||||
// If this is a multi-line flow and this item pushes us over the available size, we've
|
// If this is a multi-line flow and this item pushes us over the available size, we've
|
||||||
// hit the end of the current line. Break out of the loop and lay out the current line.
|
// hit the end of the current line. Break out of the loop and lay out the current line.
|
||||||
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
||||||
@@ -1127,7 +1127,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (isFlex(child)) {
|
if (isFlex(child)) {
|
||||||
totalFlexGrowFactors += getFlexGrowFactor(child);
|
totalFlexGrowFactors += getFlexGrowFactor(child);
|
||||||
|
|
||||||
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
||||||
// dimension.
|
// dimension.
|
||||||
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child->layout.flex_basis;
|
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child->layout.flex_basis;
|
||||||
@@ -1143,11 +1143,11 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentRelativeChild = child;
|
currentRelativeChild = child;
|
||||||
child->next_child = NULL;
|
child->next_child = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
endOfLineIndex++;
|
endOfLineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
||||||
bool canSkipFlex = !performLayout && measureModeCrossDim == CSS_MEASURE_MODE_EXACTLY;
|
bool canSkipFlex = !performLayout && measureModeCrossDim == CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
@@ -1170,7 +1170,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
||||||
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
float originalRemainingFreeSpace = remainingFreeSpace;
|
float originalRemainingFreeSpace = remainingFreeSpace;
|
||||||
float deltaFreeSpace = 0;
|
float deltaFreeSpace = 0;
|
||||||
|
|
||||||
@@ -1180,20 +1180,20 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
float flexGrowFactor;
|
float flexGrowFactor;
|
||||||
float baseMainSize;
|
float baseMainSize;
|
||||||
float boundMainSize;
|
float boundMainSize;
|
||||||
|
|
||||||
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
||||||
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
||||||
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
||||||
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
||||||
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
||||||
// their min/max constraints to trigger again.
|
// their min/max constraints to trigger again.
|
||||||
//
|
//
|
||||||
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
||||||
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
||||||
// that needs to be repeated a variable number of times. The algorithm implemented here
|
// that needs to be repeated a variable number of times. The algorithm implemented here
|
||||||
// won't handle all cases but it was simpler to implement and it mitigates performance
|
// won't handle all cases but it was simpler to implement and it mitigates performance
|
||||||
// concerns because we know exactly how many passes it'll do.
|
// concerns because we know exactly how many passes it'll do.
|
||||||
|
|
||||||
// First pass: detect the flex items whose min/max constraints trigger
|
// First pass: detect the flex items whose min/max constraints trigger
|
||||||
float deltaFlexShrinkScaledFactors = 0;
|
float deltaFlexShrinkScaledFactors = 0;
|
||||||
float deltaFlexGrowFactors = 0;
|
float deltaFlexGrowFactors = 0;
|
||||||
@@ -1203,7 +1203,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
baseMainSize = childFlexBasis +
|
baseMainSize = childFlexBasis +
|
||||||
@@ -1234,14 +1234,14 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRelativeChild = currentRelativeChild->next_child;
|
currentRelativeChild = currentRelativeChild->next_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
||||||
totalFlexGrowFactors += deltaFlexGrowFactors;
|
totalFlexGrowFactors += deltaFlexGrowFactors;
|
||||||
remainingFreeSpace += deltaFreeSpace;
|
remainingFreeSpace += deltaFreeSpace;
|
||||||
|
|
||||||
// Second pass: resolve the sizes of the flexible items
|
// Second pass: resolve the sizes of the flexible items
|
||||||
deltaFreeSpace = 0;
|
deltaFreeSpace = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
@@ -1251,7 +1251,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
||||||
@@ -1266,13 +1266,13 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = availableInnerCrossDim;
|
childHeight = availableInnerCrossDim;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1283,7 +1283,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
} else {
|
} else {
|
||||||
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = availableInnerCrossDim;
|
childWidth = availableInnerCrossDim;
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1292,7 +1292,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
bool requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
||||||
getAlignItem(node, currentRelativeChild) == CSS_ALIGN_STRETCH;
|
getAlignItem(node, currentRelativeChild) == CSS_ALIGN_STRETCH;
|
||||||
|
|
||||||
@@ -1302,7 +1302,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentRelativeChild = currentRelativeChild->next_child;
|
currentRelativeChild = currentRelativeChild->next_child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
||||||
|
|
||||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||||
@@ -1361,7 +1361,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// we put it at the current accumulated offset.
|
// we put it at the current accumulated offset.
|
||||||
child->layout.position[pos[mainAxis]] += mainDim;
|
child->layout.position[pos[mainAxis]] += mainDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we placed the element, we need to update the variables.
|
// Now that we placed the element, we need to update the variables.
|
||||||
// We need to do that only for relative elements. Absolute elements
|
// We need to do that only for relative elements. Absolute elements
|
||||||
// do not take part in that phase.
|
// do not take part in that phase.
|
||||||
@@ -1375,7 +1375,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// The main dimension is the sum of all the elements dimension plus
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
// the spacing.
|
// the spacing.
|
||||||
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
||||||
|
|
||||||
// The cross dimension is the max of the elements dimension since there
|
// The cross dimension is the max of the elements dimension since there
|
||||||
// can only be one element in that cross dimension.
|
// can only be one element in that cross dimension.
|
||||||
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
||||||
@@ -1385,12 +1385,12 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainDim += trailingPaddingAndBorderMain;
|
mainDim += trailingPaddingAndBorderMain;
|
||||||
|
|
||||||
float containerCrossAxis = availableInnerCrossDim;
|
float containerCrossAxis = availableInnerCrossDim;
|
||||||
if (measureModeCrossDim == CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim == CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
||||||
// Compute the cross axis from the max cross dimension of the children.
|
// Compute the cross axis from the max cross dimension of the children.
|
||||||
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
||||||
|
|
||||||
if (measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
||||||
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
||||||
}
|
}
|
||||||
@@ -1427,14 +1427,14 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// For a relative children, we're either using alignItems (parent) or
|
// For a relative children, we're either using alignItems (parent) or
|
||||||
// alignSelf (child) in order to determine the position in the cross axis
|
// alignSelf (child) in order to determine the position in the cross axis
|
||||||
css_align_t alignItem = getAlignItem(node, child);
|
css_align_t alignItem = getAlignItem(node, child);
|
||||||
|
|
||||||
// If the child uses align stretch, we need to lay it out one more time, this time
|
// If the child uses align stretch, we need to lay it out one more time, this time
|
||||||
// forcing the cross-axis size to be the computed cross size for the current line.
|
// forcing the cross-axis size to be the computed cross size for the current line.
|
||||||
if (alignItem == CSS_ALIGN_STRETCH) {
|
if (alignItem == CSS_ALIGN_STRETCH) {
|
||||||
childWidth = child->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = child->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
bool isCrossSizeDefinite = false;
|
bool isCrossSizeDefinite = false;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeight = crossDim;
|
childHeight = crossDim;
|
||||||
@@ -1442,7 +1442,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidth = crossDim;
|
childWidth = crossDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
||||||
if (!isCrossSizeDefinite) {
|
if (!isCrossSizeDefinite) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -1569,7 +1569,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
||||||
paddingAndBorderAxisCross);
|
paddingAndBorderAxisCross);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
bool needsMainTrailingPos = false;
|
bool needsMainTrailingPos = false;
|
||||||
@@ -1600,7 +1600,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
||||||
currentAbsoluteChild = firstAbsoluteChild;
|
currentAbsoluteChild = firstAbsoluteChild;
|
||||||
while (currentAbsoluteChild != NULL) {
|
while (currentAbsoluteChild != NULL) {
|
||||||
@@ -1622,7 +1622,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = currentAbsoluteChild->style.dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild->style.dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
} else {
|
} else {
|
||||||
@@ -1639,7 +1639,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -1662,9 +1662,9 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childWidth = currentAbsoluteChild->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = currentAbsoluteChild->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = currentAbsoluteChild->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, "abs-layout");
|
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, "abs-layout");
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
||||||
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
||||||
@@ -1672,7 +1672,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentAbsoluteChild->layout.measured_dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
currentAbsoluteChild->layout.measured_dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
||||||
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
||||||
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
||||||
@@ -1713,11 +1713,11 @@ static const char* getModeName(css_measure_mode_t mode, bool performLayout) {
|
|||||||
"LAY_EXACTLY",
|
"LAY_EXACTLY",
|
||||||
"LAY_AT_MOST"
|
"LAY_AT_MOST"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mode >= CSS_MEASURE_MODE_COUNT) {
|
if (mode >= CSS_MEASURE_MODE_COUNT) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return performLayout? kLayoutModeNames[mode] : kMeasureModeNames[mode];
|
return performLayout? kLayoutModeNames[mode] : kMeasureModeNames[mode];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1733,7 +1733,7 @@ static bool canUseCachedMeasurement(float availableWidth, float availableHeight,
|
|||||||
cachedLayout.height_measure_mode == heightMeasureMode) {
|
cachedLayout.height_measure_mode == heightMeasureMode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the width is an exact match, try a fuzzy match on the height.
|
// If the width is an exact match, try a fuzzy match on the height.
|
||||||
if (cachedLayout.width_measure_mode == widthMeasureMode &&
|
if (cachedLayout.width_measure_mode == widthMeasureMode &&
|
||||||
eq(cachedLayout.available_width, availableWidth) &&
|
eq(cachedLayout.available_width, availableWidth) &&
|
||||||
@@ -1741,7 +1741,7 @@ static bool canUseCachedMeasurement(float availableWidth, float availableHeight,
|
|||||||
eq(availableHeight - marginColumn, cachedLayout.computed_height)) {
|
eq(availableHeight - marginColumn, cachedLayout.computed_height)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the height is an exact match, try a fuzzy match on the width.
|
// If the height is an exact match, try a fuzzy match on the width.
|
||||||
if (cachedLayout.height_measure_mode == heightMeasureMode &&
|
if (cachedLayout.height_measure_mode == heightMeasureMode &&
|
||||||
eq(cachedLayout.available_height, availableHeight) &&
|
eq(cachedLayout.available_height, availableHeight) &&
|
||||||
@@ -1764,7 +1764,7 @@ static bool canUseCachedMeasurement(float availableWidth, float availableHeight,
|
|||||||
bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableHeight,
|
bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableHeight,
|
||||||
css_direction_t parentDirection, css_measure_mode_t widthMeasureMode, css_measure_mode_t heightMeasureMode, bool performLayout, char* reason) {
|
css_direction_t parentDirection, css_measure_mode_t widthMeasureMode, css_measure_mode_t heightMeasureMode, bool performLayout, char* reason) {
|
||||||
css_layout_t* layout = &node->layout;
|
css_layout_t* layout = &node->layout;
|
||||||
|
|
||||||
gDepth++;
|
gDepth++;
|
||||||
|
|
||||||
bool needToVisitNode = (node->is_dirty(node->context) && layout->generation_count != gCurrentGenerationCount) ||
|
bool needToVisitNode = (node->is_dirty(node->context) && layout->generation_count != gCurrentGenerationCount) ||
|
||||||
@@ -1778,7 +1778,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
}
|
}
|
||||||
|
|
||||||
css_cached_measurement_t* cachedResults = NULL;
|
css_cached_measurement_t* cachedResults = NULL;
|
||||||
|
|
||||||
// Determine whether the results are already cached. We maintain a separate
|
// Determine whether the results are already cached. We maintain a separate
|
||||||
// cache for layouts and measurements. A layout operation modifies the positions
|
// cache for layouts and measurements. A layout operation modifies the positions
|
||||||
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
||||||
@@ -1789,7 +1789,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
float marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
float marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
|
|
||||||
// First, try to use the layout cache.
|
// First, try to use the layout cache.
|
||||||
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||||
widthMeasureMode, heightMeasureMode, layout->cached_layout)) {
|
widthMeasureMode, heightMeasureMode, layout->cached_layout)) {
|
||||||
@@ -1809,7 +1809,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
eq(layout->cached_layout.available_height, availableHeight) &&
|
eq(layout->cached_layout.available_height, availableHeight) &&
|
||||||
layout->cached_layout.width_measure_mode == widthMeasureMode &&
|
layout->cached_layout.width_measure_mode == widthMeasureMode &&
|
||||||
layout->cached_layout.height_measure_mode == heightMeasureMode) {
|
layout->cached_layout.height_measure_mode == heightMeasureMode) {
|
||||||
|
|
||||||
cachedResults = &layout->cached_layout;
|
cachedResults = &layout->cached_layout;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1854,7 +1854,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
||||||
|
|
||||||
if (gPrintChanges) {
|
if (gPrintChanges) {
|
||||||
printf("%s%d.}%s", getSpacer(gDepth), gDepth, needToVisitNode ? "*" : "");
|
printf("%s%d.}%s", getSpacer(gDepth), gDepth, needToVisitNode ? "*" : "");
|
||||||
if (node->print) {
|
if (node->print) {
|
||||||
@@ -1867,7 +1867,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
}
|
}
|
||||||
|
|
||||||
layout->last_parent_direction = parentDirection;
|
layout->last_parent_direction = parentDirection;
|
||||||
|
|
||||||
if (cachedResults == NULL) {
|
if (cachedResults == NULL) {
|
||||||
if (layout->next_cached_measurements_index == CSS_MAX_CACHED_RESULT_COUNT) {
|
if (layout->next_cached_measurements_index == CSS_MAX_CACHED_RESULT_COUNT) {
|
||||||
if (gPrintChanges) {
|
if (gPrintChanges) {
|
||||||
@@ -1885,7 +1885,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
newCacheEntry = &layout->cached_measurements[layout->next_cached_measurements_index];
|
newCacheEntry = &layout->cached_measurements[layout->next_cached_measurements_index];
|
||||||
layout->next_cached_measurements_index++;
|
layout->next_cached_measurements_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
newCacheEntry->available_width = availableWidth;
|
newCacheEntry->available_width = availableWidth;
|
||||||
newCacheEntry->available_height = availableHeight;
|
newCacheEntry->available_height = availableHeight;
|
||||||
newCacheEntry->width_measure_mode = widthMeasureMode;
|
newCacheEntry->width_measure_mode = widthMeasureMode;
|
||||||
@@ -1894,7 +1894,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
newCacheEntry->computed_height = layout->measured_dimensions[CSS_HEIGHT];
|
newCacheEntry->computed_height = layout->measured_dimensions[CSS_HEIGHT];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
node->layout.dimensions[CSS_WIDTH] = node->layout.measured_dimensions[CSS_WIDTH];
|
node->layout.dimensions[CSS_WIDTH] = node->layout.measured_dimensions[CSS_WIDTH];
|
||||||
node->layout.dimensions[CSS_HEIGHT] = node->layout.measured_dimensions[CSS_HEIGHT];
|
node->layout.dimensions[CSS_HEIGHT] = node->layout.measured_dimensions[CSS_HEIGHT];
|
||||||
@@ -1911,7 +1911,7 @@ void layoutNode(css_node_t* node, float availableWidth, float availableHeight, c
|
|||||||
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
||||||
// parameters don't change.
|
// parameters don't change.
|
||||||
gCurrentGenerationCount++;
|
gCurrentGenerationCount++;
|
||||||
|
|
||||||
// If the caller didn't specify a height/width, use the dimensions
|
// If the caller didn't specify a height/width, use the dimensions
|
||||||
// specified in the style.
|
// specified in the style.
|
||||||
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
@@ -1920,10 +1920,10 @@ void layoutNode(css_node_t* node, float availableWidth, float availableHeight, c
|
|||||||
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
availableHeight = node->style.dimensions[CSS_HEIGHT] + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
availableHeight = node->style.dimensions[CSS_HEIGHT] + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
css_measure_mode_t widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
css_measure_mode_t widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
css_measure_mode_t heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
css_measure_mode_t heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, "initial")) {
|
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, "initial")) {
|
||||||
|
|
||||||
setPosition(node, node->layout.direction);
|
setPosition(node, node->layout.direction);
|
||||||
|
BIN
dist/css-layout.jar
vendored
BIN
dist/css-layout.jar
vendored
Binary file not shown.
190
dist/css-layout.js
vendored
190
dist/css-layout.js
vendored
@@ -27,18 +27,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var computeLayout = (function() {
|
var computeLayout = (function() {
|
||||||
|
|
||||||
var POSITIVE_FLEX_IS_AUTO = false;
|
var POSITIVE_FLEX_IS_AUTO = false;
|
||||||
|
|
||||||
var gCurrentGenerationCount = 0;
|
var gCurrentGenerationCount = 0;
|
||||||
|
|
||||||
var CSS_UNDEFINED;
|
var CSS_UNDEFINED;
|
||||||
|
|
||||||
var CSS_LEFT = 'left';
|
var CSS_LEFT = 'left';
|
||||||
var CSS_TOP = 'top';
|
var CSS_TOP = 'top';
|
||||||
var CSS_RIGHT = 'right';
|
var CSS_RIGHT = 'right';
|
||||||
var CSS_BOTTOM = 'bottom';
|
var CSS_BOTTOM = 'bottom';
|
||||||
|
|
||||||
var CSS_DIRECTION_INHERIT = 'inherit';
|
var CSS_DIRECTION_INHERIT = 'inherit';
|
||||||
var CSS_DIRECTION_LTR = 'ltr';
|
var CSS_DIRECTION_LTR = 'ltr';
|
||||||
var CSS_DIRECTION_RTL = 'rtl';
|
var CSS_DIRECTION_RTL = 'rtl';
|
||||||
@@ -61,10 +61,10 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
var CSS_POSITION_RELATIVE = 'relative';
|
var CSS_POSITION_RELATIVE = 'relative';
|
||||||
var CSS_POSITION_ABSOLUTE = 'absolute';
|
var CSS_POSITION_ABSOLUTE = 'absolute';
|
||||||
|
|
||||||
var CSS_OVERFLOW_VISIBLE = 'visible';
|
var CSS_OVERFLOW_VISIBLE = 'visible';
|
||||||
var CSS_OVERFLOW_HIDDEN = 'hidden';
|
var CSS_OVERFLOW_HIDDEN = 'hidden';
|
||||||
|
|
||||||
var CSS_MEASURE_MODE_UNDEFINED = 'undefined';
|
var CSS_MEASURE_MODE_UNDEFINED = 'undefined';
|
||||||
var CSS_MEASURE_MODE_EXACTLY = 'exactly';
|
var CSS_MEASURE_MODE_EXACTLY = 'exactly';
|
||||||
var CSS_MEASURE_MODE_AT_MOST = 'at-most';
|
var CSS_MEASURE_MODE_AT_MOST = 'at-most';
|
||||||
@@ -144,14 +144,14 @@ var computeLayout = (function() {
|
|||||||
return flexDirection === CSS_FLEX_DIRECTION_COLUMN ||
|
return flexDirection === CSS_FLEX_DIRECTION_COLUMN ||
|
||||||
flexDirection === CSS_FLEX_DIRECTION_COLUMN_REVERSE;
|
flexDirection === CSS_FLEX_DIRECTION_COLUMN_REVERSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlex(node) {
|
function getFlex(node) {
|
||||||
if (node.style.flex === undefined) {
|
if (node.style.flex === undefined) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return node.style.flex;
|
return node.style.flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFlexBasisAuto(node) {
|
function isFlexBasisAuto(node) {
|
||||||
if (POSITIVE_FLEX_IS_AUTO) {
|
if (POSITIVE_FLEX_IS_AUTO) {
|
||||||
// All flex values are auto.
|
// All flex values are auto.
|
||||||
@@ -161,7 +161,7 @@ var computeLayout = (function() {
|
|||||||
return getFlex(node) <= 0;
|
return getFlex(node) <= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlexGrowFactor(node) {
|
function getFlexGrowFactor(node) {
|
||||||
// Flex grow is implied by positive values for flex.
|
// Flex grow is implied by positive values for flex.
|
||||||
if (getFlex(node) > 0) {
|
if (getFlex(node) > 0) {
|
||||||
@@ -169,7 +169,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlexShrinkFactor(node) {
|
function getFlexShrinkFactor(node) {
|
||||||
if (POSITIVE_FLEX_IS_AUTO) {
|
if (POSITIVE_FLEX_IS_AUTO) {
|
||||||
// A flex shrink factor of 1 is implied by non-zero values for flex.
|
// A flex shrink factor of 1 is implied by non-zero values for flex.
|
||||||
@@ -422,7 +422,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return CSS_POSITION_RELATIVE;
|
return CSS_POSITION_RELATIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOverflow(node) {
|
function getOverflow(node) {
|
||||||
if (node.style.overflow) {
|
if (node.style.overflow) {
|
||||||
return node.style.overflow;
|
return node.style.overflow;
|
||||||
@@ -444,12 +444,12 @@ var computeLayout = (function() {
|
|||||||
function getDimWithMargin(node, axis) {
|
function getDimWithMargin(node, axis) {
|
||||||
return node.layout[measuredDim[axis]] + getMarginAxis(node, axis);
|
return node.layout[measuredDim[axis]] + getMarginAxis(node, axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isStyleDimDefined(node, axis) {
|
function isStyleDimDefined(node, axis) {
|
||||||
return node.style[dim[axis]] !== undefined && node.style[dim[axis]] >= 0;
|
return node.style[dim[axis]] !== undefined && node.style[dim[axis]] >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLayoutDimDefined(node, axis) {
|
function isLayoutDimDefined(node, axis) {
|
||||||
return node.layout[measuredDim[axis]] !== undefined && node.layout[measuredDim[axis]] >= 0;
|
return node.layout[measuredDim[axis]] !== undefined && node.layout[measuredDim[axis]] >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,7 +467,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function boundAxisWithinMinAndMax(node, axis, value) {
|
function boundAxisWithinMinAndMax(node, axis, value) {
|
||||||
var min = {
|
var min = {
|
||||||
'row': node.style.minWidth,
|
'row': node.style.minWidth,
|
||||||
@@ -492,7 +492,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return boundValue;
|
return boundValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fminf(a, b) {
|
function fminf(a, b) {
|
||||||
if (a < b) {
|
if (a < b) {
|
||||||
return a;
|
return a;
|
||||||
@@ -506,7 +506,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like boundAxisWithinMinAndMax but also ensures that the value doesn't go below the
|
// Like boundAxisWithinMinAndMax but also ensures that the value doesn't go below the
|
||||||
// padding and border amount.
|
// padding and border amount.
|
||||||
function boundAxis(node, axis, value) {
|
function boundAxis(node, axis, value) {
|
||||||
@@ -528,11 +528,11 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return -getPosition(node, trailing[axis]);
|
return -getPosition(node, trailing[axis]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPosition(node, direction) {
|
function setPosition(node, direction) {
|
||||||
var mainAxis = resolveAxis(getFlexDirection(node), direction);
|
var mainAxis = resolveAxis(getFlexDirection(node), direction);
|
||||||
var crossAxis = getCrossFlexDirection(mainAxis, direction);
|
var crossAxis = getCrossFlexDirection(mainAxis, direction);
|
||||||
|
|
||||||
node.layout[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
node.layout[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
||||||
getRelativePosition(node, mainAxis);
|
getRelativePosition(node, mainAxis);
|
||||||
node.layout[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
node.layout[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
||||||
@@ -542,13 +542,13 @@ var computeLayout = (function() {
|
|||||||
node.layout[trailing[crossAxis]] = getTrailingMargin(node, crossAxis) +
|
node.layout[trailing[crossAxis]] = getTrailingMargin(node, crossAxis) +
|
||||||
getRelativePosition(node, crossAxis);
|
getRelativePosition(node, crossAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assert(condition, message) {
|
function assert(condition, message) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is the main routine that implements a subset of the flexbox layout algorithm
|
// This is the main routine that implements a subset of the flexbox layout algorithm
|
||||||
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
||||||
@@ -585,8 +585,8 @@ var computeLayout = (function() {
|
|||||||
//
|
//
|
||||||
// Deviations from standard:
|
// Deviations from standard:
|
||||||
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
||||||
// main size. For text blocks, for example, this is the width of the widest word.
|
// main size. For text blocks, for example, this is the width of the widest word.
|
||||||
// Calculating the minimum width is expensive, so we forego it and assume a default
|
// Calculating the minimum width is expensive, so we forego it and assume a default
|
||||||
// minimum main size of 0.
|
// minimum main size of 0.
|
||||||
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
||||||
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
||||||
@@ -620,14 +620,14 @@ var computeLayout = (function() {
|
|||||||
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
||||||
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
||||||
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
||||||
//
|
//
|
||||||
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
||||||
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
||||||
//
|
//
|
||||||
function layoutNodeImpl(node, availableWidth, availableHeight, /*css_direction_t*/parentDirection, widthMeasureMode, heightMeasureMode, performLayout) {
|
function layoutNodeImpl(node, availableWidth, availableHeight, /*css_direction_t*/parentDirection, widthMeasureMode, heightMeasureMode, performLayout) {
|
||||||
assert(isUndefined(availableWidth) ? widthMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
assert(isUndefined(availableWidth) ? widthMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
||||||
assert(isUndefined(availableHeight) ? heightMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
assert(isUndefined(availableHeight) ? heightMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
||||||
|
|
||||||
var/*float*/ paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
var/*float*/ paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
var/*float*/ paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
var/*float*/ paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
var/*float*/ marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
var/*float*/ marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
@@ -641,7 +641,7 @@ var computeLayout = (function() {
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
var/*float*/ innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
var/*float*/ innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
||||||
var/*float*/ innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
var/*float*/ innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
||||||
|
|
||||||
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
||||||
|
|
||||||
// Don't bother sizing the text if both dimensions are already defined.
|
// Don't bother sizing the text if both dimensions are already defined.
|
||||||
@@ -673,7 +673,7 @@ var computeLayout = (function() {
|
|||||||
measureDim.height + paddingAndBorderAxisColumn :
|
measureDim.height + paddingAndBorderAxisColumn :
|
||||||
availableHeight - marginAxisColumn);
|
availableHeight - marginAxisColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,7 +703,7 @@ var computeLayout = (function() {
|
|||||||
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widthMeasureMode === CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
if (widthMeasureMode === CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
||||||
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
||||||
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
||||||
@@ -715,7 +715,7 @@ var computeLayout = (function() {
|
|||||||
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
||||||
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
||||||
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
||||||
@@ -739,7 +739,7 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
var/*float*/ leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
||||||
var/*float*/ paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
var/*float*/ paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
||||||
var/*float*/ paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
var/*float*/ paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
||||||
|
|
||||||
var/*css_measure_mode_t*/ measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
var/*css_measure_mode_t*/ measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
||||||
var/*css_measure_mode_t*/ measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
var/*css_measure_mode_t*/ measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
||||||
|
|
||||||
@@ -764,7 +764,7 @@ var computeLayout = (function() {
|
|||||||
var/*css_direction_t*/ childDirection = resolveDirection(child, direction);
|
var/*css_direction_t*/ childDirection = resolveDirection(child, direction);
|
||||||
setPosition(child, childDirection);
|
setPosition(child, childDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute-positioned children don't participate in flex layout. Add them
|
// Absolute-positioned children don't participate in flex layout. Add them
|
||||||
// to a list that we can process later.
|
// to a list that we can process later.
|
||||||
if (getPositionType(child) === CSS_POSITION_ABSOLUTE) {
|
if (getPositionType(child) === CSS_POSITION_ABSOLUTE) {
|
||||||
@@ -780,27 +780,27 @@ var computeLayout = (function() {
|
|||||||
currentAbsoluteChild = child;
|
currentAbsoluteChild = child;
|
||||||
child.nextChild = undefined;
|
child.nextChild = undefined;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
|
|
||||||
// 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.width, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
child.layout.flexBasis = fmaxf(child.style.width, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
||||||
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
|
|
||||||
// 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.height, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
child.layout.flexBasis = fmaxf(child.style.height, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
||||||
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
||||||
|
|
||||||
// If the basis isn't 'auto', it is assumed to be zero.
|
// If the basis isn't 'auto', it is assumed to be zero.
|
||||||
child.layout.flexBasis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
child.layout.flexBasis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
||||||
childWidth = CSS_UNDEFINED;
|
childWidth = CSS_UNDEFINED;
|
||||||
childHeight = CSS_UNDEFINED;
|
childHeight = CSS_UNDEFINED;
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
|
|
||||||
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -809,7 +809,7 @@ var computeLayout = (function() {
|
|||||||
childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -830,21 +830,21 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
// Measure the child
|
// Measure the child
|
||||||
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, 'measure');
|
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, 'measure');
|
||||||
|
|
||||||
child.layout.flexBasis = fmaxf(isMainAxisRow ? child.layout.measuredWidth : child.layout.measuredHeight, getPaddingAndBorderAxis(child, mainAxis));
|
child.layout.flexBasis = fmaxf(isMainAxisRow ? child.layout.measuredWidth : child.layout.measuredHeight, getPaddingAndBorderAxis(child, mainAxis));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
||||||
|
|
||||||
// Indexes of children that represent the first and last items in the line.
|
// Indexes of children that represent the first and last items in the line.
|
||||||
var/*int*/ startOfLineIndex = 0;
|
var/*int*/ startOfLineIndex = 0;
|
||||||
var/*int*/ endOfLineIndex = 0;
|
var/*int*/ endOfLineIndex = 0;
|
||||||
|
|
||||||
// Number of lines.
|
// Number of lines.
|
||||||
var/*int*/ lineCount = 0;
|
var/*int*/ lineCount = 0;
|
||||||
|
|
||||||
// Accumulated cross dimensions of all lines so far.
|
// Accumulated cross dimensions of all lines so far.
|
||||||
var/*float*/ totalLineCrossDim = 0;
|
var/*float*/ totalLineCrossDim = 0;
|
||||||
|
|
||||||
@@ -852,7 +852,7 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ maxLineMainDim = 0;
|
var/*float*/ maxLineMainDim = 0;
|
||||||
|
|
||||||
while (endOfLineIndex < childCount) {
|
while (endOfLineIndex < childCount) {
|
||||||
|
|
||||||
// Number of items on the currently line. May be different than the difference
|
// Number of items on the currently line. May be different than the difference
|
||||||
// between start and end indicates because we skip over absolute-positioned items.
|
// between start and end indicates because we skip over absolute-positioned items.
|
||||||
var/*int*/ itemsOnLine = 0;
|
var/*int*/ itemsOnLine = 0;
|
||||||
@@ -879,7 +879,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (getPositionType(child) !== CSS_POSITION_ABSOLUTE) {
|
if (getPositionType(child) !== CSS_POSITION_ABSOLUTE) {
|
||||||
var/*float*/ outerFlexBasis = child.layout.flexBasis + getMarginAxis(child, mainAxis);
|
var/*float*/ outerFlexBasis = child.layout.flexBasis + getMarginAxis(child, mainAxis);
|
||||||
|
|
||||||
// If this is a multi-line flow and this item pushes us over the available size, we've
|
// If this is a multi-line flow and this item pushes us over the available size, we've
|
||||||
// hit the end of the current line. Break out of the loop and lay out the current line.
|
// hit the end of the current line. Break out of the loop and lay out the current line.
|
||||||
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
||||||
@@ -891,7 +891,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (isFlex(child)) {
|
if (isFlex(child)) {
|
||||||
totalFlexGrowFactors += getFlexGrowFactor(child);
|
totalFlexGrowFactors += getFlexGrowFactor(child);
|
||||||
|
|
||||||
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
||||||
// dimension.
|
// dimension.
|
||||||
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
||||||
@@ -907,11 +907,11 @@ var computeLayout = (function() {
|
|||||||
currentRelativeChild = child;
|
currentRelativeChild = child;
|
||||||
child.nextChild = undefined;
|
child.nextChild = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
endOfLineIndex++;
|
endOfLineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
||||||
var/*bool*/ canSkipFlex = !performLayout && measureModeCrossDim === CSS_MEASURE_MODE_EXACTLY;
|
var/*bool*/ canSkipFlex = !performLayout && measureModeCrossDim === CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
@@ -934,7 +934,7 @@ var computeLayout = (function() {
|
|||||||
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
||||||
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
var/*float*/ originalRemainingFreeSpace = remainingFreeSpace;
|
var/*float*/ originalRemainingFreeSpace = remainingFreeSpace;
|
||||||
var/*float*/ deltaFreeSpace = 0;
|
var/*float*/ deltaFreeSpace = 0;
|
||||||
|
|
||||||
@@ -944,20 +944,20 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ flexGrowFactor;
|
var/*float*/ flexGrowFactor;
|
||||||
var/*float*/ baseMainSize;
|
var/*float*/ baseMainSize;
|
||||||
var/*float*/ boundMainSize;
|
var/*float*/ boundMainSize;
|
||||||
|
|
||||||
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
||||||
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
||||||
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
||||||
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
||||||
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
||||||
// their min/max constraints to trigger again.
|
// their min/max constraints to trigger again.
|
||||||
//
|
//
|
||||||
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
||||||
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
||||||
// that needs to be repeated a variable number of times. The algorithm implemented here
|
// that needs to be repeated a variable number of times. The algorithm implemented here
|
||||||
// won't handle all cases but it was simpler to implement and it mitigates performance
|
// won't handle all cases but it was simpler to implement and it mitigates performance
|
||||||
// concerns because we know exactly how many passes it'll do.
|
// concerns because we know exactly how many passes it'll do.
|
||||||
|
|
||||||
// First pass: detect the flex items whose min/max constraints trigger
|
// First pass: detect the flex items whose min/max constraints trigger
|
||||||
var/*float*/ deltaFlexShrinkScaledFactors = 0;
|
var/*float*/ deltaFlexShrinkScaledFactors = 0;
|
||||||
var/*float*/ deltaFlexGrowFactors = 0;
|
var/*float*/ deltaFlexGrowFactors = 0;
|
||||||
@@ -967,7 +967,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor !== 0) {
|
if (flexShrinkScaledFactor !== 0) {
|
||||||
baseMainSize = childFlexBasis +
|
baseMainSize = childFlexBasis +
|
||||||
@@ -998,14 +998,14 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
||||||
totalFlexGrowFactors += deltaFlexGrowFactors;
|
totalFlexGrowFactors += deltaFlexGrowFactors;
|
||||||
remainingFreeSpace += deltaFreeSpace;
|
remainingFreeSpace += deltaFreeSpace;
|
||||||
|
|
||||||
// Second pass: resolve the sizes of the flexible items
|
// Second pass: resolve the sizes of the flexible items
|
||||||
deltaFreeSpace = 0;
|
deltaFreeSpace = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
@@ -1015,7 +1015,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor !== 0) {
|
if (flexShrinkScaledFactor !== 0) {
|
||||||
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
||||||
@@ -1030,13 +1030,13 @@ var computeLayout = (function() {
|
|||||||
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = availableInnerCrossDim;
|
childHeight = availableInnerCrossDim;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1047,7 +1047,7 @@ var computeLayout = (function() {
|
|||||||
} else {
|
} else {
|
||||||
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = availableInnerCrossDim;
|
childWidth = availableInnerCrossDim;
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1056,7 +1056,7 @@ var computeLayout = (function() {
|
|||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var/*bool*/ requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
var/*bool*/ requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
||||||
getAlignItem(node, currentRelativeChild) === CSS_ALIGN_STRETCH;
|
getAlignItem(node, currentRelativeChild) === CSS_ALIGN_STRETCH;
|
||||||
|
|
||||||
@@ -1066,7 +1066,7 @@ var computeLayout = (function() {
|
|||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
||||||
|
|
||||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||||
@@ -1125,7 +1125,7 @@ var computeLayout = (function() {
|
|||||||
// we put it at the current accumulated offset.
|
// we put it at the current accumulated offset.
|
||||||
child.layout[pos[mainAxis]] += mainDim;
|
child.layout[pos[mainAxis]] += mainDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we placed the element, we need to update the variables.
|
// Now that we placed the element, we need to update the variables.
|
||||||
// We need to do that only for relative elements. Absolute elements
|
// We need to do that only for relative elements. Absolute elements
|
||||||
// do not take part in that phase.
|
// do not take part in that phase.
|
||||||
@@ -1139,7 +1139,7 @@ var computeLayout = (function() {
|
|||||||
// The main dimension is the sum of all the elements dimension plus
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
// the spacing.
|
// the spacing.
|
||||||
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
||||||
|
|
||||||
// The cross dimension is the max of the elements dimension since there
|
// The cross dimension is the max of the elements dimension since there
|
||||||
// can only be one element in that cross dimension.
|
// can only be one element in that cross dimension.
|
||||||
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
||||||
@@ -1149,12 +1149,12 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainDim += trailingPaddingAndBorderMain;
|
mainDim += trailingPaddingAndBorderMain;
|
||||||
|
|
||||||
var/*float*/ containerCrossAxis = availableInnerCrossDim;
|
var/*float*/ containerCrossAxis = availableInnerCrossDim;
|
||||||
if (measureModeCrossDim === CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim === CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
||||||
// Compute the cross axis from the max cross dimension of the children.
|
// Compute the cross axis from the max cross dimension of the children.
|
||||||
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
||||||
|
|
||||||
if (measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
||||||
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
||||||
}
|
}
|
||||||
@@ -1191,14 +1191,14 @@ var computeLayout = (function() {
|
|||||||
// For a relative children, we're either using alignItems (parent) or
|
// For a relative children, we're either using alignItems (parent) or
|
||||||
// alignSelf (child) in order to determine the position in the cross axis
|
// alignSelf (child) in order to determine the position in the cross axis
|
||||||
var/*css_align_t*/ alignItem = getAlignItem(node, child);
|
var/*css_align_t*/ alignItem = getAlignItem(node, child);
|
||||||
|
|
||||||
// If the child uses align stretch, we need to lay it out one more time, this time
|
// If the child uses align stretch, we need to lay it out one more time, this time
|
||||||
// forcing the cross-axis size to be the computed cross size for the current line.
|
// forcing the cross-axis size to be the computed cross size for the current line.
|
||||||
if (alignItem === CSS_ALIGN_STRETCH) {
|
if (alignItem === CSS_ALIGN_STRETCH) {
|
||||||
childWidth = child.layout.measuredWidth + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child.layout.measuredWidth + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = child.layout.measuredHeight + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child.layout.measuredHeight + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
var/*bool*/ isCrossSizeDefinite = false;
|
var/*bool*/ isCrossSizeDefinite = false;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeight = crossDim;
|
childHeight = crossDim;
|
||||||
@@ -1206,7 +1206,7 @@ var computeLayout = (function() {
|
|||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidth = crossDim;
|
childWidth = crossDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
||||||
if (!isCrossSizeDefinite) {
|
if (!isCrossSizeDefinite) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -1333,7 +1333,7 @@ var computeLayout = (function() {
|
|||||||
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
||||||
paddingAndBorderAxisCross);
|
paddingAndBorderAxisCross);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
var/*bool*/ needsMainTrailingPos = false;
|
var/*bool*/ needsMainTrailingPos = false;
|
||||||
@@ -1364,7 +1364,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
||||||
currentAbsoluteChild = firstAbsoluteChild;
|
currentAbsoluteChild = firstAbsoluteChild;
|
||||||
while (currentAbsoluteChild !== undefined) {
|
while (currentAbsoluteChild !== undefined) {
|
||||||
@@ -1386,7 +1386,7 @@ var computeLayout = (function() {
|
|||||||
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = currentAbsoluteChild.style.height + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild.style.height + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
} else {
|
} else {
|
||||||
@@ -1403,7 +1403,7 @@ var computeLayout = (function() {
|
|||||||
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -1426,9 +1426,9 @@ var computeLayout = (function() {
|
|||||||
childWidth = currentAbsoluteChild.layout.measuredWidth + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = currentAbsoluteChild.layout.measuredWidth + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = currentAbsoluteChild.layout.measuredHeight + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild.layout.measuredHeight + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, 'abs-layout');
|
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, 'abs-layout');
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
||||||
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_ROW]] =
|
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_ROW]] =
|
||||||
@@ -1436,7 +1436,7 @@ var computeLayout = (function() {
|
|||||||
currentAbsoluteChild.layout[measuredDim[CSS_FLEX_DIRECTION_ROW]] -
|
currentAbsoluteChild.layout[measuredDim[CSS_FLEX_DIRECTION_ROW]] -
|
||||||
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
||||||
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
||||||
@@ -1449,7 +1449,7 @@ var computeLayout = (function() {
|
|||||||
currentAbsoluteChild = currentAbsoluteChild.nextChild;
|
currentAbsoluteChild = currentAbsoluteChild.nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function canUseCachedMeasurement(availableWidth, availableHeight,
|
function canUseCachedMeasurement(availableWidth, availableHeight,
|
||||||
marginRow, marginColumn,
|
marginRow, marginColumn,
|
||||||
widthMeasureMode, heightMeasureMode,
|
widthMeasureMode, heightMeasureMode,
|
||||||
@@ -1462,7 +1462,7 @@ var computeLayout = (function() {
|
|||||||
cachedLayout.heightMeasureMode === heightMeasureMode) {
|
cachedLayout.heightMeasureMode === heightMeasureMode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the width is an exact match, try a fuzzy match on the height.
|
// If the width is an exact match, try a fuzzy match on the height.
|
||||||
if (cachedLayout.availableWidth === availableWidth &&
|
if (cachedLayout.availableWidth === availableWidth &&
|
||||||
cachedLayout.widthMeasureMode === widthMeasureMode &&
|
cachedLayout.widthMeasureMode === widthMeasureMode &&
|
||||||
@@ -1470,7 +1470,7 @@ var computeLayout = (function() {
|
|||||||
availableHeight - marginColumn === cachedLayout.computedHeight) {
|
availableHeight - marginColumn === cachedLayout.computedHeight) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the height is an exact match, try a fuzzy match on the width.
|
// If the height is an exact match, try a fuzzy match on the width.
|
||||||
if (cachedLayout.availableHeight === availableHeight &&
|
if (cachedLayout.availableHeight === availableHeight &&
|
||||||
cachedLayout.heightMeasureMode === heightMeasureMode &&
|
cachedLayout.heightMeasureMode === heightMeasureMode &&
|
||||||
@@ -1481,7 +1481,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is a wrapper around the layoutNodeImpl function. It determines
|
// This is a wrapper around the layoutNodeImpl function. It determines
|
||||||
// whether the layout request is redundant and can be skipped.
|
// whether the layout request is redundant and can be skipped.
|
||||||
@@ -1500,18 +1500,18 @@ var computeLayout = (function() {
|
|||||||
if (needToVisitNode) {
|
if (needToVisitNode) {
|
||||||
// Invalidate the cached results.
|
// Invalidate the cached results.
|
||||||
if (layout.cachedMeasurements !== undefined) {
|
if (layout.cachedMeasurements !== undefined) {
|
||||||
layout.cachedMeasurements = [];
|
layout.cachedMeasurements = [];
|
||||||
}
|
}
|
||||||
if (layout.cachedLayout !== undefined) {
|
if (layout.cachedLayout !== undefined) {
|
||||||
layout.cachedLayout.widthMeasureMode = undefined;
|
layout.cachedLayout.widthMeasureMode = undefined;
|
||||||
layout.cachedLayout.heightMeasureMode = undefined;
|
layout.cachedLayout.heightMeasureMode = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
var len;
|
var len;
|
||||||
var cachedResults;
|
var cachedResults;
|
||||||
|
|
||||||
// Determine whether the results are already cached. We maintain a separate
|
// Determine whether the results are already cached. We maintain a separate
|
||||||
// cache for layouts and measurements. A layout operation modifies the positions
|
// cache for layouts and measurements. A layout operation modifies the positions
|
||||||
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
||||||
@@ -1522,7 +1522,7 @@ var computeLayout = (function() {
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
var marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
var marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
var marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
var marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
|
|
||||||
// First, try to use the layout cache.
|
// First, try to use the layout cache.
|
||||||
if (layout.cachedLayout &&
|
if (layout.cachedLayout &&
|
||||||
canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||||
@@ -1557,14 +1557,14 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needToVisitNode && cachedResults !== undefined) {
|
if (!needToVisitNode && cachedResults !== undefined) {
|
||||||
layout.measureWidth = cachedResults.computedWidth;
|
layout.measureWidth = cachedResults.computedWidth;
|
||||||
layout.measureHeight = cachedResults.computedHeight;
|
layout.measureHeight = cachedResults.computedHeight;
|
||||||
} else {
|
} else {
|
||||||
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
||||||
layout.lastParentDirection = parentDirection;
|
layout.lastParentDirection = parentDirection;
|
||||||
|
|
||||||
if (cachedResults === undefined) {
|
if (cachedResults === undefined) {
|
||||||
var newCacheEntry;
|
var newCacheEntry;
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
@@ -1581,7 +1581,7 @@ var computeLayout = (function() {
|
|||||||
newCacheEntry = {};
|
newCacheEntry = {};
|
||||||
layout.cachedMeasurements.push(newCacheEntry);
|
layout.cachedMeasurements.push(newCacheEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
newCacheEntry.availableWidth = availableWidth;
|
newCacheEntry.availableWidth = availableWidth;
|
||||||
newCacheEntry.availableHeight = availableHeight;
|
newCacheEntry.availableHeight = availableHeight;
|
||||||
newCacheEntry.widthMeasureMode = widthMeasureMode;
|
newCacheEntry.widthMeasureMode = widthMeasureMode;
|
||||||
@@ -1590,23 +1590,23 @@ var computeLayout = (function() {
|
|||||||
newCacheEntry.computedHeight = layout.measuredHeight;
|
newCacheEntry.computedHeight = layout.measuredHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
node.layout.width = node.layout.measuredWidth;
|
node.layout.width = node.layout.measuredWidth;
|
||||||
node.layout.height = node.layout.measuredHeight;
|
node.layout.height = node.layout.measuredHeight;
|
||||||
layout.shouldUpdate = true;
|
layout.shouldUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.generationCount = gCurrentGenerationCount;
|
layout.generationCount = gCurrentGenerationCount;
|
||||||
return (needToVisitNode || cachedResults === undefined);
|
return (needToVisitNode || cachedResults === undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
function layoutNode(node, availableWidth, availableHeight, parentDirection) {
|
function layoutNode(node, availableWidth, availableHeight, parentDirection) {
|
||||||
// Increment the generation count. This will force the recursive routine to visit
|
// Increment the generation count. This will force the recursive routine to visit
|
||||||
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
||||||
// parameters don't change.
|
// parameters don't change.
|
||||||
gCurrentGenerationCount++;
|
gCurrentGenerationCount++;
|
||||||
|
|
||||||
// If the caller didn't specify a height/width, use the dimensions
|
// If the caller didn't specify a height/width, use the dimensions
|
||||||
// specified in the style.
|
// specified in the style.
|
||||||
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
@@ -1615,10 +1615,10 @@ var computeLayout = (function() {
|
|||||||
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
availableHeight = node.style.height + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
availableHeight = node.style.height + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
var widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
var widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
var heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
var heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, 'initial')) {
|
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, 'initial')) {
|
||||||
setPosition(node, node.layout.direction);
|
setPosition(node, node.layout.direction);
|
||||||
}
|
}
|
||||||
|
2
dist/css-layout.min.js
vendored
2
dist/css-layout.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/css-layout.min.js.map
vendored
2
dist/css-layout.min.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -130,13 +130,13 @@ var layoutTestUtils = (function() {
|
|||||||
keysToCopy.forEach(function(key) {
|
keysToCopy.forEach(function(key) {
|
||||||
layout[key] = node.layout[key];
|
layout[key] = node.layout[key];
|
||||||
});
|
});
|
||||||
|
|
||||||
if (node.children && node.children.length > 0) {
|
if (node.children && node.children.length > 0) {
|
||||||
layout.children = node.children.map(extractNodes);
|
layout.children = node.children.map(extractNodes);
|
||||||
} else {
|
} else {
|
||||||
delete node.children;
|
delete node.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete node.layout;
|
delete node.layout;
|
||||||
|
|
||||||
return layout;
|
return layout;
|
||||||
@@ -192,13 +192,13 @@ var layoutTestUtils = (function() {
|
|||||||
|
|
||||||
function computeDOMLayout(node) {
|
function computeDOMLayout(node) {
|
||||||
var body = getIframe().contentDocument.body;
|
var body = getIframe().contentDocument.body;
|
||||||
|
|
||||||
function setStyle(div, name, value) {
|
function setStyle(div, name, value) {
|
||||||
div.style['-webkit-' + name] = value;
|
div.style['-webkit-' + name] = value;
|
||||||
div.style['webkit' + capitalizeFirst(name)] = value;
|
div.style['webkit' + capitalizeFirst(name)] = value;
|
||||||
div.style[name] = value;
|
div.style[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function transfer(div, node, name, ext) {
|
function transfer(div, node, name, ext) {
|
||||||
if (name in node.style) {
|
if (name in node.style) {
|
||||||
var value = node.style[name] + (ext || '');
|
var value = node.style[name] + (ext || '');
|
||||||
@@ -215,7 +215,7 @@ var layoutTestUtils = (function() {
|
|||||||
transfer(div, node, type + 'Start' + suffix, 'px');
|
transfer(div, node, type + 'Start' + suffix, 'px');
|
||||||
transfer(div, node, type + 'End' + suffix, 'px');
|
transfer(div, node, type + 'End' + suffix, 'px');
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferFlex(div, node) {
|
function transferFlex(div, node) {
|
||||||
if ('flex' in node.style) {
|
if ('flex' in node.style) {
|
||||||
var flex = node.style.flex;
|
var flex = node.style.flex;
|
||||||
@@ -227,7 +227,7 @@ var layoutTestUtils = (function() {
|
|||||||
setStyle(div, 'flex', resolvedFlex);
|
setStyle(div, 'flex', resolvedFlex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderNode(parent, node) {
|
function renderNode(parent, node) {
|
||||||
var div = document.createElement('div');
|
var div = document.createElement('div');
|
||||||
transfer(div, node, 'width', 'px');
|
transfer(div, node, 'width', 'px');
|
||||||
@@ -325,13 +325,13 @@ var layoutTestUtils = (function() {
|
|||||||
function testExtractNodes(node, extractedNode) {
|
function testExtractNodes(node, extractedNode) {
|
||||||
expect(extractNodes(node)).toEqual(extractedNode);
|
expect(extractNodes(node)).toEqual(extractedNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCanUseCachedMeasurement(canReuse, spec, cacheEntry) {
|
function testCanUseCachedMeasurement(canReuse, spec, cacheEntry) {
|
||||||
var availableWidth = spec.availableWidth;
|
var availableWidth = spec.availableWidth;
|
||||||
var availableHeight = spec.availableHeight;
|
var availableHeight = spec.availableHeight;
|
||||||
var widthMeasureMode = spec.widthMeasureMode;
|
var widthMeasureMode = spec.widthMeasureMode;
|
||||||
var heightMeasureMode = spec.heightMeasureMode;
|
var heightMeasureMode = spec.heightMeasureMode;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
canUseCachedMeasurement(
|
canUseCachedMeasurement(
|
||||||
availableWidth, availableHeight,
|
availableWidth, availableHeight,
|
||||||
|
146
src/Layout.c
146
src/Layout.c
@@ -54,7 +54,7 @@ void init_css_node(css_node_t* node) {
|
|||||||
|
|
||||||
node->style.direction = CSS_DIRECTION_INHERIT;
|
node->style.direction = CSS_DIRECTION_INHERIT;
|
||||||
node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
|
node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
|
||||||
|
|
||||||
node->style.overflow = CSS_OVERFLOW_VISIBLE;
|
node->style.overflow = CSS_OVERFLOW_VISIBLE;
|
||||||
|
|
||||||
// Some of the fields default to undefined and not 0
|
// Some of the fields default to undefined and not 0
|
||||||
@@ -86,7 +86,7 @@ void init_css_node(css_node_t* node) {
|
|||||||
node->layout.last_parent_direction = (css_direction_t)-1;
|
node->layout.last_parent_direction = (css_direction_t)-1;
|
||||||
node->layout.should_update = true;
|
node->layout.should_update = true;
|
||||||
node->layout.next_cached_measurements_index = 0;
|
node->layout.next_cached_measurements_index = 0;
|
||||||
|
|
||||||
node->layout.measured_dimensions[CSS_WIDTH] = CSS_UNDEFINED;
|
node->layout.measured_dimensions[CSS_WIDTH] = CSS_UNDEFINED;
|
||||||
node->layout.measured_dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
|
node->layout.measured_dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
|
||||||
node->layout.cached_layout.width_measure_mode = (css_measure_mode_t)-1;
|
node->layout.cached_layout.width_measure_mode = (css_measure_mode_t)-1;
|
||||||
@@ -566,7 +566,7 @@ static float getRelativePosition(css_node_t* node, css_flex_direction_t axis) {
|
|||||||
static void setPosition(css_node_t* node, css_direction_t direction) {
|
static void setPosition(css_node_t* node, css_direction_t direction) {
|
||||||
css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);
|
css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);
|
||||||
css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction);
|
css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction);
|
||||||
|
|
||||||
node->layout.position[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
node->layout.position[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
||||||
getRelativePosition(node, mainAxis);
|
getRelativePosition(node, mainAxis);
|
||||||
node->layout.position[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
node->layout.position[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
||||||
@@ -613,8 +613,8 @@ static void setPosition(css_node_t* node, css_direction_t direction) {
|
|||||||
//
|
//
|
||||||
// Deviations from standard:
|
// Deviations from standard:
|
||||||
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
||||||
// main size. For text blocks, for example, this is the width of the widest word.
|
// main size. For text blocks, for example, this is the width of the widest word.
|
||||||
// Calculating the minimum width is expensive, so we forego it and assume a default
|
// Calculating the minimum width is expensive, so we forego it and assume a default
|
||||||
// minimum main size of 0.
|
// minimum main size of 0.
|
||||||
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
||||||
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
||||||
@@ -648,7 +648,7 @@ static void setPosition(css_node_t* node, css_direction_t direction) {
|
|||||||
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
||||||
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
||||||
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
||||||
//
|
//
|
||||||
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
||||||
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
||||||
//
|
//
|
||||||
@@ -658,7 +658,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
assert(isUndefined(availableWidth) ? widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
assert(isUndefined(availableWidth) ? widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
||||||
assert(isUndefined(availableHeight) ? heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
assert(isUndefined(availableHeight) ? heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED : true); // availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED
|
||||||
|
|
||||||
float paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
float paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
float paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
@@ -672,7 +672,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
||||||
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
||||||
|
|
||||||
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
||||||
|
|
||||||
// Don't bother sizing the text if both dimensions are already defined.
|
// Don't bother sizing the text if both dimensions are already defined.
|
||||||
@@ -704,7 +704,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
measureDim.dimensions[CSS_HEIGHT] + paddingAndBorderAxisColumn :
|
measureDim.dimensions[CSS_HEIGHT] + paddingAndBorderAxisColumn :
|
||||||
availableHeight - marginAxisColumn);
|
availableHeight - marginAxisColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,7 +734,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widthMeasureMode == CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
if (widthMeasureMode == CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
||||||
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
||||||
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
||||||
@@ -746,7 +746,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node->layout.measured_dimensions[CSS_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
||||||
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY) {
|
||||||
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
node->layout.measured_dimensions[CSS_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
||||||
@@ -770,7 +770,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
float leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
||||||
float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
float paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
||||||
float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
float paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
||||||
|
|
||||||
css_measure_mode_t measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
css_measure_mode_t measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
||||||
css_measure_mode_t measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
css_measure_mode_t measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
||||||
|
|
||||||
@@ -795,7 +795,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
css_direction_t childDirection = resolveDirection(child, direction);
|
css_direction_t childDirection = resolveDirection(child, direction);
|
||||||
setPosition(child, childDirection);
|
setPosition(child, childDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute-positioned children don't participate in flex layout. Add them
|
// Absolute-positioned children don't participate in flex layout. Add them
|
||||||
// to a list that we can process later.
|
// to a list that we can process later.
|
||||||
if (child->style.position_type == CSS_POSITION_ABSOLUTE) {
|
if (child->style.position_type == CSS_POSITION_ABSOLUTE) {
|
||||||
@@ -811,27 +811,27 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentAbsoluteChild = child;
|
currentAbsoluteChild = child;
|
||||||
child->next_child = NULL;
|
child->next_child = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
|
|
||||||
// The width is definite, so use that as the flex basis.
|
// The width is definite, so use that as the flex basis.
|
||||||
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_WIDTH], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_WIDTH], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
||||||
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
|
|
||||||
// The height is definite, so use that as the flex basis.
|
// The height is definite, so use that as the flex basis.
|
||||||
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
child->layout.flex_basis = fmaxf(child->style.dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
||||||
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
||||||
|
|
||||||
// If the basis isn't 'auto', it is assumed to be zero.
|
// If the basis isn't 'auto', it is assumed to be zero.
|
||||||
child->layout.flex_basis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
child->layout.flex_basis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
||||||
childWidth = CSS_UNDEFINED;
|
childWidth = CSS_UNDEFINED;
|
||||||
childHeight = CSS_UNDEFINED;
|
childHeight = CSS_UNDEFINED;
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
|
|
||||||
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -840,7 +840,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -861,21 +861,21 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
// Measure the child
|
// Measure the child
|
||||||
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
||||||
|
|
||||||
child->layout.flex_basis = fmaxf(isMainAxisRow ? child->layout.measured_dimensions[CSS_WIDTH] : child->layout.measured_dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, mainAxis));
|
child->layout.flex_basis = fmaxf(isMainAxisRow ? child->layout.measured_dimensions[CSS_WIDTH] : child->layout.measured_dimensions[CSS_HEIGHT], getPaddingAndBorderAxis(child, mainAxis));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
||||||
|
|
||||||
// Indexes of children that represent the first and last items in the line.
|
// Indexes of children that represent the first and last items in the line.
|
||||||
int startOfLineIndex = 0;
|
int startOfLineIndex = 0;
|
||||||
int endOfLineIndex = 0;
|
int endOfLineIndex = 0;
|
||||||
|
|
||||||
// Number of lines.
|
// Number of lines.
|
||||||
int lineCount = 0;
|
int lineCount = 0;
|
||||||
|
|
||||||
// Accumulated cross dimensions of all lines so far.
|
// Accumulated cross dimensions of all lines so far.
|
||||||
float totalLineCrossDim = 0;
|
float totalLineCrossDim = 0;
|
||||||
|
|
||||||
@@ -883,7 +883,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
float maxLineMainDim = 0;
|
float maxLineMainDim = 0;
|
||||||
|
|
||||||
while (endOfLineIndex < childCount) {
|
while (endOfLineIndex < childCount) {
|
||||||
|
|
||||||
// Number of items on the currently line. May be different than the difference
|
// Number of items on the currently line. May be different than the difference
|
||||||
// between start and end indicates because we skip over absolute-positioned items.
|
// between start and end indicates because we skip over absolute-positioned items.
|
||||||
int itemsOnLine = 0;
|
int itemsOnLine = 0;
|
||||||
@@ -910,7 +910,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (child->style.position_type != CSS_POSITION_ABSOLUTE) {
|
if (child->style.position_type != CSS_POSITION_ABSOLUTE) {
|
||||||
float outerFlexBasis = child->layout.flex_basis + getMarginAxis(child, mainAxis);
|
float outerFlexBasis = child->layout.flex_basis + getMarginAxis(child, mainAxis);
|
||||||
|
|
||||||
// If this is a multi-line flow and this item pushes us over the available size, we've
|
// If this is a multi-line flow and this item pushes us over the available size, we've
|
||||||
// hit the end of the current line. Break out of the loop and lay out the current line.
|
// hit the end of the current line. Break out of the loop and lay out the current line.
|
||||||
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
||||||
@@ -922,7 +922,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (isFlex(child)) {
|
if (isFlex(child)) {
|
||||||
totalFlexGrowFactors += getFlexGrowFactor(child);
|
totalFlexGrowFactors += getFlexGrowFactor(child);
|
||||||
|
|
||||||
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
||||||
// dimension.
|
// dimension.
|
||||||
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child->layout.flex_basis;
|
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child->layout.flex_basis;
|
||||||
@@ -938,11 +938,11 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentRelativeChild = child;
|
currentRelativeChild = child;
|
||||||
child->next_child = NULL;
|
child->next_child = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
endOfLineIndex++;
|
endOfLineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
||||||
bool canSkipFlex = !performLayout && measureModeCrossDim == CSS_MEASURE_MODE_EXACTLY;
|
bool canSkipFlex = !performLayout && measureModeCrossDim == CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
@@ -965,7 +965,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
||||||
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
float originalRemainingFreeSpace = remainingFreeSpace;
|
float originalRemainingFreeSpace = remainingFreeSpace;
|
||||||
float deltaFreeSpace = 0;
|
float deltaFreeSpace = 0;
|
||||||
|
|
||||||
@@ -975,20 +975,20 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
float flexGrowFactor;
|
float flexGrowFactor;
|
||||||
float baseMainSize;
|
float baseMainSize;
|
||||||
float boundMainSize;
|
float boundMainSize;
|
||||||
|
|
||||||
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
||||||
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
||||||
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
||||||
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
||||||
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
||||||
// their min/max constraints to trigger again.
|
// their min/max constraints to trigger again.
|
||||||
//
|
//
|
||||||
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
||||||
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
||||||
// that needs to be repeated a variable number of times. The algorithm implemented here
|
// that needs to be repeated a variable number of times. The algorithm implemented here
|
||||||
// won't handle all cases but it was simpler to implement and it mitigates performance
|
// won't handle all cases but it was simpler to implement and it mitigates performance
|
||||||
// concerns because we know exactly how many passes it'll do.
|
// concerns because we know exactly how many passes it'll do.
|
||||||
|
|
||||||
// First pass: detect the flex items whose min/max constraints trigger
|
// First pass: detect the flex items whose min/max constraints trigger
|
||||||
float deltaFlexShrinkScaledFactors = 0;
|
float deltaFlexShrinkScaledFactors = 0;
|
||||||
float deltaFlexGrowFactors = 0;
|
float deltaFlexGrowFactors = 0;
|
||||||
@@ -998,7 +998,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
baseMainSize = childFlexBasis +
|
baseMainSize = childFlexBasis +
|
||||||
@@ -1029,14 +1029,14 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRelativeChild = currentRelativeChild->next_child;
|
currentRelativeChild = currentRelativeChild->next_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
||||||
totalFlexGrowFactors += deltaFlexGrowFactors;
|
totalFlexGrowFactors += deltaFlexGrowFactors;
|
||||||
remainingFreeSpace += deltaFreeSpace;
|
remainingFreeSpace += deltaFreeSpace;
|
||||||
|
|
||||||
// Second pass: resolve the sizes of the flexible items
|
// Second pass: resolve the sizes of the flexible items
|
||||||
deltaFreeSpace = 0;
|
deltaFreeSpace = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
@@ -1046,7 +1046,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
||||||
@@ -1061,13 +1061,13 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = availableInnerCrossDim;
|
childHeight = availableInnerCrossDim;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1078,7 +1078,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
} else {
|
} else {
|
||||||
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = availableInnerCrossDim;
|
childWidth = availableInnerCrossDim;
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1087,7 +1087,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
bool requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
||||||
getAlignItem(node, currentRelativeChild) == CSS_ALIGN_STRETCH;
|
getAlignItem(node, currentRelativeChild) == CSS_ALIGN_STRETCH;
|
||||||
|
|
||||||
@@ -1097,7 +1097,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentRelativeChild = currentRelativeChild->next_child;
|
currentRelativeChild = currentRelativeChild->next_child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
||||||
|
|
||||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||||
@@ -1156,7 +1156,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// we put it at the current accumulated offset.
|
// we put it at the current accumulated offset.
|
||||||
child->layout.position[pos[mainAxis]] += mainDim;
|
child->layout.position[pos[mainAxis]] += mainDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we placed the element, we need to update the variables.
|
// Now that we placed the element, we need to update the variables.
|
||||||
// We need to do that only for relative elements. Absolute elements
|
// We need to do that only for relative elements. Absolute elements
|
||||||
// do not take part in that phase.
|
// do not take part in that phase.
|
||||||
@@ -1170,7 +1170,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// The main dimension is the sum of all the elements dimension plus
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
// the spacing.
|
// the spacing.
|
||||||
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
||||||
|
|
||||||
// The cross dimension is the max of the elements dimension since there
|
// The cross dimension is the max of the elements dimension since there
|
||||||
// can only be one element in that cross dimension.
|
// can only be one element in that cross dimension.
|
||||||
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
||||||
@@ -1180,12 +1180,12 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainDim += trailingPaddingAndBorderMain;
|
mainDim += trailingPaddingAndBorderMain;
|
||||||
|
|
||||||
float containerCrossAxis = availableInnerCrossDim;
|
float containerCrossAxis = availableInnerCrossDim;
|
||||||
if (measureModeCrossDim == CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim == CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
||||||
// Compute the cross axis from the max cross dimension of the children.
|
// Compute the cross axis from the max cross dimension of the children.
|
||||||
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
||||||
|
|
||||||
if (measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim == CSS_MEASURE_MODE_AT_MOST) {
|
||||||
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
||||||
}
|
}
|
||||||
@@ -1222,14 +1222,14 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
// For a relative children, we're either using alignItems (parent) or
|
// For a relative children, we're either using alignItems (parent) or
|
||||||
// alignSelf (child) in order to determine the position in the cross axis
|
// alignSelf (child) in order to determine the position in the cross axis
|
||||||
css_align_t alignItem = getAlignItem(node, child);
|
css_align_t alignItem = getAlignItem(node, child);
|
||||||
|
|
||||||
// If the child uses align stretch, we need to lay it out one more time, this time
|
// If the child uses align stretch, we need to lay it out one more time, this time
|
||||||
// forcing the cross-axis size to be the computed cross size for the current line.
|
// forcing the cross-axis size to be the computed cross size for the current line.
|
||||||
if (alignItem == CSS_ALIGN_STRETCH) {
|
if (alignItem == CSS_ALIGN_STRETCH) {
|
||||||
childWidth = child->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = child->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
bool isCrossSizeDefinite = false;
|
bool isCrossSizeDefinite = false;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeight = crossDim;
|
childHeight = crossDim;
|
||||||
@@ -1237,7 +1237,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidth = crossDim;
|
childWidth = crossDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
||||||
if (!isCrossSizeDefinite) {
|
if (!isCrossSizeDefinite) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -1364,7 +1364,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
||||||
paddingAndBorderAxisCross);
|
paddingAndBorderAxisCross);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
bool needsMainTrailingPos = false;
|
bool needsMainTrailingPos = false;
|
||||||
@@ -1395,7 +1395,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
||||||
currentAbsoluteChild = firstAbsoluteChild;
|
currentAbsoluteChild = firstAbsoluteChild;
|
||||||
while (currentAbsoluteChild != NULL) {
|
while (currentAbsoluteChild != NULL) {
|
||||||
@@ -1417,7 +1417,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = currentAbsoluteChild->style.dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild->style.dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
} else {
|
} else {
|
||||||
@@ -1434,7 +1434,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -1457,9 +1457,9 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
childWidth = currentAbsoluteChild->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = currentAbsoluteChild->layout.measured_dimensions[CSS_WIDTH] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = currentAbsoluteChild->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild->layout.measured_dimensions[CSS_HEIGHT] + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, "abs-layout");
|
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, "abs-layout");
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
||||||
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
||||||
@@ -1467,7 +1467,7 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
|
|||||||
currentAbsoluteChild->layout.measured_dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
currentAbsoluteChild->layout.measured_dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
||||||
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
||||||
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
currentAbsoluteChild->layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
||||||
@@ -1508,11 +1508,11 @@ static const char* getModeName(css_measure_mode_t mode, bool performLayout) {
|
|||||||
"LAY_EXACTLY",
|
"LAY_EXACTLY",
|
||||||
"LAY_AT_MOST"
|
"LAY_AT_MOST"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (mode >= CSS_MEASURE_MODE_COUNT) {
|
if (mode >= CSS_MEASURE_MODE_COUNT) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return performLayout? kLayoutModeNames[mode] : kMeasureModeNames[mode];
|
return performLayout? kLayoutModeNames[mode] : kMeasureModeNames[mode];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1528,7 +1528,7 @@ static bool canUseCachedMeasurement(float availableWidth, float availableHeight,
|
|||||||
cachedLayout.height_measure_mode == heightMeasureMode) {
|
cachedLayout.height_measure_mode == heightMeasureMode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the width is an exact match, try a fuzzy match on the height.
|
// If the width is an exact match, try a fuzzy match on the height.
|
||||||
if (cachedLayout.width_measure_mode == widthMeasureMode &&
|
if (cachedLayout.width_measure_mode == widthMeasureMode &&
|
||||||
eq(cachedLayout.available_width, availableWidth) &&
|
eq(cachedLayout.available_width, availableWidth) &&
|
||||||
@@ -1536,7 +1536,7 @@ static bool canUseCachedMeasurement(float availableWidth, float availableHeight,
|
|||||||
eq(availableHeight - marginColumn, cachedLayout.computed_height)) {
|
eq(availableHeight - marginColumn, cachedLayout.computed_height)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the height is an exact match, try a fuzzy match on the width.
|
// If the height is an exact match, try a fuzzy match on the width.
|
||||||
if (cachedLayout.height_measure_mode == heightMeasureMode &&
|
if (cachedLayout.height_measure_mode == heightMeasureMode &&
|
||||||
eq(cachedLayout.available_height, availableHeight) &&
|
eq(cachedLayout.available_height, availableHeight) &&
|
||||||
@@ -1559,7 +1559,7 @@ static bool canUseCachedMeasurement(float availableWidth, float availableHeight,
|
|||||||
bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableHeight,
|
bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableHeight,
|
||||||
css_direction_t parentDirection, css_measure_mode_t widthMeasureMode, css_measure_mode_t heightMeasureMode, bool performLayout, char* reason) {
|
css_direction_t parentDirection, css_measure_mode_t widthMeasureMode, css_measure_mode_t heightMeasureMode, bool performLayout, char* reason) {
|
||||||
css_layout_t* layout = &node->layout;
|
css_layout_t* layout = &node->layout;
|
||||||
|
|
||||||
gDepth++;
|
gDepth++;
|
||||||
|
|
||||||
bool needToVisitNode = (node->is_dirty(node->context) && layout->generation_count != gCurrentGenerationCount) ||
|
bool needToVisitNode = (node->is_dirty(node->context) && layout->generation_count != gCurrentGenerationCount) ||
|
||||||
@@ -1573,7 +1573,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
}
|
}
|
||||||
|
|
||||||
css_cached_measurement_t* cachedResults = NULL;
|
css_cached_measurement_t* cachedResults = NULL;
|
||||||
|
|
||||||
// Determine whether the results are already cached. We maintain a separate
|
// Determine whether the results are already cached. We maintain a separate
|
||||||
// cache for layouts and measurements. A layout operation modifies the positions
|
// cache for layouts and measurements. A layout operation modifies the positions
|
||||||
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
||||||
@@ -1584,7 +1584,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
float marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
float marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
float marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
|
|
||||||
// First, try to use the layout cache.
|
// First, try to use the layout cache.
|
||||||
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||||
widthMeasureMode, heightMeasureMode, layout->cached_layout)) {
|
widthMeasureMode, heightMeasureMode, layout->cached_layout)) {
|
||||||
@@ -1604,7 +1604,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
eq(layout->cached_layout.available_height, availableHeight) &&
|
eq(layout->cached_layout.available_height, availableHeight) &&
|
||||||
layout->cached_layout.width_measure_mode == widthMeasureMode &&
|
layout->cached_layout.width_measure_mode == widthMeasureMode &&
|
||||||
layout->cached_layout.height_measure_mode == heightMeasureMode) {
|
layout->cached_layout.height_measure_mode == heightMeasureMode) {
|
||||||
|
|
||||||
cachedResults = &layout->cached_layout;
|
cachedResults = &layout->cached_layout;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1649,7 +1649,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
||||||
|
|
||||||
if (gPrintChanges) {
|
if (gPrintChanges) {
|
||||||
printf("%s%d.}%s", getSpacer(gDepth), gDepth, needToVisitNode ? "*" : "");
|
printf("%s%d.}%s", getSpacer(gDepth), gDepth, needToVisitNode ? "*" : "");
|
||||||
if (node->print) {
|
if (node->print) {
|
||||||
@@ -1662,7 +1662,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
}
|
}
|
||||||
|
|
||||||
layout->last_parent_direction = parentDirection;
|
layout->last_parent_direction = parentDirection;
|
||||||
|
|
||||||
if (cachedResults == NULL) {
|
if (cachedResults == NULL) {
|
||||||
if (layout->next_cached_measurements_index == CSS_MAX_CACHED_RESULT_COUNT) {
|
if (layout->next_cached_measurements_index == CSS_MAX_CACHED_RESULT_COUNT) {
|
||||||
if (gPrintChanges) {
|
if (gPrintChanges) {
|
||||||
@@ -1680,7 +1680,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
newCacheEntry = &layout->cached_measurements[layout->next_cached_measurements_index];
|
newCacheEntry = &layout->cached_measurements[layout->next_cached_measurements_index];
|
||||||
layout->next_cached_measurements_index++;
|
layout->next_cached_measurements_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
newCacheEntry->available_width = availableWidth;
|
newCacheEntry->available_width = availableWidth;
|
||||||
newCacheEntry->available_height = availableHeight;
|
newCacheEntry->available_height = availableHeight;
|
||||||
newCacheEntry->width_measure_mode = widthMeasureMode;
|
newCacheEntry->width_measure_mode = widthMeasureMode;
|
||||||
@@ -1689,7 +1689,7 @@ bool layoutNodeInternal(css_node_t* node, float availableWidth, float availableH
|
|||||||
newCacheEntry->computed_height = layout->measured_dimensions[CSS_HEIGHT];
|
newCacheEntry->computed_height = layout->measured_dimensions[CSS_HEIGHT];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
node->layout.dimensions[CSS_WIDTH] = node->layout.measured_dimensions[CSS_WIDTH];
|
node->layout.dimensions[CSS_WIDTH] = node->layout.measured_dimensions[CSS_WIDTH];
|
||||||
node->layout.dimensions[CSS_HEIGHT] = node->layout.measured_dimensions[CSS_HEIGHT];
|
node->layout.dimensions[CSS_HEIGHT] = node->layout.measured_dimensions[CSS_HEIGHT];
|
||||||
@@ -1706,7 +1706,7 @@ void layoutNode(css_node_t* node, float availableWidth, float availableHeight, c
|
|||||||
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
||||||
// parameters don't change.
|
// parameters don't change.
|
||||||
gCurrentGenerationCount++;
|
gCurrentGenerationCount++;
|
||||||
|
|
||||||
// If the caller didn't specify a height/width, use the dimensions
|
// If the caller didn't specify a height/width, use the dimensions
|
||||||
// specified in the style.
|
// specified in the style.
|
||||||
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
@@ -1715,10 +1715,10 @@ void layoutNode(css_node_t* node, float availableWidth, float availableHeight, c
|
|||||||
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
availableHeight = node->style.dimensions[CSS_HEIGHT] + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
availableHeight = node->style.dimensions[CSS_HEIGHT] + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
css_measure_mode_t widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
css_measure_mode_t widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
css_measure_mode_t heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
css_measure_mode_t heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, "initial")) {
|
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, "initial")) {
|
||||||
|
|
||||||
setPosition(node, node->layout.direction);
|
setPosition(node, node->layout.direction);
|
||||||
|
190
src/Layout.js
190
src/Layout.js
@@ -8,18 +8,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var computeLayout = (function() {
|
var computeLayout = (function() {
|
||||||
|
|
||||||
var POSITIVE_FLEX_IS_AUTO = false;
|
var POSITIVE_FLEX_IS_AUTO = false;
|
||||||
|
|
||||||
var gCurrentGenerationCount = 0;
|
var gCurrentGenerationCount = 0;
|
||||||
|
|
||||||
var CSS_UNDEFINED;
|
var CSS_UNDEFINED;
|
||||||
|
|
||||||
var CSS_LEFT = 'left';
|
var CSS_LEFT = 'left';
|
||||||
var CSS_TOP = 'top';
|
var CSS_TOP = 'top';
|
||||||
var CSS_RIGHT = 'right';
|
var CSS_RIGHT = 'right';
|
||||||
var CSS_BOTTOM = 'bottom';
|
var CSS_BOTTOM = 'bottom';
|
||||||
|
|
||||||
var CSS_DIRECTION_INHERIT = 'inherit';
|
var CSS_DIRECTION_INHERIT = 'inherit';
|
||||||
var CSS_DIRECTION_LTR = 'ltr';
|
var CSS_DIRECTION_LTR = 'ltr';
|
||||||
var CSS_DIRECTION_RTL = 'rtl';
|
var CSS_DIRECTION_RTL = 'rtl';
|
||||||
@@ -42,10 +42,10 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
var CSS_POSITION_RELATIVE = 'relative';
|
var CSS_POSITION_RELATIVE = 'relative';
|
||||||
var CSS_POSITION_ABSOLUTE = 'absolute';
|
var CSS_POSITION_ABSOLUTE = 'absolute';
|
||||||
|
|
||||||
var CSS_OVERFLOW_VISIBLE = 'visible';
|
var CSS_OVERFLOW_VISIBLE = 'visible';
|
||||||
var CSS_OVERFLOW_HIDDEN = 'hidden';
|
var CSS_OVERFLOW_HIDDEN = 'hidden';
|
||||||
|
|
||||||
var CSS_MEASURE_MODE_UNDEFINED = 'undefined';
|
var CSS_MEASURE_MODE_UNDEFINED = 'undefined';
|
||||||
var CSS_MEASURE_MODE_EXACTLY = 'exactly';
|
var CSS_MEASURE_MODE_EXACTLY = 'exactly';
|
||||||
var CSS_MEASURE_MODE_AT_MOST = 'at-most';
|
var CSS_MEASURE_MODE_AT_MOST = 'at-most';
|
||||||
@@ -125,14 +125,14 @@ var computeLayout = (function() {
|
|||||||
return flexDirection === CSS_FLEX_DIRECTION_COLUMN ||
|
return flexDirection === CSS_FLEX_DIRECTION_COLUMN ||
|
||||||
flexDirection === CSS_FLEX_DIRECTION_COLUMN_REVERSE;
|
flexDirection === CSS_FLEX_DIRECTION_COLUMN_REVERSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlex(node) {
|
function getFlex(node) {
|
||||||
if (node.style.flex === undefined) {
|
if (node.style.flex === undefined) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return node.style.flex;
|
return node.style.flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFlexBasisAuto(node) {
|
function isFlexBasisAuto(node) {
|
||||||
if (POSITIVE_FLEX_IS_AUTO) {
|
if (POSITIVE_FLEX_IS_AUTO) {
|
||||||
// All flex values are auto.
|
// All flex values are auto.
|
||||||
@@ -142,7 +142,7 @@ var computeLayout = (function() {
|
|||||||
return getFlex(node) <= 0;
|
return getFlex(node) <= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlexGrowFactor(node) {
|
function getFlexGrowFactor(node) {
|
||||||
// Flex grow is implied by positive values for flex.
|
// Flex grow is implied by positive values for flex.
|
||||||
if (getFlex(node) > 0) {
|
if (getFlex(node) > 0) {
|
||||||
@@ -150,7 +150,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlexShrinkFactor(node) {
|
function getFlexShrinkFactor(node) {
|
||||||
if (POSITIVE_FLEX_IS_AUTO) {
|
if (POSITIVE_FLEX_IS_AUTO) {
|
||||||
// A flex shrink factor of 1 is implied by non-zero values for flex.
|
// A flex shrink factor of 1 is implied by non-zero values for flex.
|
||||||
@@ -403,7 +403,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return CSS_POSITION_RELATIVE;
|
return CSS_POSITION_RELATIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOverflow(node) {
|
function getOverflow(node) {
|
||||||
if (node.style.overflow) {
|
if (node.style.overflow) {
|
||||||
return node.style.overflow;
|
return node.style.overflow;
|
||||||
@@ -425,12 +425,12 @@ var computeLayout = (function() {
|
|||||||
function getDimWithMargin(node, axis) {
|
function getDimWithMargin(node, axis) {
|
||||||
return node.layout[measuredDim[axis]] + getMarginAxis(node, axis);
|
return node.layout[measuredDim[axis]] + getMarginAxis(node, axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isStyleDimDefined(node, axis) {
|
function isStyleDimDefined(node, axis) {
|
||||||
return node.style[dim[axis]] !== undefined && node.style[dim[axis]] >= 0;
|
return node.style[dim[axis]] !== undefined && node.style[dim[axis]] >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLayoutDimDefined(node, axis) {
|
function isLayoutDimDefined(node, axis) {
|
||||||
return node.layout[measuredDim[axis]] !== undefined && node.layout[measuredDim[axis]] >= 0;
|
return node.layout[measuredDim[axis]] !== undefined && node.layout[measuredDim[axis]] >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +448,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function boundAxisWithinMinAndMax(node, axis, value) {
|
function boundAxisWithinMinAndMax(node, axis, value) {
|
||||||
var min = {
|
var min = {
|
||||||
'row': node.style.minWidth,
|
'row': node.style.minWidth,
|
||||||
@@ -473,7 +473,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return boundValue;
|
return boundValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fminf(a, b) {
|
function fminf(a, b) {
|
||||||
if (a < b) {
|
if (a < b) {
|
||||||
return a;
|
return a;
|
||||||
@@ -487,7 +487,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like boundAxisWithinMinAndMax but also ensures that the value doesn't go below the
|
// Like boundAxisWithinMinAndMax but also ensures that the value doesn't go below the
|
||||||
// padding and border amount.
|
// padding and border amount.
|
||||||
function boundAxis(node, axis, value) {
|
function boundAxis(node, axis, value) {
|
||||||
@@ -509,11 +509,11 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
return -getPosition(node, trailing[axis]);
|
return -getPosition(node, trailing[axis]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPosition(node, direction) {
|
function setPosition(node, direction) {
|
||||||
var mainAxis = resolveAxis(getFlexDirection(node), direction);
|
var mainAxis = resolveAxis(getFlexDirection(node), direction);
|
||||||
var crossAxis = getCrossFlexDirection(mainAxis, direction);
|
var crossAxis = getCrossFlexDirection(mainAxis, direction);
|
||||||
|
|
||||||
node.layout[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
node.layout[leading[mainAxis]] = getLeadingMargin(node, mainAxis) +
|
||||||
getRelativePosition(node, mainAxis);
|
getRelativePosition(node, mainAxis);
|
||||||
node.layout[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
node.layout[trailing[mainAxis]] = getTrailingMargin(node, mainAxis) +
|
||||||
@@ -523,13 +523,13 @@ var computeLayout = (function() {
|
|||||||
node.layout[trailing[crossAxis]] = getTrailingMargin(node, crossAxis) +
|
node.layout[trailing[crossAxis]] = getTrailingMargin(node, crossAxis) +
|
||||||
getRelativePosition(node, crossAxis);
|
getRelativePosition(node, crossAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assert(condition, message) {
|
function assert(condition, message) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is the main routine that implements a subset of the flexbox layout algorithm
|
// This is the main routine that implements a subset of the flexbox layout algorithm
|
||||||
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
||||||
@@ -566,8 +566,8 @@ var computeLayout = (function() {
|
|||||||
//
|
//
|
||||||
// Deviations from standard:
|
// Deviations from standard:
|
||||||
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
||||||
// main size. For text blocks, for example, this is the width of the widest word.
|
// main size. For text blocks, for example, this is the width of the widest word.
|
||||||
// Calculating the minimum width is expensive, so we forego it and assume a default
|
// Calculating the minimum width is expensive, so we forego it and assume a default
|
||||||
// minimum main size of 0.
|
// minimum main size of 0.
|
||||||
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
||||||
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
||||||
@@ -601,14 +601,14 @@ var computeLayout = (function() {
|
|||||||
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
||||||
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
||||||
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
||||||
//
|
//
|
||||||
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
||||||
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
||||||
//
|
//
|
||||||
function layoutNodeImpl(node, availableWidth, availableHeight, /*css_direction_t*/parentDirection, widthMeasureMode, heightMeasureMode, performLayout) {
|
function layoutNodeImpl(node, availableWidth, availableHeight, /*css_direction_t*/parentDirection, widthMeasureMode, heightMeasureMode, performLayout) {
|
||||||
assert(isUndefined(availableWidth) ? widthMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
assert(isUndefined(availableWidth) ? widthMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableWidth is indefinite so widthMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
||||||
assert(isUndefined(availableHeight) ? heightMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
assert(isUndefined(availableHeight) ? heightMeasureMode === CSS_MEASURE_MODE_UNDEFINED : true, 'availableHeight is indefinite so heightMeasureMode must be CSS_MEASURE_MODE_UNDEFINED');
|
||||||
|
|
||||||
var/*float*/ paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
var/*float*/ paddingAndBorderAxisRow = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
var/*float*/ paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
var/*float*/ paddingAndBorderAxisColumn = getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
var/*float*/ marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
var/*float*/ marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
@@ -622,7 +622,7 @@ var computeLayout = (function() {
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
var/*float*/ innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
var/*float*/ innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
||||||
var/*float*/ innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
var/*float*/ innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
||||||
|
|
||||||
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
||||||
|
|
||||||
// Don't bother sizing the text if both dimensions are already defined.
|
// Don't bother sizing the text if both dimensions are already defined.
|
||||||
@@ -654,7 +654,7 @@ var computeLayout = (function() {
|
|||||||
measureDim.height + paddingAndBorderAxisColumn :
|
measureDim.height + paddingAndBorderAxisColumn :
|
||||||
availableHeight - marginAxisColumn);
|
availableHeight - marginAxisColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,7 +684,7 @@ var computeLayout = (function() {
|
|||||||
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widthMeasureMode === CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
if (widthMeasureMode === CSS_MEASURE_MODE_AT_MOST && availableWidth <= 0) {
|
||||||
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
||||||
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, isUndefined(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
||||||
@@ -696,7 +696,7 @@ var computeLayout = (function() {
|
|||||||
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredHeight = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
||||||
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
if (widthMeasureMode === CSS_MEASURE_MODE_EXACTLY && heightMeasureMode === CSS_MEASURE_MODE_EXACTLY) {
|
||||||
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
node.layout.measuredWidth = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
||||||
@@ -720,7 +720,7 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
var/*float*/ leadingPaddingAndBorderCross = getLeadingPaddingAndBorder(node, crossAxis);
|
||||||
var/*float*/ paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
var/*float*/ paddingAndBorderAxisMain = getPaddingAndBorderAxis(node, mainAxis);
|
||||||
var/*float*/ paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
var/*float*/ paddingAndBorderAxisCross = getPaddingAndBorderAxis(node, crossAxis);
|
||||||
|
|
||||||
var/*css_measure_mode_t*/ measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
var/*css_measure_mode_t*/ measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
||||||
var/*css_measure_mode_t*/ measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
var/*css_measure_mode_t*/ measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
||||||
|
|
||||||
@@ -745,7 +745,7 @@ var computeLayout = (function() {
|
|||||||
var/*css_direction_t*/ childDirection = resolveDirection(child, direction);
|
var/*css_direction_t*/ childDirection = resolveDirection(child, direction);
|
||||||
setPosition(child, childDirection);
|
setPosition(child, childDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute-positioned children don't participate in flex layout. Add them
|
// Absolute-positioned children don't participate in flex layout. Add them
|
||||||
// to a list that we can process later.
|
// to a list that we can process later.
|
||||||
if (getPositionType(child) === CSS_POSITION_ABSOLUTE) {
|
if (getPositionType(child) === CSS_POSITION_ABSOLUTE) {
|
||||||
@@ -761,27 +761,27 @@ var computeLayout = (function() {
|
|||||||
currentAbsoluteChild = child;
|
currentAbsoluteChild = child;
|
||||||
child.nextChild = undefined;
|
child.nextChild = undefined;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
|
|
||||||
// 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.width, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
child.layout.flexBasis = fmaxf(child.style.width, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_ROW));
|
||||||
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
} else if (!isMainAxisRow && isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
|
|
||||||
// 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.height, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
child.layout.flexBasis = fmaxf(child.style.height, getPaddingAndBorderAxis(child, CSS_FLEX_DIRECTION_COLUMN));
|
||||||
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
} else if (!isFlexBasisAuto(child) && !isUndefined(availableInnerMainDim)) {
|
||||||
|
|
||||||
// If the basis isn't 'auto', it is assumed to be zero.
|
// If the basis isn't 'auto', it is assumed to be zero.
|
||||||
child.layout.flexBasis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
child.layout.flexBasis = fmaxf(0, getPaddingAndBorderAxis(child, mainAxis));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
||||||
childWidth = CSS_UNDEFINED;
|
childWidth = CSS_UNDEFINED;
|
||||||
childHeight = CSS_UNDEFINED;
|
childHeight = CSS_UNDEFINED;
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
|
||||||
|
|
||||||
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -790,7 +790,7 @@ var computeLayout = (function() {
|
|||||||
childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -811,21 +811,21 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
// Measure the child
|
// Measure the child
|
||||||
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, 'measure');
|
layoutNodeInternal(child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, 'measure');
|
||||||
|
|
||||||
child.layout.flexBasis = fmaxf(isMainAxisRow ? child.layout.measuredWidth : child.layout.measuredHeight, getPaddingAndBorderAxis(child, mainAxis));
|
child.layout.flexBasis = fmaxf(isMainAxisRow ? child.layout.measuredWidth : child.layout.measuredHeight, getPaddingAndBorderAxis(child, mainAxis));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
||||||
|
|
||||||
// Indexes of children that represent the first and last items in the line.
|
// Indexes of children that represent the first and last items in the line.
|
||||||
var/*int*/ startOfLineIndex = 0;
|
var/*int*/ startOfLineIndex = 0;
|
||||||
var/*int*/ endOfLineIndex = 0;
|
var/*int*/ endOfLineIndex = 0;
|
||||||
|
|
||||||
// Number of lines.
|
// Number of lines.
|
||||||
var/*int*/ lineCount = 0;
|
var/*int*/ lineCount = 0;
|
||||||
|
|
||||||
// Accumulated cross dimensions of all lines so far.
|
// Accumulated cross dimensions of all lines so far.
|
||||||
var/*float*/ totalLineCrossDim = 0;
|
var/*float*/ totalLineCrossDim = 0;
|
||||||
|
|
||||||
@@ -833,7 +833,7 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ maxLineMainDim = 0;
|
var/*float*/ maxLineMainDim = 0;
|
||||||
|
|
||||||
while (endOfLineIndex < childCount) {
|
while (endOfLineIndex < childCount) {
|
||||||
|
|
||||||
// Number of items on the currently line. May be different than the difference
|
// Number of items on the currently line. May be different than the difference
|
||||||
// between start and end indicates because we skip over absolute-positioned items.
|
// between start and end indicates because we skip over absolute-positioned items.
|
||||||
var/*int*/ itemsOnLine = 0;
|
var/*int*/ itemsOnLine = 0;
|
||||||
@@ -860,7 +860,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (getPositionType(child) !== CSS_POSITION_ABSOLUTE) {
|
if (getPositionType(child) !== CSS_POSITION_ABSOLUTE) {
|
||||||
var/*float*/ outerFlexBasis = child.layout.flexBasis + getMarginAxis(child, mainAxis);
|
var/*float*/ outerFlexBasis = child.layout.flexBasis + getMarginAxis(child, mainAxis);
|
||||||
|
|
||||||
// If this is a multi-line flow and this item pushes us over the available size, we've
|
// If this is a multi-line flow and this item pushes us over the available size, we've
|
||||||
// hit the end of the current line. Break out of the loop and lay out the current line.
|
// hit the end of the current line. Break out of the loop and lay out the current line.
|
||||||
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
||||||
@@ -872,7 +872,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (isFlex(child)) {
|
if (isFlex(child)) {
|
||||||
totalFlexGrowFactors += getFlexGrowFactor(child);
|
totalFlexGrowFactors += getFlexGrowFactor(child);
|
||||||
|
|
||||||
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
||||||
// dimension.
|
// dimension.
|
||||||
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
||||||
@@ -888,11 +888,11 @@ var computeLayout = (function() {
|
|||||||
currentRelativeChild = child;
|
currentRelativeChild = child;
|
||||||
child.nextChild = undefined;
|
child.nextChild = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
endOfLineIndex++;
|
endOfLineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
||||||
var/*bool*/ canSkipFlex = !performLayout && measureModeCrossDim === CSS_MEASURE_MODE_EXACTLY;
|
var/*bool*/ canSkipFlex = !performLayout && measureModeCrossDim === CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
@@ -915,7 +915,7 @@ var computeLayout = (function() {
|
|||||||
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
||||||
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
var/*float*/ originalRemainingFreeSpace = remainingFreeSpace;
|
var/*float*/ originalRemainingFreeSpace = remainingFreeSpace;
|
||||||
var/*float*/ deltaFreeSpace = 0;
|
var/*float*/ deltaFreeSpace = 0;
|
||||||
|
|
||||||
@@ -925,20 +925,20 @@ var computeLayout = (function() {
|
|||||||
var/*float*/ flexGrowFactor;
|
var/*float*/ flexGrowFactor;
|
||||||
var/*float*/ baseMainSize;
|
var/*float*/ baseMainSize;
|
||||||
var/*float*/ boundMainSize;
|
var/*float*/ boundMainSize;
|
||||||
|
|
||||||
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
||||||
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
||||||
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
||||||
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
||||||
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
||||||
// their min/max constraints to trigger again.
|
// their min/max constraints to trigger again.
|
||||||
//
|
//
|
||||||
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
||||||
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
||||||
// that needs to be repeated a variable number of times. The algorithm implemented here
|
// that needs to be repeated a variable number of times. The algorithm implemented here
|
||||||
// won't handle all cases but it was simpler to implement and it mitigates performance
|
// won't handle all cases but it was simpler to implement and it mitigates performance
|
||||||
// concerns because we know exactly how many passes it'll do.
|
// concerns because we know exactly how many passes it'll do.
|
||||||
|
|
||||||
// First pass: detect the flex items whose min/max constraints trigger
|
// First pass: detect the flex items whose min/max constraints trigger
|
||||||
var/*float*/ deltaFlexShrinkScaledFactors = 0;
|
var/*float*/ deltaFlexShrinkScaledFactors = 0;
|
||||||
var/*float*/ deltaFlexGrowFactors = 0;
|
var/*float*/ deltaFlexGrowFactors = 0;
|
||||||
@@ -948,7 +948,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor !== 0) {
|
if (flexShrinkScaledFactor !== 0) {
|
||||||
baseMainSize = childFlexBasis +
|
baseMainSize = childFlexBasis +
|
||||||
@@ -979,14 +979,14 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
||||||
totalFlexGrowFactors += deltaFlexGrowFactors;
|
totalFlexGrowFactors += deltaFlexGrowFactors;
|
||||||
remainingFreeSpace += deltaFreeSpace;
|
remainingFreeSpace += deltaFreeSpace;
|
||||||
|
|
||||||
// Second pass: resolve the sizes of the flexible items
|
// Second pass: resolve the sizes of the flexible items
|
||||||
deltaFreeSpace = 0;
|
deltaFreeSpace = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
@@ -996,7 +996,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor !== 0) {
|
if (flexShrinkScaledFactor !== 0) {
|
||||||
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
||||||
@@ -1011,13 +1011,13 @@ var computeLayout = (function() {
|
|||||||
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = availableInnerCrossDim;
|
childHeight = availableInnerCrossDim;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1028,7 +1028,7 @@ var computeLayout = (function() {
|
|||||||
} else {
|
} else {
|
||||||
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = updatedMainSize + getMarginAxis(currentRelativeChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
if (!isStyleDimDefined(currentRelativeChild, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
childWidth = availableInnerCrossDim;
|
childWidth = availableInnerCrossDim;
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
|
||||||
@@ -1037,7 +1037,7 @@ var computeLayout = (function() {
|
|||||||
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var/*bool*/ requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
var/*bool*/ requiresStretchLayout = !isStyleDimDefined(currentRelativeChild, crossAxis) &&
|
||||||
getAlignItem(node, currentRelativeChild) === CSS_ALIGN_STRETCH;
|
getAlignItem(node, currentRelativeChild) === CSS_ALIGN_STRETCH;
|
||||||
|
|
||||||
@@ -1047,7 +1047,7 @@ var computeLayout = (function() {
|
|||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
||||||
|
|
||||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||||
@@ -1106,7 +1106,7 @@ var computeLayout = (function() {
|
|||||||
// we put it at the current accumulated offset.
|
// we put it at the current accumulated offset.
|
||||||
child.layout[pos[mainAxis]] += mainDim;
|
child.layout[pos[mainAxis]] += mainDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we placed the element, we need to update the variables.
|
// Now that we placed the element, we need to update the variables.
|
||||||
// We need to do that only for relative elements. Absolute elements
|
// We need to do that only for relative elements. Absolute elements
|
||||||
// do not take part in that phase.
|
// do not take part in that phase.
|
||||||
@@ -1120,7 +1120,7 @@ var computeLayout = (function() {
|
|||||||
// The main dimension is the sum of all the elements dimension plus
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
// the spacing.
|
// the spacing.
|
||||||
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
mainDim += betweenMainDim + getDimWithMargin(child, mainAxis);
|
||||||
|
|
||||||
// The cross dimension is the max of the elements dimension since there
|
// The cross dimension is the max of the elements dimension since there
|
||||||
// can only be one element in that cross dimension.
|
// can only be one element in that cross dimension.
|
||||||
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
crossDim = fmaxf(crossDim, getDimWithMargin(child, crossAxis));
|
||||||
@@ -1130,12 +1130,12 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainDim += trailingPaddingAndBorderMain;
|
mainDim += trailingPaddingAndBorderMain;
|
||||||
|
|
||||||
var/*float*/ containerCrossAxis = availableInnerCrossDim;
|
var/*float*/ containerCrossAxis = availableInnerCrossDim;
|
||||||
if (measureModeCrossDim === CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim === CSS_MEASURE_MODE_UNDEFINED || measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
||||||
// Compute the cross axis from the max cross dimension of the children.
|
// Compute the cross axis from the max cross dimension of the children.
|
||||||
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
||||||
|
|
||||||
if (measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
if (measureModeCrossDim === CSS_MEASURE_MODE_AT_MOST) {
|
||||||
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
containerCrossAxis = fminf(containerCrossAxis, availableInnerCrossDim);
|
||||||
}
|
}
|
||||||
@@ -1172,14 +1172,14 @@ var computeLayout = (function() {
|
|||||||
// For a relative children, we're either using alignItems (parent) or
|
// For a relative children, we're either using alignItems (parent) or
|
||||||
// alignSelf (child) in order to determine the position in the cross axis
|
// alignSelf (child) in order to determine the position in the cross axis
|
||||||
var/*css_align_t*/ alignItem = getAlignItem(node, child);
|
var/*css_align_t*/ alignItem = getAlignItem(node, child);
|
||||||
|
|
||||||
// If the child uses align stretch, we need to lay it out one more time, this time
|
// If the child uses align stretch, we need to lay it out one more time, this time
|
||||||
// forcing the cross-axis size to be the computed cross size for the current line.
|
// forcing the cross-axis size to be the computed cross size for the current line.
|
||||||
if (alignItem === CSS_ALIGN_STRETCH) {
|
if (alignItem === CSS_ALIGN_STRETCH) {
|
||||||
childWidth = child.layout.measuredWidth + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
childWidth = child.layout.measuredWidth + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = child.layout.measuredHeight + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = child.layout.measuredHeight + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
var/*bool*/ isCrossSizeDefinite = false;
|
var/*bool*/ isCrossSizeDefinite = false;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
childHeight = crossDim;
|
childHeight = crossDim;
|
||||||
@@ -1187,7 +1187,7 @@ var computeLayout = (function() {
|
|||||||
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
isCrossSizeDefinite = isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW);
|
||||||
childWidth = crossDim;
|
childWidth = crossDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
||||||
if (!isCrossSizeDefinite) {
|
if (!isCrossSizeDefinite) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
@@ -1314,7 +1314,7 @@ var computeLayout = (function() {
|
|||||||
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
||||||
paddingAndBorderAxisCross);
|
paddingAndBorderAxisCross);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
var/*bool*/ needsMainTrailingPos = false;
|
var/*bool*/ needsMainTrailingPos = false;
|
||||||
@@ -1345,7 +1345,7 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
||||||
currentAbsoluteChild = firstAbsoluteChild;
|
currentAbsoluteChild = firstAbsoluteChild;
|
||||||
while (currentAbsoluteChild !== undefined) {
|
while (currentAbsoluteChild !== undefined) {
|
||||||
@@ -1367,7 +1367,7 @@ var computeLayout = (function() {
|
|||||||
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isStyleDimDefined(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
childHeight = currentAbsoluteChild.style.height + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild.style.height + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
} else {
|
} else {
|
||||||
@@ -1384,7 +1384,7 @@ var computeLayout = (function() {
|
|||||||
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
if (isUndefined(childWidth) || isUndefined(childHeight)) {
|
||||||
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -1407,9 +1407,9 @@ var computeLayout = (function() {
|
|||||||
childWidth = currentAbsoluteChild.layout.measuredWidth + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
childWidth = currentAbsoluteChild.layout.measuredWidth + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW);
|
||||||
childHeight = currentAbsoluteChild.layout.measuredHeight + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
childHeight = currentAbsoluteChild.layout.measuredHeight + getMarginAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, 'abs-layout');
|
layoutNodeInternal(currentAbsoluteChild, childWidth, childHeight, direction, CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY, true, 'abs-layout');
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_ROW])) {
|
||||||
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_ROW]] =
|
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_ROW]] =
|
||||||
@@ -1417,7 +1417,7 @@ var computeLayout = (function() {
|
|||||||
currentAbsoluteChild.layout[measuredDim[CSS_FLEX_DIRECTION_ROW]] -
|
currentAbsoluteChild.layout[measuredDim[CSS_FLEX_DIRECTION_ROW]] -
|
||||||
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
getPosition(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_ROW]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
if (isPosDefined(currentAbsoluteChild, trailing[CSS_FLEX_DIRECTION_COLUMN]) &&
|
||||||
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
!isPosDefined(currentAbsoluteChild, leading[CSS_FLEX_DIRECTION_COLUMN])) {
|
||||||
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
currentAbsoluteChild.layout[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
||||||
@@ -1430,7 +1430,7 @@ var computeLayout = (function() {
|
|||||||
currentAbsoluteChild = currentAbsoluteChild.nextChild;
|
currentAbsoluteChild = currentAbsoluteChild.nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function canUseCachedMeasurement(availableWidth, availableHeight,
|
function canUseCachedMeasurement(availableWidth, availableHeight,
|
||||||
marginRow, marginColumn,
|
marginRow, marginColumn,
|
||||||
widthMeasureMode, heightMeasureMode,
|
widthMeasureMode, heightMeasureMode,
|
||||||
@@ -1443,7 +1443,7 @@ var computeLayout = (function() {
|
|||||||
cachedLayout.heightMeasureMode === heightMeasureMode) {
|
cachedLayout.heightMeasureMode === heightMeasureMode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the width is an exact match, try a fuzzy match on the height.
|
// If the width is an exact match, try a fuzzy match on the height.
|
||||||
if (cachedLayout.availableWidth === availableWidth &&
|
if (cachedLayout.availableWidth === availableWidth &&
|
||||||
cachedLayout.widthMeasureMode === widthMeasureMode &&
|
cachedLayout.widthMeasureMode === widthMeasureMode &&
|
||||||
@@ -1451,7 +1451,7 @@ var computeLayout = (function() {
|
|||||||
availableHeight - marginColumn === cachedLayout.computedHeight) {
|
availableHeight - marginColumn === cachedLayout.computedHeight) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the height is an exact match, try a fuzzy match on the width.
|
// If the height is an exact match, try a fuzzy match on the width.
|
||||||
if (cachedLayout.availableHeight === availableHeight &&
|
if (cachedLayout.availableHeight === availableHeight &&
|
||||||
cachedLayout.heightMeasureMode === heightMeasureMode &&
|
cachedLayout.heightMeasureMode === heightMeasureMode &&
|
||||||
@@ -1462,7 +1462,7 @@ var computeLayout = (function() {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is a wrapper around the layoutNodeImpl function. It determines
|
// This is a wrapper around the layoutNodeImpl function. It determines
|
||||||
// whether the layout request is redundant and can be skipped.
|
// whether the layout request is redundant and can be skipped.
|
||||||
@@ -1481,18 +1481,18 @@ var computeLayout = (function() {
|
|||||||
if (needToVisitNode) {
|
if (needToVisitNode) {
|
||||||
// Invalidate the cached results.
|
// Invalidate the cached results.
|
||||||
if (layout.cachedMeasurements !== undefined) {
|
if (layout.cachedMeasurements !== undefined) {
|
||||||
layout.cachedMeasurements = [];
|
layout.cachedMeasurements = [];
|
||||||
}
|
}
|
||||||
if (layout.cachedLayout !== undefined) {
|
if (layout.cachedLayout !== undefined) {
|
||||||
layout.cachedLayout.widthMeasureMode = undefined;
|
layout.cachedLayout.widthMeasureMode = undefined;
|
||||||
layout.cachedLayout.heightMeasureMode = undefined;
|
layout.cachedLayout.heightMeasureMode = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
var len;
|
var len;
|
||||||
var cachedResults;
|
var cachedResults;
|
||||||
|
|
||||||
// Determine whether the results are already cached. We maintain a separate
|
// Determine whether the results are already cached. We maintain a separate
|
||||||
// cache for layouts and measurements. A layout operation modifies the positions
|
// cache for layouts and measurements. A layout operation modifies the positions
|
||||||
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
||||||
@@ -1503,7 +1503,7 @@ var computeLayout = (function() {
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
var marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
var marginAxisRow = getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
|
||||||
var marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
var marginAxisColumn = getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
|
|
||||||
// First, try to use the layout cache.
|
// First, try to use the layout cache.
|
||||||
if (layout.cachedLayout &&
|
if (layout.cachedLayout &&
|
||||||
canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||||
@@ -1538,14 +1538,14 @@ var computeLayout = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needToVisitNode && cachedResults !== undefined) {
|
if (!needToVisitNode && cachedResults !== undefined) {
|
||||||
layout.measureWidth = cachedResults.computedWidth;
|
layout.measureWidth = cachedResults.computedWidth;
|
||||||
layout.measureHeight = cachedResults.computedHeight;
|
layout.measureHeight = cachedResults.computedHeight;
|
||||||
} else {
|
} else {
|
||||||
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
layoutNodeImpl(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
||||||
layout.lastParentDirection = parentDirection;
|
layout.lastParentDirection = parentDirection;
|
||||||
|
|
||||||
if (cachedResults === undefined) {
|
if (cachedResults === undefined) {
|
||||||
var newCacheEntry;
|
var newCacheEntry;
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
@@ -1562,7 +1562,7 @@ var computeLayout = (function() {
|
|||||||
newCacheEntry = {};
|
newCacheEntry = {};
|
||||||
layout.cachedMeasurements.push(newCacheEntry);
|
layout.cachedMeasurements.push(newCacheEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
newCacheEntry.availableWidth = availableWidth;
|
newCacheEntry.availableWidth = availableWidth;
|
||||||
newCacheEntry.availableHeight = availableHeight;
|
newCacheEntry.availableHeight = availableHeight;
|
||||||
newCacheEntry.widthMeasureMode = widthMeasureMode;
|
newCacheEntry.widthMeasureMode = widthMeasureMode;
|
||||||
@@ -1571,23 +1571,23 @@ var computeLayout = (function() {
|
|||||||
newCacheEntry.computedHeight = layout.measuredHeight;
|
newCacheEntry.computedHeight = layout.measuredHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
node.layout.width = node.layout.measuredWidth;
|
node.layout.width = node.layout.measuredWidth;
|
||||||
node.layout.height = node.layout.measuredHeight;
|
node.layout.height = node.layout.measuredHeight;
|
||||||
layout.shouldUpdate = true;
|
layout.shouldUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.generationCount = gCurrentGenerationCount;
|
layout.generationCount = gCurrentGenerationCount;
|
||||||
return (needToVisitNode || cachedResults === undefined);
|
return (needToVisitNode || cachedResults === undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
function layoutNode(node, availableWidth, availableHeight, parentDirection) {
|
function layoutNode(node, availableWidth, availableHeight, parentDirection) {
|
||||||
// Increment the generation count. This will force the recursive routine to visit
|
// Increment the generation count. This will force the recursive routine to visit
|
||||||
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
||||||
// parameters don't change.
|
// parameters don't change.
|
||||||
gCurrentGenerationCount++;
|
gCurrentGenerationCount++;
|
||||||
|
|
||||||
// If the caller didn't specify a height/width, use the dimensions
|
// If the caller didn't specify a height/width, use the dimensions
|
||||||
// specified in the style.
|
// specified in the style.
|
||||||
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
if (isUndefined(availableWidth) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
|
||||||
@@ -1596,10 +1596,10 @@ var computeLayout = (function() {
|
|||||||
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
if (isUndefined(availableHeight) && isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
|
||||||
availableHeight = node.style.height + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
availableHeight = node.style.height + getMarginAxis(node, CSS_FLEX_DIRECTION_COLUMN);
|
||||||
}
|
}
|
||||||
|
|
||||||
var widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
var widthMeasureMode = isUndefined(availableWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
var heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
var heightMeasureMode = isUndefined(availableHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_EXACTLY;
|
||||||
|
|
||||||
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, 'initial')) {
|
if (layoutNodeInternal(node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, 'initial')) {
|
||||||
setPosition(node, node.layout.direction);
|
setPosition(node, node.layout.direction);
|
||||||
}
|
}
|
||||||
|
@@ -39,14 +39,14 @@ describe('Javascript Only', function() {
|
|||||||
{layout: {width: 200}},
|
{layout: {width: 200}},
|
||||||
{layout: {width: 200}, style: {}, children: []}
|
{layout: {width: 200}, style: {}, children: []}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('should only invoke measure function one time in simple layout', function() {
|
it('should only invoke measure function one time in simple layout', function() {
|
||||||
var measureInvocations = 0;
|
var measureInvocations = 0;
|
||||||
function measure(width, widthMode, height, heightMode) {
|
function measure(width, widthMode, height, heightMode) {
|
||||||
measureInvocations++;
|
measureInvocations++;
|
||||||
return { width: 25, height: 25 };
|
return { width: 25, height: 25 };
|
||||||
}
|
}
|
||||||
|
|
||||||
testLayoutAgainstExpectedOnly(
|
testLayoutAgainstExpectedOnly(
|
||||||
{style: {width: 100, height: 100}, children: [
|
{style: {width: 100, height: 100}, children: [
|
||||||
{style: {measure: measure}}
|
{style: {measure: measure}}
|
||||||
@@ -55,17 +55,17 @@ describe('Javascript Only', function() {
|
|||||||
{width: 100, height: 25, top: 0, left: 0}
|
{width: 100, height: 25, top: 0, left: 0}
|
||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(measureInvocations).toEqual(1);
|
expect(measureInvocations).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
||||||
var measureModes = ['undefined', 'exactly', 'at-most'];
|
var measureModes = ['undefined', 'exactly', 'at-most'];
|
||||||
|
|
||||||
var assertCanReuse = testCanUseCachedMeasurement.bind(null, true);
|
var assertCanReuse = testCanUseCachedMeasurement.bind(null, true);
|
||||||
var assertCannotReuse = testCanUseCachedMeasurement.bind(null, false);
|
var assertCannotReuse = testCanUseCachedMeasurement.bind(null, false);
|
||||||
|
|
||||||
it('should not reuse when width mode is "exactly" and available width != measurement', function() {
|
it('should not reuse when width mode is "exactly" and available width != measurement', function() {
|
||||||
measureModes.forEach(function(widthMeasureMode) {
|
measureModes.forEach(function(widthMeasureMode) {
|
||||||
measureModes.forEach(function(heightMeasureMode) {
|
measureModes.forEach(function(heightMeasureMode) {
|
||||||
@@ -73,12 +73,12 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
var computedHeight = 200;
|
var computedHeight = 200;
|
||||||
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
||||||
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
||||||
|
|
||||||
var cacheEntry = {
|
var cacheEntry = {
|
||||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: computedWidth,
|
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: computedWidth,
|
||||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: computedHeight
|
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: computedHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
assertCannotReuse(
|
assertCannotReuse(
|
||||||
{
|
{
|
||||||
availableWidth: computedWidth - 1, widthMeasureMode: 'exactly',
|
availableWidth: computedWidth - 1, widthMeasureMode: 'exactly',
|
||||||
@@ -86,7 +86,7 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
},
|
},
|
||||||
cacheEntry
|
cacheEntry
|
||||||
);
|
);
|
||||||
|
|
||||||
assertCannotReuse(
|
assertCannotReuse(
|
||||||
{
|
{
|
||||||
availableWidth: computedWidth + 1, widthMeasureMode: 'exactly',
|
availableWidth: computedWidth + 1, widthMeasureMode: 'exactly',
|
||||||
@@ -97,7 +97,7 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not reuse when height mode is "exactly" and available height != measurement', function() {
|
it('should not reuse when height mode is "exactly" and available height != measurement', function() {
|
||||||
measureModes.forEach(function(widthMeasureMode) {
|
measureModes.forEach(function(widthMeasureMode) {
|
||||||
measureModes.forEach(function(heightMeasureMode) {
|
measureModes.forEach(function(heightMeasureMode) {
|
||||||
@@ -105,12 +105,12 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
var computedHeight = 200;
|
var computedHeight = 200;
|
||||||
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
||||||
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
||||||
|
|
||||||
var cacheEntry = {
|
var cacheEntry = {
|
||||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: computedWidth,
|
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: computedWidth,
|
||||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: computedHeight
|
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: computedHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
assertCannotReuse(
|
assertCannotReuse(
|
||||||
{
|
{
|
||||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
||||||
@@ -118,7 +118,7 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
},
|
},
|
||||||
cacheEntry
|
cacheEntry
|
||||||
);
|
);
|
||||||
|
|
||||||
assertCannotReuse(
|
assertCannotReuse(
|
||||||
{
|
{
|
||||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
||||||
@@ -129,7 +129,7 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reuse exact matches', function() {
|
it('should reuse exact matches', function() {
|
||||||
measureModes.forEach(function(widthMeasureMode) {
|
measureModes.forEach(function(widthMeasureMode) {
|
||||||
measureModes.forEach(function(heightMeasureMode) {
|
measureModes.forEach(function(heightMeasureMode) {
|
||||||
@@ -148,13 +148,13 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reuse cache entry with unconstrained width when width mode is "exactly" and available width == measurement', function() {
|
it('should reuse cache entry with unconstrained width when width mode is "exactly" and available width == measurement', function() {
|
||||||
measureModes.forEach(function(heightMeasureMode) {
|
measureModes.forEach(function(heightMeasureMode) {
|
||||||
var computedWidth = 100;
|
var computedWidth = 100;
|
||||||
var computedHeight = 200;
|
var computedHeight = 200;
|
||||||
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
||||||
|
|
||||||
assertCanReuse(
|
assertCanReuse(
|
||||||
{
|
{
|
||||||
availableWidth: computedWidth, widthMeasureMode: 'exactly',
|
availableWidth: computedWidth, widthMeasureMode: 'exactly',
|
||||||
@@ -167,13 +167,13 @@ describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reuse cache entry with unconstrained height when height mode is "exactly" and height == measurement', function() {
|
it('should reuse cache entry with unconstrained height when height mode is "exactly" and height == measurement', function() {
|
||||||
measureModes.forEach(function(widthMeasureMode) {
|
measureModes.forEach(function(widthMeasureMode) {
|
||||||
var computedWidth = 100;
|
var computedWidth = 100;
|
||||||
var computedHeight = 200;
|
var computedHeight = 200;
|
||||||
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
||||||
|
|
||||||
assertCanReuse(
|
assertCanReuse(
|
||||||
{
|
{
|
||||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
||||||
@@ -2298,7 +2298,7 @@ describe('Layout', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should center flexible item with max size', function() {
|
it('should center flexible item with max size', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 1000, height: 1000, flexDirection: 'row', justifyContent: 'center'}, children: [
|
{style: {width: 1000, height: 1000, flexDirection: 'row', justifyContent: 'center'}, children: [
|
||||||
@@ -2309,7 +2309,7 @@ describe('Layout', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly size flexible items with flex basis and a max width', function() {
|
it('should correctly size flexible items with flex basis and a max width', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 1000, height: 1000, flexDirection: 'row'}, children: [
|
{style: {width: 1000, height: 1000, flexDirection: 'row'}, children: [
|
||||||
@@ -2660,7 +2660,7 @@ describe('Layout', function() {
|
|||||||
|
|
||||||
describe('Layout flex:-1', function() {
|
describe('Layout flex:-1', function() {
|
||||||
// Tests for items with flex:-1 in a container with flexDirection:column
|
// Tests for items with flex:-1 in a container with flexDirection:column
|
||||||
|
|
||||||
it('should not shrink column node when there is space left over', function() {
|
it('should not shrink column node when there is space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100}, children: [
|
{style: {width: 100, height: 100}, children: [
|
||||||
@@ -2675,7 +2675,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink column node when there is not any space left over', function() {
|
it('should shrink column node when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100}, children: [
|
{style: {width: 100, height: 100}, children: [
|
||||||
@@ -2690,7 +2690,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not shrink column node with siblings when there is space left over', function() {
|
it('should not shrink column node with siblings when there is space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100}, children: [
|
{style: {width: 100, height: 100}, children: [
|
||||||
@@ -2709,7 +2709,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink column node with siblings when there is not any space left over', function() {
|
it('should shrink column node with siblings when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100}, children: [
|
{style: {width: 100, height: 100}, children: [
|
||||||
@@ -2728,7 +2728,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink column nodes proportional to their main size when there is not any space left over', function() {
|
it('should shrink column nodes proportional to their main size when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100}, children: [
|
{style: {width: 100, height: 100}, children: [
|
||||||
@@ -2743,9 +2743,9 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tests for items with flex:-1 and overflow:visible in a container with flexDirection:row
|
// Tests for items with flex:-1 and overflow:visible in a container with flexDirection:row
|
||||||
|
|
||||||
it('should not shrink visible row node when there is space left over', function() {
|
it('should not shrink visible row node when there is space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2760,7 +2760,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink visible row node when there is not any space left over', function() {
|
it('should shrink visible row node when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2776,7 +2776,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not shrink visible row node with siblings when there is space left over', function() {
|
it('should not shrink visible row node with siblings when there is space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2795,7 +2795,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink visible row node with siblings when there is not any space left over', function() {
|
it('should shrink visible row node with siblings when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2815,7 +2815,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink visible row nodes when there is not any space left over', function() {
|
it('should shrink visible row nodes when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2832,9 +2832,9 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tests for items with flex:-1 and overflow:hidden in a container with flexDirection:row
|
// Tests for items with flex:-1 and overflow:hidden in a container with flexDirection:row
|
||||||
|
|
||||||
it('should not shrink hidden row node when there is space left over', function() {
|
it('should not shrink hidden row node when there is space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2864,7 +2864,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not shrink hidden row node with siblings when there is space left over', function() {
|
it('should not shrink hidden row node with siblings when there is space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2883,7 +2883,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink hidden row node with siblings when there is not any space left over', function() {
|
it('should shrink hidden row node with siblings when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2902,7 +2902,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink hidden row nodes proportional to their main size when there is not any space left over', function() {
|
it('should shrink hidden row nodes proportional to their main size when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2917,9 +2917,9 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tests for items with flex:-1 containing a text node
|
// Tests for items with flex:-1 containing a text node
|
||||||
|
|
||||||
it('should not shrink text node with siblings when there is space left over', function() {
|
it('should not shrink text node with siblings when there is space left over', function() {
|
||||||
testLayoutAgainstExpectedOnly(
|
testLayoutAgainstExpectedOnly(
|
||||||
{style: {width: 213, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 213, height: 100, flexDirection: 'row'}, children: [
|
||||||
@@ -2938,7 +2938,7 @@ describe('Layout flex:-1', function() {
|
|||||||
]}
|
]}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should shrink text node with siblings when there is not any space left over', function() {
|
it('should shrink text node with siblings when there is not any space left over', function() {
|
||||||
testLayout(
|
testLayout(
|
||||||
{style: {width: 140, height: 100, flexDirection: 'row'}, children: [
|
{style: {width: 140, height: 100, flexDirection: 'row'}, children: [
|
||||||
|
@@ -60,7 +60,7 @@
|
|||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
</Target>
|
</Target>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="NUnit" version="2.6.4" targetFramework="net45" />
|
<package id="NUnit" version="2.6.4" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
||||||
|
@@ -18,7 +18,7 @@ namespace Facebook.CSSLayout
|
|||||||
Debug.Assert(v != null);
|
Debug.Assert(v != null);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertCondition(bool condition, string explanation)
|
public static void assertCondition(bool condition, string explanation)
|
||||||
{
|
{
|
||||||
Debug.Assert(condition, explanation);
|
Debug.Assert(condition, explanation);
|
||||||
|
@@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
namespace Facebook.CSSLayout
|
namespace Facebook.CSSLayout
|
||||||
{
|
{
|
||||||
public static class CSSConstants
|
public static class CSSConstants
|
||||||
{
|
{
|
||||||
public const float Undefined = float.NaN;
|
public const float Undefined = float.NaN;
|
||||||
|
|
||||||
public static bool IsUndefined(float value)
|
public static bool IsUndefined(float value)
|
||||||
{
|
{
|
||||||
return float.IsNaN(value);
|
return float.IsNaN(value);
|
||||||
}
|
}
|
||||||
|
@@ -16,4 +16,4 @@ namespace Facebook.CSSLayout
|
|||||||
Row,
|
Row,
|
||||||
RowReverse
|
RowReverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,4 +21,4 @@ namespace Facebook.CSSLayout
|
|||||||
End = 7,
|
End = 7,
|
||||||
All = 8
|
All = 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -63,11 +63,11 @@
|
|||||||
<Compile Include="CSSSpacingType.cs" />
|
<Compile Include="CSSSpacingType.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
</Target>
|
</Target>
|
||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -156,7 +156,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
return boundValue;
|
return boundValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float boundAxis(CSSNode node, int axis, float value)
|
private static float boundAxis(CSSNode node, int axis, float value)
|
||||||
{
|
{
|
||||||
float paddingAndBorderAxis =
|
float paddingAndBorderAxis =
|
||||||
@@ -178,12 +178,12 @@ namespace Facebook.CSSLayout
|
|||||||
float trailingPos = node.style.position[trailing[axis]];
|
float trailingPos = node.style.position[trailing[axis]];
|
||||||
return float.IsNaN(trailingPos) ? 0 : -trailingPos;
|
return float.IsNaN(trailingPos) ? 0 : -trailingPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setPosition(CSSNode node, CSSDirection direction)
|
private static void setPosition(CSSNode node, CSSDirection direction)
|
||||||
{
|
{
|
||||||
int mainAxis = resolveAxis(getFlexDirection(node), direction);
|
int mainAxis = resolveAxis(getFlexDirection(node), direction);
|
||||||
int crossAxis = getCrossFlexDirection(mainAxis, direction);
|
int crossAxis = getCrossFlexDirection(mainAxis, direction);
|
||||||
|
|
||||||
node.layout.position[leading[mainAxis]] = node.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) +
|
node.layout.position[leading[mainAxis]] = node.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) +
|
||||||
getRelativePosition(node, mainAxis);
|
getRelativePosition(node, mainAxis);
|
||||||
node.layout.position[trailing[mainAxis]] = node.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) +
|
node.layout.position[trailing[mainAxis]] = node.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) +
|
||||||
@@ -272,7 +272,7 @@ namespace Facebook.CSSLayout
|
|||||||
float marginAxisColumn = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
float marginAxisColumn = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
availableHeight = node.style.dimensions[DIMENSION_HEIGHT] + marginAxisColumn;
|
availableHeight = node.style.dimensions[DIMENSION_HEIGHT] + marginAxisColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSMeasureMode widthMeasureMode = float.IsNaN(availableWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
CSSMeasureMode widthMeasureMode = float.IsNaN(availableWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
||||||
CSSMeasureMode heightMeasureMode = float.IsNaN(availableHeight) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
CSSMeasureMode heightMeasureMode = float.IsNaN(availableHeight) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ namespace Facebook.CSSLayout
|
|||||||
setPosition(node, node.layout.direction);
|
setPosition(node, node.layout.direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static boolean canUseCachedMeasurement(float availableWidth, float availableHeight,
|
internal static boolean canUseCachedMeasurement(float availableWidth, float availableHeight,
|
||||||
float marginRow, float marginColumn,
|
float marginRow, float marginColumn,
|
||||||
CSSMeasureMode widthMeasureMode, CSSMeasureMode heightMeasureMode,
|
CSSMeasureMode widthMeasureMode, CSSMeasureMode heightMeasureMode,
|
||||||
@@ -295,7 +295,7 @@ namespace Facebook.CSSLayout
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the width is an exact match, try a fuzzy match on the height.
|
// If the width is an exact match, try a fuzzy match on the height.
|
||||||
if (FloatUtil.floatsEqual(cachedLayout.availableWidth, availableWidth) &&
|
if (FloatUtil.floatsEqual(cachedLayout.availableWidth, availableWidth) &&
|
||||||
cachedLayout.widthMeasureMode == widthMeasureMode &&
|
cachedLayout.widthMeasureMode == widthMeasureMode &&
|
||||||
@@ -304,7 +304,7 @@ namespace Facebook.CSSLayout
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the height is an exact match, try a fuzzy match on the width.
|
// If the height is an exact match, try a fuzzy match on the width.
|
||||||
if (FloatUtil.floatsEqual(cachedLayout.availableHeight, availableHeight) &&
|
if (FloatUtil.floatsEqual(cachedLayout.availableHeight, availableHeight) &&
|
||||||
cachedLayout.heightMeasureMode == heightMeasureMode &&
|
cachedLayout.heightMeasureMode == heightMeasureMode &&
|
||||||
@@ -316,7 +316,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is a wrapper around the layoutNodeImpl function. It determines
|
// This is a wrapper around the layoutNodeImpl function. It determines
|
||||||
// whether the layout request is redundant and can be skipped.
|
// whether the layout request is redundant and can be skipped.
|
||||||
@@ -356,8 +356,8 @@ namespace Facebook.CSSLayout
|
|||||||
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]);
|
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]);
|
||||||
float marginAxisColumn =
|
float marginAxisColumn =
|
||||||
node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) +
|
node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) +
|
||||||
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]);
|
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]);
|
||||||
|
|
||||||
// First, try to use the layout cache.
|
// First, try to use the layout cache.
|
||||||
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||||
widthMeasureMode, heightMeasureMode, layout.cachedLayout))
|
widthMeasureMode, heightMeasureMode, layout.cachedLayout))
|
||||||
@@ -460,7 +460,7 @@ namespace Facebook.CSSLayout
|
|||||||
layout.generationCount = layoutContext.currentGenerationCount;
|
layout.generationCount = layoutContext.currentGenerationCount;
|
||||||
return (needToVisitNode || cachedResults == null);
|
return (needToVisitNode || cachedResults == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is the main routine that implements a subset of the flexbox layout algorithm
|
// This is the main routine that implements a subset of the flexbox layout algorithm
|
||||||
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
||||||
@@ -497,8 +497,8 @@ namespace Facebook.CSSLayout
|
|||||||
//
|
//
|
||||||
// Deviations from standard:
|
// Deviations from standard:
|
||||||
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
||||||
// main size. For text blocks, for example, this is the width of the widest word.
|
// main size. For text blocks, for example, this is the width of the widest word.
|
||||||
// Calculating the minimum width is expensive, so we forego it and assume a default
|
// Calculating the minimum width is expensive, so we forego it and assume a default
|
||||||
// minimum main size of 0.
|
// minimum main size of 0.
|
||||||
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
||||||
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
||||||
@@ -532,7 +532,7 @@ namespace Facebook.CSSLayout
|
|||||||
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
||||||
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
||||||
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
||||||
//
|
//
|
||||||
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
||||||
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
||||||
//
|
//
|
||||||
@@ -542,7 +542,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
Assertions.assertCondition(float.IsNaN(availableWidth) ? widthMeasureMode == CSSMeasureMode.Undefined : true, "availableWidth is indefinite so widthMeasureMode must be CSSMeasureMode.Undefined");
|
Assertions.assertCondition(float.IsNaN(availableWidth) ? widthMeasureMode == CSSMeasureMode.Undefined : true, "availableWidth is indefinite so widthMeasureMode must be CSSMeasureMode.Undefined");
|
||||||
Assertions.assertCondition(float.IsNaN(availableHeight) ? heightMeasureMode == CSSMeasureMode.Undefined : true, "availableHeight is indefinite so heightMeasureMode must be CSSMeasureMode.Undefined");
|
Assertions.assertCondition(float.IsNaN(availableHeight) ? heightMeasureMode == CSSMeasureMode.Undefined : true, "availableHeight is indefinite so heightMeasureMode must be CSSMeasureMode.Undefined");
|
||||||
|
|
||||||
float paddingAndBorderAxisRow = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])));
|
float paddingAndBorderAxisRow = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])));
|
||||||
float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
|
float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
|
||||||
float marginAxisRow = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
float marginAxisRow = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
@@ -556,7 +556,7 @@ namespace Facebook.CSSLayout
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
||||||
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
||||||
|
|
||||||
if (widthMeasureMode == CSSMeasureMode.Exactly && heightMeasureMode == CSSMeasureMode.Exactly) {
|
if (widthMeasureMode == CSSMeasureMode.Exactly && heightMeasureMode == CSSMeasureMode.Exactly) {
|
||||||
|
|
||||||
// Don't bother sizing the text if both dimensions are already defined.
|
// Don't bother sizing the text if both dimensions are already defined.
|
||||||
@@ -588,7 +588,7 @@ namespace Facebook.CSSLayout
|
|||||||
measureDim.height + paddingAndBorderAxisColumn :
|
measureDim.height + paddingAndBorderAxisColumn :
|
||||||
availableHeight - marginAxisColumn);
|
availableHeight - marginAxisColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,7 +618,7 @@ namespace Facebook.CSSLayout
|
|||||||
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widthMeasureMode == CSSMeasureMode.AtMost && availableWidth <= 0) {
|
if (widthMeasureMode == CSSMeasureMode.AtMost && availableWidth <= 0) {
|
||||||
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
||||||
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, float.IsNaN(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, float.IsNaN(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
||||||
@@ -630,7 +630,7 @@ namespace Facebook.CSSLayout
|
|||||||
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
||||||
if (widthMeasureMode == CSSMeasureMode.Exactly && heightMeasureMode == CSSMeasureMode.Exactly) {
|
if (widthMeasureMode == CSSMeasureMode.Exactly && heightMeasureMode == CSSMeasureMode.Exactly) {
|
||||||
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
||||||
@@ -654,7 +654,7 @@ namespace Facebook.CSSLayout
|
|||||||
float leadingPaddingAndBorderCross = (node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]));
|
float leadingPaddingAndBorderCross = (node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]));
|
||||||
float paddingAndBorderAxisMain = ((node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])));
|
float paddingAndBorderAxisMain = ((node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])));
|
||||||
float paddingAndBorderAxisCross = ((node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (node.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + node.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
float paddingAndBorderAxisCross = ((node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (node.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + node.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
||||||
|
|
||||||
CSSMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
CSSMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
||||||
CSSMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
CSSMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
||||||
|
|
||||||
@@ -679,7 +679,7 @@ namespace Facebook.CSSLayout
|
|||||||
CSSDirection childDirection = resolveDirection(child, direction);
|
CSSDirection childDirection = resolveDirection(child, direction);
|
||||||
setPosition(child, childDirection);
|
setPosition(child, childDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute-positioned children don't participate in flex layout. Add them
|
// Absolute-positioned children don't participate in flex layout. Add them
|
||||||
// to a list that we can process later.
|
// to a list that we can process later.
|
||||||
if (child.style.positionType == CSSPositionType.Absolute) {
|
if (child.style.positionType == CSSPositionType.Absolute) {
|
||||||
@@ -695,27 +695,27 @@ namespace Facebook.CSSLayout
|
|||||||
currentAbsoluteChild = child;
|
currentAbsoluteChild = child;
|
||||||
child.nextChild = null;
|
child.nextChild = null;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
if (isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
||||||
|
|
||||||
// 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 = Math.Max(child.style.dimensions[DIMENSION_WIDTH], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]))));
|
child.layout.flexBasis = Math.Max(child.style.dimensions[DIMENSION_WIDTH], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]))));
|
||||||
} else if (!isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
} else if (!isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
||||||
|
|
||||||
// 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 = Math.Max(child.style.dimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))));
|
child.layout.flexBasis = Math.Max(child.style.dimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))));
|
||||||
} else if (!isFlexBasisAuto(child) && !float.IsNaN(availableInnerMainDim)) {
|
} else if (!isFlexBasisAuto(child) && !float.IsNaN(availableInnerMainDim)) {
|
||||||
|
|
||||||
// If the basis isn't 'auto', it is assumed to be zero.
|
// If the basis isn't 'auto', it is assumed to be zero.
|
||||||
child.layout.flexBasis = Math.Max(0, ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
child.layout.flexBasis = Math.Max(0, ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
||||||
childWidth = CSSConstants.Undefined;
|
childWidth = CSSConstants.Undefined;
|
||||||
childHeight = CSSConstants.Undefined;
|
childHeight = CSSConstants.Undefined;
|
||||||
childWidthMeasureMode = CSSMeasureMode.Undefined;
|
childWidthMeasureMode = CSSMeasureMode.Undefined;
|
||||||
childHeightMeasureMode = CSSMeasureMode.Undefined;
|
childHeightMeasureMode = CSSMeasureMode.Undefined;
|
||||||
|
|
||||||
if ((child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
if ((child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
||||||
childWidth = child.style.dimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = child.style.dimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childWidthMeasureMode = CSSMeasureMode.Exactly;
|
childWidthMeasureMode = CSSMeasureMode.Exactly;
|
||||||
@@ -724,7 +724,7 @@ namespace Facebook.CSSLayout
|
|||||||
childHeight = child.style.dimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = child.style.dimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
childHeightMeasureMode = CSSMeasureMode.Exactly;
|
childHeightMeasureMode = CSSMeasureMode.Exactly;
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -745,21 +745,21 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
// Measure the child
|
// Measure the child
|
||||||
layoutNodeInternal(layoutContext, child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
layoutNodeInternal(layoutContext, child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
||||||
|
|
||||||
child.layout.flexBasis = Math.Max(isMainAxisRow ? child.layout.measuredDimensions[DIMENSION_WIDTH] : child.layout.measuredDimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
child.layout.flexBasis = Math.Max(isMainAxisRow ? child.layout.measuredDimensions[DIMENSION_WIDTH] : child.layout.measuredDimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
||||||
|
|
||||||
// Indexes of children that represent the first and last items in the line.
|
// Indexes of children that represent the first and last items in the line.
|
||||||
int startOfLineIndex = 0;
|
int startOfLineIndex = 0;
|
||||||
int endOfLineIndex = 0;
|
int endOfLineIndex = 0;
|
||||||
|
|
||||||
// Number of lines.
|
// Number of lines.
|
||||||
int lineCount = 0;
|
int lineCount = 0;
|
||||||
|
|
||||||
// Accumulated cross dimensions of all lines so far.
|
// Accumulated cross dimensions of all lines so far.
|
||||||
float totalLineCrossDim = 0;
|
float totalLineCrossDim = 0;
|
||||||
|
|
||||||
@@ -767,7 +767,7 @@ namespace Facebook.CSSLayout
|
|||||||
float maxLineMainDim = 0;
|
float maxLineMainDim = 0;
|
||||||
|
|
||||||
while (endOfLineIndex < childCount) {
|
while (endOfLineIndex < childCount) {
|
||||||
|
|
||||||
// Number of items on the currently line. May be different than the difference
|
// Number of items on the currently line. May be different than the difference
|
||||||
// between start and end indicates because we skip over absolute-positioned items.
|
// between start and end indicates because we skip over absolute-positioned items.
|
||||||
int itemsOnLine = 0;
|
int itemsOnLine = 0;
|
||||||
@@ -794,7 +794,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
if (child.style.positionType != CSSPositionType.Absolute) {
|
if (child.style.positionType != CSSPositionType.Absolute) {
|
||||||
float outerFlexBasis = child.layout.flexBasis + (child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
float outerFlexBasis = child.layout.flexBasis + (child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
||||||
|
|
||||||
// If this is a multi-line flow and this item pushes us over the available size, we've
|
// If this is a multi-line flow and this item pushes us over the available size, we've
|
||||||
// hit the end of the current line. Break out of the loop and lay out the current line.
|
// hit the end of the current line. Break out of the loop and lay out the current line.
|
||||||
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
||||||
@@ -806,7 +806,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
if ((child.style.positionType == CSSPositionType.Relative && child.style.flex != 0)) {
|
if ((child.style.positionType == CSSPositionType.Relative && child.style.flex != 0)) {
|
||||||
totalFlexGrowFactors += getFlexGrowFactor(child);
|
totalFlexGrowFactors += getFlexGrowFactor(child);
|
||||||
|
|
||||||
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
||||||
// dimension.
|
// dimension.
|
||||||
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
||||||
@@ -822,11 +822,11 @@ namespace Facebook.CSSLayout
|
|||||||
currentRelativeChild = child;
|
currentRelativeChild = child;
|
||||||
child.nextChild = null;
|
child.nextChild = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
endOfLineIndex++;
|
endOfLineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
||||||
boolean canSkipFlex = !performLayout && measureModeCrossDim == CSSMeasureMode.Exactly;
|
boolean canSkipFlex = !performLayout && measureModeCrossDim == CSSMeasureMode.Exactly;
|
||||||
|
|
||||||
@@ -849,7 +849,7 @@ namespace Facebook.CSSLayout
|
|||||||
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
||||||
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
float originalRemainingFreeSpace = remainingFreeSpace;
|
float originalRemainingFreeSpace = remainingFreeSpace;
|
||||||
float deltaFreeSpace = 0;
|
float deltaFreeSpace = 0;
|
||||||
|
|
||||||
@@ -859,20 +859,20 @@ namespace Facebook.CSSLayout
|
|||||||
float flexGrowFactor;
|
float flexGrowFactor;
|
||||||
float baseMainSize;
|
float baseMainSize;
|
||||||
float boundMainSize;
|
float boundMainSize;
|
||||||
|
|
||||||
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
||||||
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
||||||
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
||||||
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
||||||
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
||||||
// their min/max constraints to trigger again.
|
// their min/max constraints to trigger again.
|
||||||
//
|
//
|
||||||
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
||||||
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
||||||
// that needs to be repeated a variable number of times. The algorithm implemented here
|
// that needs to be repeated a variable number of times. The algorithm implemented here
|
||||||
// won't handle all cases but it was simpler to implement and it mitigates performance
|
// won't handle all cases but it was simpler to implement and it mitigates performance
|
||||||
// concerns because we know exactly how many passes it'll do.
|
// concerns because we know exactly how many passes it'll do.
|
||||||
|
|
||||||
// First pass: detect the flex items whose min/max constraints trigger
|
// First pass: detect the flex items whose min/max constraints trigger
|
||||||
float deltaFlexShrinkScaledFactors = 0;
|
float deltaFlexShrinkScaledFactors = 0;
|
||||||
float deltaFlexGrowFactors = 0;
|
float deltaFlexGrowFactors = 0;
|
||||||
@@ -882,7 +882,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
baseMainSize = childFlexBasis +
|
baseMainSize = childFlexBasis +
|
||||||
@@ -913,14 +913,14 @@ namespace Facebook.CSSLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
||||||
totalFlexGrowFactors += deltaFlexGrowFactors;
|
totalFlexGrowFactors += deltaFlexGrowFactors;
|
||||||
remainingFreeSpace += deltaFreeSpace;
|
remainingFreeSpace += deltaFreeSpace;
|
||||||
|
|
||||||
// Second pass: resolve the sizes of the flexible items
|
// Second pass: resolve the sizes of the flexible items
|
||||||
deltaFreeSpace = 0;
|
deltaFreeSpace = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
@@ -930,7 +930,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
||||||
@@ -945,13 +945,13 @@ namespace Facebook.CSSLayout
|
|||||||
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
childWidth = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childWidthMeasureMode = CSSMeasureMode.Exactly;
|
childWidthMeasureMode = CSSMeasureMode.Exactly;
|
||||||
|
|
||||||
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
||||||
childHeight = availableInnerCrossDim;
|
childHeight = availableInnerCrossDim;
|
||||||
childHeightMeasureMode = float.IsNaN(childHeight) ? CSSMeasureMode.Undefined : CSSMeasureMode.AtMost;
|
childHeightMeasureMode = float.IsNaN(childHeight) ? CSSMeasureMode.Undefined : CSSMeasureMode.AtMost;
|
||||||
@@ -962,7 +962,7 @@ namespace Facebook.CSSLayout
|
|||||||
} else {
|
} else {
|
||||||
childHeight = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
childHeightMeasureMode = CSSMeasureMode.Exactly;
|
childHeightMeasureMode = CSSMeasureMode.Exactly;
|
||||||
|
|
||||||
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
||||||
childWidth = availableInnerCrossDim;
|
childWidth = availableInnerCrossDim;
|
||||||
childWidthMeasureMode = float.IsNaN(childWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.AtMost;
|
childWidthMeasureMode = float.IsNaN(childWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.AtMost;
|
||||||
@@ -971,7 +971,7 @@ namespace Facebook.CSSLayout
|
|||||||
childWidthMeasureMode = CSSMeasureMode.Exactly;
|
childWidthMeasureMode = CSSMeasureMode.Exactly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean requiresStretchLayout = !(currentRelativeChild.style.dimensions[dim[crossAxis]] >= 0.0) &&
|
boolean requiresStretchLayout = !(currentRelativeChild.style.dimensions[dim[crossAxis]] >= 0.0) &&
|
||||||
getAlignItem(node, currentRelativeChild) == CSSAlign.Stretch;
|
getAlignItem(node, currentRelativeChild) == CSSAlign.Stretch;
|
||||||
|
|
||||||
@@ -981,7 +981,7 @@ namespace Facebook.CSSLayout
|
|||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
||||||
|
|
||||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||||
@@ -1040,7 +1040,7 @@ namespace Facebook.CSSLayout
|
|||||||
// we put it at the current accumulated offset.
|
// we put it at the current accumulated offset.
|
||||||
child.layout.position[pos[mainAxis]] += mainDim;
|
child.layout.position[pos[mainAxis]] += mainDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we placed the element, we need to update the variables.
|
// Now that we placed the element, we need to update the variables.
|
||||||
// We need to do that only for relative elements. Absolute elements
|
// We need to do that only for relative elements. Absolute elements
|
||||||
// do not take part in that phase.
|
// do not take part in that phase.
|
||||||
@@ -1054,7 +1054,7 @@ namespace Facebook.CSSLayout
|
|||||||
// The main dimension is the sum of all the elements dimension plus
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
// the spacing.
|
// the spacing.
|
||||||
mainDim += betweenMainDim + (child.layout.measuredDimensions[dim[mainAxis]] + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
mainDim += betweenMainDim + (child.layout.measuredDimensions[dim[mainAxis]] + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
||||||
|
|
||||||
// The cross dimension is the max of the elements dimension since there
|
// The cross dimension is the max of the elements dimension since there
|
||||||
// can only be one element in that cross dimension.
|
// can only be one element in that cross dimension.
|
||||||
crossDim = Math.Max(crossDim, (child.layout.measuredDimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
crossDim = Math.Max(crossDim, (child.layout.measuredDimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
||||||
@@ -1064,12 +1064,12 @@ namespace Facebook.CSSLayout
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainDim += trailingPaddingAndBorderMain;
|
mainDim += trailingPaddingAndBorderMain;
|
||||||
|
|
||||||
float containerCrossAxis = availableInnerCrossDim;
|
float containerCrossAxis = availableInnerCrossDim;
|
||||||
if (measureModeCrossDim == CSSMeasureMode.Undefined || measureModeCrossDim == CSSMeasureMode.AtMost) {
|
if (measureModeCrossDim == CSSMeasureMode.Undefined || measureModeCrossDim == CSSMeasureMode.AtMost) {
|
||||||
// Compute the cross axis from the max cross dimension of the children.
|
// Compute the cross axis from the max cross dimension of the children.
|
||||||
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
||||||
|
|
||||||
if (measureModeCrossDim == CSSMeasureMode.AtMost) {
|
if (measureModeCrossDim == CSSMeasureMode.AtMost) {
|
||||||
containerCrossAxis = Math.Min(containerCrossAxis, availableInnerCrossDim);
|
containerCrossAxis = Math.Min(containerCrossAxis, availableInnerCrossDim);
|
||||||
}
|
}
|
||||||
@@ -1106,14 +1106,14 @@ namespace Facebook.CSSLayout
|
|||||||
// For a relative children, we're either using alignItems (parent) or
|
// For a relative children, we're either using alignItems (parent) or
|
||||||
// alignSelf (child) in order to determine the position in the cross axis
|
// alignSelf (child) in order to determine the position in the cross axis
|
||||||
CSSAlign alignItem = getAlignItem(node, child);
|
CSSAlign alignItem = getAlignItem(node, child);
|
||||||
|
|
||||||
// If the child uses align stretch, we need to lay it out one more time, this time
|
// If the child uses align stretch, we need to lay it out one more time, this time
|
||||||
// forcing the cross-axis size to be the computed cross size for the current line.
|
// forcing the cross-axis size to be the computed cross size for the current line.
|
||||||
if (alignItem == CSSAlign.Stretch) {
|
if (alignItem == CSSAlign.Stretch) {
|
||||||
childWidth = child.layout.measuredDimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = child.layout.measuredDimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childHeight = child.layout.measuredDimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = child.layout.measuredDimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
boolean isCrossSizeDefinite = false;
|
boolean isCrossSizeDefinite = false;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0);
|
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0);
|
||||||
childHeight = crossDim;
|
childHeight = crossDim;
|
||||||
@@ -1121,7 +1121,7 @@ namespace Facebook.CSSLayout
|
|||||||
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0);
|
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0);
|
||||||
childWidth = crossDim;
|
childWidth = crossDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
||||||
if (!isCrossSizeDefinite) {
|
if (!isCrossSizeDefinite) {
|
||||||
childWidthMeasureMode = float.IsNaN(childWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
childWidthMeasureMode = float.IsNaN(childWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
||||||
@@ -1248,7 +1248,7 @@ namespace Facebook.CSSLayout
|
|||||||
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
||||||
paddingAndBorderAxisCross);
|
paddingAndBorderAxisCross);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
boolean needsMainTrailingPos = false;
|
boolean needsMainTrailingPos = false;
|
||||||
@@ -1279,7 +1279,7 @@ namespace Facebook.CSSLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
||||||
currentAbsoluteChild = firstAbsoluteChild;
|
currentAbsoluteChild = firstAbsoluteChild;
|
||||||
while (currentAbsoluteChild != null) {
|
while (currentAbsoluteChild != null) {
|
||||||
@@ -1301,7 +1301,7 @@ namespace Facebook.CSSLayout
|
|||||||
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((currentAbsoluteChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
if ((currentAbsoluteChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
||||||
childHeight = currentAbsoluteChild.style.dimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = currentAbsoluteChild.style.dimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
} else {
|
} else {
|
||||||
@@ -1318,7 +1318,7 @@ namespace Facebook.CSSLayout
|
|||||||
if (float.IsNaN(childWidth) || float.IsNaN(childHeight)) {
|
if (float.IsNaN(childWidth) || float.IsNaN(childHeight)) {
|
||||||
childWidthMeasureMode = float.IsNaN(childWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
childWidthMeasureMode = float.IsNaN(childWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
||||||
childHeightMeasureMode = float.IsNaN(childHeight) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
childHeightMeasureMode = float.IsNaN(childHeight) ? CSSMeasureMode.Undefined : CSSMeasureMode.Exactly;
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -1341,9 +1341,9 @@ namespace Facebook.CSSLayout
|
|||||||
childWidth = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_WIDTH] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_WIDTH] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childHeight = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeInternal(layoutContext, currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureMode.Exactly, CSSMeasureMode.Exactly, true, "abs-layout");
|
layoutNodeInternal(layoutContext, currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureMode.Exactly, CSSMeasureMode.Exactly, true, "abs-layout");
|
||||||
|
|
||||||
if (!float.IsNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) &&
|
if (!float.IsNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) &&
|
||||||
!!float.IsNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_ROW]])) {
|
!!float.IsNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_ROW]])) {
|
||||||
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
||||||
@@ -1351,7 +1351,7 @@ namespace Facebook.CSSLayout
|
|||||||
currentAbsoluteChild.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
currentAbsoluteChild.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
||||||
(float.IsNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]);
|
(float.IsNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!float.IsNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) &&
|
if (!float.IsNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) &&
|
||||||
!!float.IsNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_COLUMN]])) {
|
!!float.IsNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_COLUMN]])) {
|
||||||
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
||||||
|
@@ -33,4 +33,4 @@ namespace Facebook.CSSLayout
|
|||||||
get { return Height; }
|
get { return Height; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -137,7 +137,7 @@ namespace Facebook.CSSLayout
|
|||||||
|
|
||||||
internal float get(int spacingType)
|
internal float get(int spacingType)
|
||||||
{
|
{
|
||||||
float defaultValue =
|
float defaultValue =
|
||||||
(mDefaultSpacing != null)
|
(mDefaultSpacing != null)
|
||||||
? mDefaultSpacing[spacingType]
|
? mDefaultSpacing[spacingType]
|
||||||
: (spacingType == START || spacingType == END ? CSSConstants.Undefined : 0);
|
: (spacingType == START || spacingType == END ? CSSConstants.Undefined : 0);
|
||||||
|
@@ -35,4 +35,3 @@ build-release: build
|
|||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
${MSB} ${NAME}.sln /p:Configuration=${conf} /t:"Facebook_CSSLayout:Rebuild;Facebook_CSSLayout_Tests:Rebuild"
|
${MSB} ${NAME}.sln /p:Configuration=${conf} /t:"Facebook_CSSLayout:Rebuild;Facebook_CSSLayout_Tests:Rebuild"
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ public class CSSCachedMeasurement {
|
|||||||
public float availableHeight;
|
public float availableHeight;
|
||||||
public CSSMeasureMode widthMeasureMode = null;
|
public CSSMeasureMode widthMeasureMode = null;
|
||||||
public CSSMeasureMode heightMeasureMode = null;
|
public CSSMeasureMode heightMeasureMode = null;
|
||||||
|
|
||||||
public float computedWidth;
|
public float computedWidth;
|
||||||
public float computedHeight;
|
public float computedHeight;
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ public class CSSLayout {
|
|||||||
// This value was chosen based on empiracle data. Even the most complicated
|
// This value was chosen based on empiracle data. Even the most complicated
|
||||||
// layouts should not require more than 16 entries to fit within the cache.
|
// layouts should not require more than 16 entries to fit within the cache.
|
||||||
public static final int MAX_CACHED_RESULT_COUNT = 16;
|
public static final int MAX_CACHED_RESULT_COUNT = 16;
|
||||||
|
|
||||||
public static final int POSITION_LEFT = 0;
|
public static final int POSITION_LEFT = 0;
|
||||||
public static final int POSITION_TOP = 1;
|
public static final int POSITION_TOP = 1;
|
||||||
public static final int POSITION_RIGHT = 2;
|
public static final int POSITION_RIGHT = 2;
|
||||||
@@ -29,36 +29,36 @@ public class CSSLayout {
|
|||||||
public float[] position = new float[4];
|
public float[] position = new float[4];
|
||||||
public float[] dimensions = new float[2];
|
public float[] dimensions = new float[2];
|
||||||
public CSSDirection direction = CSSDirection.LTR;
|
public CSSDirection direction = CSSDirection.LTR;
|
||||||
|
|
||||||
public float flexBasis;
|
public float flexBasis;
|
||||||
|
|
||||||
public int generationCount;
|
public int generationCount;
|
||||||
public CSSDirection lastParentDirection;
|
public CSSDirection lastParentDirection;
|
||||||
|
|
||||||
public int nextCachedMeasurementsIndex;
|
public int nextCachedMeasurementsIndex;
|
||||||
public CSSCachedMeasurement[] cachedMeasurements = new CSSCachedMeasurement[MAX_CACHED_RESULT_COUNT];
|
public CSSCachedMeasurement[] cachedMeasurements = new CSSCachedMeasurement[MAX_CACHED_RESULT_COUNT];
|
||||||
public float[] measuredDimensions = new float[2];
|
public float[] measuredDimensions = new float[2];
|
||||||
|
|
||||||
public CSSCachedMeasurement cachedLayout = new CSSCachedMeasurement();
|
public CSSCachedMeasurement cachedLayout = new CSSCachedMeasurement();
|
||||||
|
|
||||||
CSSLayout() {
|
CSSLayout() {
|
||||||
resetResult();
|
resetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetResult() {
|
public void resetResult() {
|
||||||
Arrays.fill(position, 0);
|
Arrays.fill(position, 0);
|
||||||
Arrays.fill(dimensions, CSSConstants.UNDEFINED);
|
Arrays.fill(dimensions, CSSConstants.UNDEFINED);
|
||||||
direction = CSSDirection.LTR;
|
direction = CSSDirection.LTR;
|
||||||
|
|
||||||
flexBasis = 0;
|
flexBasis = 0;
|
||||||
|
|
||||||
generationCount = 0;
|
generationCount = 0;
|
||||||
lastParentDirection = null;
|
lastParentDirection = null;
|
||||||
|
|
||||||
nextCachedMeasurementsIndex = 0;
|
nextCachedMeasurementsIndex = 0;
|
||||||
measuredDimensions[DIMENSION_WIDTH] = CSSConstants.UNDEFINED;
|
measuredDimensions[DIMENSION_WIDTH] = CSSConstants.UNDEFINED;
|
||||||
measuredDimensions[DIMENSION_HEIGHT] = CSSConstants.UNDEFINED;
|
measuredDimensions[DIMENSION_HEIGHT] = CSSConstants.UNDEFINED;
|
||||||
|
|
||||||
cachedLayout.widthMeasureMode = null;
|
cachedLayout.widthMeasureMode = null;
|
||||||
cachedLayout.heightMeasureMode = null;
|
cachedLayout.heightMeasureMode = null;
|
||||||
}
|
}
|
||||||
|
@@ -64,7 +64,7 @@ public class CSSNode {
|
|||||||
public int lineIndex = 0;
|
public int lineIndex = 0;
|
||||||
|
|
||||||
/*package*/ CSSNode nextChild;
|
/*package*/ CSSNode nextChild;
|
||||||
|
|
||||||
private @Nullable ArrayList<CSSNode> mChildren;
|
private @Nullable ArrayList<CSSNode> mChildren;
|
||||||
private @Nullable CSSNode mParent;
|
private @Nullable CSSNode mParent;
|
||||||
private @Nullable MeasureFunction mMeasureFunction = null;
|
private @Nullable MeasureFunction mMeasureFunction = null;
|
||||||
|
@@ -21,9 +21,9 @@ import static com.facebook.csslayout.CSSLayout.POSITION_TOP;
|
|||||||
* Calculates layouts based on CSS style. See {@link #layoutNode(CSSNode, float, float)}.
|
* Calculates layouts based on CSS style. See {@link #layoutNode(CSSNode, float, float)}.
|
||||||
*/
|
*/
|
||||||
public class LayoutEngine {
|
public class LayoutEngine {
|
||||||
|
|
||||||
private static final boolean POSITIVE_FLEX_IS_AUTO = false;
|
private static final boolean POSITIVE_FLEX_IS_AUTO = false;
|
||||||
|
|
||||||
private static final int CSS_FLEX_DIRECTION_COLUMN =
|
private static final int CSS_FLEX_DIRECTION_COLUMN =
|
||||||
CSSFlexDirection.COLUMN.ordinal();
|
CSSFlexDirection.COLUMN.ordinal();
|
||||||
private static final int CSS_FLEX_DIRECTION_COLUMN_REVERSE =
|
private static final int CSS_FLEX_DIRECTION_COLUMN_REVERSE =
|
||||||
@@ -77,7 +77,7 @@ public class LayoutEngine {
|
|||||||
Spacing.END,
|
Spacing.END,
|
||||||
Spacing.END
|
Spacing.END
|
||||||
};
|
};
|
||||||
|
|
||||||
private static boolean isFlexBasisAuto(CSSNode node) {
|
private static boolean isFlexBasisAuto(CSSNode node) {
|
||||||
if (POSITIVE_FLEX_IS_AUTO) {
|
if (POSITIVE_FLEX_IS_AUTO) {
|
||||||
// All flex values are auto.
|
// All flex values are auto.
|
||||||
@@ -87,7 +87,7 @@ public class LayoutEngine {
|
|||||||
return node.style.flex <= 0;
|
return node.style.flex <= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float getFlexGrowFactor(CSSNode node) {
|
private static float getFlexGrowFactor(CSSNode node) {
|
||||||
// Flex grow is implied by positive values for flex.
|
// Flex grow is implied by positive values for flex.
|
||||||
if (node.style.flex > 0) {
|
if (node.style.flex > 0) {
|
||||||
@@ -95,7 +95,7 @@ public class LayoutEngine {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float getFlexShrinkFactor(CSSNode node) {
|
private static float getFlexShrinkFactor(CSSNode node) {
|
||||||
if (POSITIVE_FLEX_IS_AUTO) {
|
if (POSITIVE_FLEX_IS_AUTO) {
|
||||||
// A flex shrink factor of 1 is implied by non-zero values for flex.
|
// A flex shrink factor of 1 is implied by non-zero values for flex.
|
||||||
@@ -137,7 +137,7 @@ public class LayoutEngine {
|
|||||||
|
|
||||||
return boundValue;
|
return boundValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float boundAxis(CSSNode node, int axis, float value) {
|
private static float boundAxis(CSSNode node, int axis, float value) {
|
||||||
float paddingAndBorderAxis =
|
float paddingAndBorderAxis =
|
||||||
node.style.padding.getWithFallback(leadingSpacing[axis], leading[axis]) +
|
node.style.padding.getWithFallback(leadingSpacing[axis], leading[axis]) +
|
||||||
@@ -156,11 +156,11 @@ public class LayoutEngine {
|
|||||||
float trailingPos = node.style.position[trailing[axis]];
|
float trailingPos = node.style.position[trailing[axis]];
|
||||||
return Float.isNaN(trailingPos) ? 0 : -trailingPos;
|
return Float.isNaN(trailingPos) ? 0 : -trailingPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setPosition(CSSNode node, CSSDirection direction) {
|
private static void setPosition(CSSNode node, CSSDirection direction) {
|
||||||
int mainAxis = resolveAxis(getFlexDirection(node), direction);
|
int mainAxis = resolveAxis(getFlexDirection(node), direction);
|
||||||
int crossAxis = getCrossFlexDirection(mainAxis, direction);
|
int crossAxis = getCrossFlexDirection(mainAxis, direction);
|
||||||
|
|
||||||
node.layout.position[leading[mainAxis]] = node.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) +
|
node.layout.position[leading[mainAxis]] = node.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) +
|
||||||
getRelativePosition(node, mainAxis);
|
getRelativePosition(node, mainAxis);
|
||||||
node.layout.position[trailing[mainAxis]] = node.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) +
|
node.layout.position[trailing[mainAxis]] = node.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) +
|
||||||
@@ -230,7 +230,7 @@ public class LayoutEngine {
|
|||||||
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
// all dirty nodes at least once. Subsequent visits will be skipped if the input
|
||||||
// parameters don't change.
|
// parameters don't change.
|
||||||
layoutContext.currentGenerationCount++;
|
layoutContext.currentGenerationCount++;
|
||||||
|
|
||||||
// If the caller didn't specify a height/width, use the dimensions
|
// If the caller didn't specify a height/width, use the dimensions
|
||||||
// specified in the style.
|
// specified in the style.
|
||||||
if (Float.isNaN(availableWidth) && node.style.dimensions[DIMENSION_WIDTH] >= 0.0) {
|
if (Float.isNaN(availableWidth) && node.style.dimensions[DIMENSION_WIDTH] >= 0.0) {
|
||||||
@@ -241,15 +241,15 @@ public class LayoutEngine {
|
|||||||
float marginAxisColumn = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
float marginAxisColumn = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
availableHeight = node.style.dimensions[DIMENSION_HEIGHT] + marginAxisColumn;
|
availableHeight = node.style.dimensions[DIMENSION_HEIGHT] + marginAxisColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSMeasureMode widthMeasureMode = Float.isNaN(availableWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
CSSMeasureMode widthMeasureMode = Float.isNaN(availableWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
||||||
CSSMeasureMode heightMeasureMode = Float.isNaN(availableHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
CSSMeasureMode heightMeasureMode = Float.isNaN(availableHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
||||||
|
|
||||||
if (layoutNodeInternal(layoutContext, node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, "initial")) {
|
if (layoutNodeInternal(layoutContext, node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, true, "initial")) {
|
||||||
setPosition(node, node.layout.direction);
|
setPosition(node, node.layout.direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ static boolean canUseCachedMeasurement(float availableWidth, float availableHeight,
|
/*package*/ static boolean canUseCachedMeasurement(float availableWidth, float availableHeight,
|
||||||
float marginRow, float marginColumn,
|
float marginRow, float marginColumn,
|
||||||
CSSMeasureMode widthMeasureMode, CSSMeasureMode heightMeasureMode,
|
CSSMeasureMode widthMeasureMode, CSSMeasureMode heightMeasureMode,
|
||||||
@@ -261,7 +261,7 @@ public class LayoutEngine {
|
|||||||
cachedLayout.heightMeasureMode == heightMeasureMode) {
|
cachedLayout.heightMeasureMode == heightMeasureMode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the width is an exact match, try a fuzzy match on the height.
|
// If the width is an exact match, try a fuzzy match on the height.
|
||||||
if (FloatUtil.floatsEqual(cachedLayout.availableWidth, availableWidth) &&
|
if (FloatUtil.floatsEqual(cachedLayout.availableWidth, availableWidth) &&
|
||||||
cachedLayout.widthMeasureMode == widthMeasureMode &&
|
cachedLayout.widthMeasureMode == widthMeasureMode &&
|
||||||
@@ -269,7 +269,7 @@ public class LayoutEngine {
|
|||||||
FloatUtil.floatsEqual(availableHeight - marginColumn, cachedLayout.computedHeight)) {
|
FloatUtil.floatsEqual(availableHeight - marginColumn, cachedLayout.computedHeight)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the height is an exact match, try a fuzzy match on the width.
|
// If the height is an exact match, try a fuzzy match on the width.
|
||||||
if (FloatUtil.floatsEqual(cachedLayout.availableHeight, availableHeight) &&
|
if (FloatUtil.floatsEqual(cachedLayout.availableHeight, availableHeight) &&
|
||||||
cachedLayout.heightMeasureMode == heightMeasureMode &&
|
cachedLayout.heightMeasureMode == heightMeasureMode &&
|
||||||
@@ -277,10 +277,10 @@ public class LayoutEngine {
|
|||||||
FloatUtil.floatsEqual(availableWidth - marginRow, cachedLayout.computedWidth)) {
|
FloatUtil.floatsEqual(availableWidth - marginRow, cachedLayout.computedWidth)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is a wrapper around the layoutNodeImpl function. It determines
|
// This is a wrapper around the layoutNodeImpl function. It determines
|
||||||
// whether the layout request is redundant and can be skipped.
|
// whether the layout request is redundant and can be skipped.
|
||||||
@@ -300,19 +300,19 @@ public class LayoutEngine {
|
|||||||
boolean performLayout,
|
boolean performLayout,
|
||||||
String reason) {
|
String reason) {
|
||||||
CSSLayout layout = node.layout;
|
CSSLayout layout = node.layout;
|
||||||
|
|
||||||
boolean needToVisitNode = (node.isDirty() && layout.generationCount != layoutContext.currentGenerationCount) ||
|
boolean needToVisitNode = (node.isDirty() && layout.generationCount != layoutContext.currentGenerationCount) ||
|
||||||
layout.lastParentDirection != parentDirection;
|
layout.lastParentDirection != parentDirection;
|
||||||
|
|
||||||
if (needToVisitNode) {
|
if (needToVisitNode) {
|
||||||
// Invalidate the cached results.
|
// Invalidate the cached results.
|
||||||
layout.nextCachedMeasurementsIndex = 0;
|
layout.nextCachedMeasurementsIndex = 0;
|
||||||
layout.cachedLayout.widthMeasureMode = null;
|
layout.cachedLayout.widthMeasureMode = null;
|
||||||
layout.cachedLayout.heightMeasureMode = null;
|
layout.cachedLayout.heightMeasureMode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSCachedMeasurement cachedResults = null;
|
CSSCachedMeasurement cachedResults = null;
|
||||||
|
|
||||||
// Determine whether the results are already cached. We maintain a separate
|
// Determine whether the results are already cached. We maintain a separate
|
||||||
// cache for layouts and measurements. A layout operation modifies the positions
|
// cache for layouts and measurements. A layout operation modifies the positions
|
||||||
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
// and dimensions for nodes in the subtree. The algorithm assumes that each node
|
||||||
@@ -326,8 +326,8 @@ public class LayoutEngine {
|
|||||||
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]);
|
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]);
|
||||||
float marginAxisColumn =
|
float marginAxisColumn =
|
||||||
node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) +
|
node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) +
|
||||||
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]);
|
node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]);
|
||||||
|
|
||||||
// First, try to use the layout cache.
|
// First, try to use the layout cache.
|
||||||
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
if (canUseCachedMeasurement(availableWidth, availableHeight, marginAxisRow, marginAxisColumn,
|
||||||
widthMeasureMode, heightMeasureMode, layout.cachedLayout)) {
|
widthMeasureMode, heightMeasureMode, layout.cachedLayout)) {
|
||||||
@@ -347,7 +347,7 @@ public class LayoutEngine {
|
|||||||
FloatUtil.floatsEqual(layout.cachedLayout.availableHeight, availableHeight) &&
|
FloatUtil.floatsEqual(layout.cachedLayout.availableHeight, availableHeight) &&
|
||||||
layout.cachedLayout.widthMeasureMode == widthMeasureMode &&
|
layout.cachedLayout.widthMeasureMode == widthMeasureMode &&
|
||||||
layout.cachedLayout.heightMeasureMode == heightMeasureMode) {
|
layout.cachedLayout.heightMeasureMode == heightMeasureMode) {
|
||||||
|
|
||||||
cachedResults = layout.cachedLayout;
|
cachedResults = layout.cachedLayout;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -362,15 +362,15 @@ public class LayoutEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needToVisitNode && cachedResults != null) {
|
if (!needToVisitNode && cachedResults != null) {
|
||||||
layout.measuredDimensions[DIMENSION_WIDTH] = cachedResults.computedWidth;
|
layout.measuredDimensions[DIMENSION_WIDTH] = cachedResults.computedWidth;
|
||||||
layout.measuredDimensions[DIMENSION_HEIGHT] = cachedResults.computedHeight;
|
layout.measuredDimensions[DIMENSION_HEIGHT] = cachedResults.computedHeight;
|
||||||
} else {
|
} else {
|
||||||
layoutNodeImpl(layoutContext, node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
layoutNodeImpl(layoutContext, node, availableWidth, availableHeight, parentDirection, widthMeasureMode, heightMeasureMode, performLayout);
|
||||||
|
|
||||||
layout.lastParentDirection = parentDirection;
|
layout.lastParentDirection = parentDirection;
|
||||||
|
|
||||||
if (cachedResults == null) {
|
if (cachedResults == null) {
|
||||||
if (layout.nextCachedMeasurementsIndex == CSSLayout.MAX_CACHED_RESULT_COUNT) {
|
if (layout.nextCachedMeasurementsIndex == CSSLayout.MAX_CACHED_RESULT_COUNT) {
|
||||||
layout.nextCachedMeasurementsIndex = 0;
|
layout.nextCachedMeasurementsIndex = 0;
|
||||||
@@ -389,7 +389,7 @@ public class LayoutEngine {
|
|||||||
}
|
}
|
||||||
layout.nextCachedMeasurementsIndex++;
|
layout.nextCachedMeasurementsIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
newCacheEntry.availableWidth = availableWidth;
|
newCacheEntry.availableWidth = availableWidth;
|
||||||
newCacheEntry.availableHeight = availableHeight;
|
newCacheEntry.availableHeight = availableHeight;
|
||||||
newCacheEntry.widthMeasureMode = widthMeasureMode;
|
newCacheEntry.widthMeasureMode = widthMeasureMode;
|
||||||
@@ -398,18 +398,18 @@ public class LayoutEngine {
|
|||||||
newCacheEntry.computedHeight = layout.measuredDimensions[DIMENSION_HEIGHT];
|
newCacheEntry.computedHeight = layout.measuredDimensions[DIMENSION_HEIGHT];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
node.layout.dimensions[DIMENSION_WIDTH] = node.layout.measuredDimensions[DIMENSION_WIDTH];
|
node.layout.dimensions[DIMENSION_WIDTH] = node.layout.measuredDimensions[DIMENSION_WIDTH];
|
||||||
node.layout.dimensions[DIMENSION_HEIGHT] = node.layout.measuredDimensions[DIMENSION_HEIGHT];
|
node.layout.dimensions[DIMENSION_HEIGHT] = node.layout.measuredDimensions[DIMENSION_HEIGHT];
|
||||||
node.markHasNewLayout();
|
node.markHasNewLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.generationCount = layoutContext.currentGenerationCount;
|
layout.generationCount = layoutContext.currentGenerationCount;
|
||||||
return (needToVisitNode || cachedResults == null);
|
return (needToVisitNode || cachedResults == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// This is the main routine that implements a subset of the flexbox layout algorithm
|
// This is the main routine that implements a subset of the flexbox layout algorithm
|
||||||
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
// described in the W3C CSS documentation: https://www.w3.org/TR/css3-flexbox/.
|
||||||
@@ -446,8 +446,8 @@ public class LayoutEngine {
|
|||||||
//
|
//
|
||||||
// Deviations from standard:
|
// Deviations from standard:
|
||||||
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
// * Section 4.5 of the spec indicates that all flex items have a default minimum
|
||||||
// main size. For text blocks, for example, this is the width of the widest word.
|
// main size. For text blocks, for example, this is the width of the widest word.
|
||||||
// Calculating the minimum width is expensive, so we forego it and assume a default
|
// Calculating the minimum width is expensive, so we forego it and assume a default
|
||||||
// minimum main size of 0.
|
// minimum main size of 0.
|
||||||
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
// * Min/Max sizes in the main axis are not honored when resolving flexible lengths.
|
||||||
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
// * The spec indicates that the default value for 'flexDirection' is 'row', but
|
||||||
@@ -481,7 +481,7 @@ public class LayoutEngine {
|
|||||||
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
// - CSS_MEASURE_MODE_UNDEFINED: max content
|
||||||
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
// - CSS_MEASURE_MODE_EXACTLY: fill available
|
||||||
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
// - CSS_MEASURE_MODE_AT_MOST: fit content
|
||||||
//
|
//
|
||||||
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
// When calling layoutNodeImpl and layoutNodeInternal, if the caller passes an available size of
|
||||||
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
// undefined then it must also pass a measure mode of CSS_MEASURE_MODE_UNDEFINED in that dimension.
|
||||||
//
|
//
|
||||||
@@ -498,7 +498,7 @@ public class LayoutEngine {
|
|||||||
|
|
||||||
Assertions.assertCondition(Float.isNaN(availableWidth) ? widthMeasureMode == CSSMeasureMode.UNDEFINED : true, "availableWidth is indefinite so widthMeasureMode must be CSSMeasureMode.UNDEFINED");
|
Assertions.assertCondition(Float.isNaN(availableWidth) ? widthMeasureMode == CSSMeasureMode.UNDEFINED : true, "availableWidth is indefinite so widthMeasureMode must be CSSMeasureMode.UNDEFINED");
|
||||||
Assertions.assertCondition(Float.isNaN(availableHeight) ? heightMeasureMode == CSSMeasureMode.UNDEFINED : true, "availableHeight is indefinite so heightMeasureMode must be CSSMeasureMode.UNDEFINED");
|
Assertions.assertCondition(Float.isNaN(availableHeight) ? heightMeasureMode == CSSMeasureMode.UNDEFINED : true, "availableHeight is indefinite so heightMeasureMode must be CSSMeasureMode.UNDEFINED");
|
||||||
|
|
||||||
float paddingAndBorderAxisRow = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])));
|
float paddingAndBorderAxisRow = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])));
|
||||||
float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
|
float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
|
||||||
float marginAxisRow = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
float marginAxisRow = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
@@ -512,7 +512,7 @@ public class LayoutEngine {
|
|||||||
if (isMeasureDefined(node)) {
|
if (isMeasureDefined(node)) {
|
||||||
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
|
||||||
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
|
||||||
|
|
||||||
if (widthMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY) {
|
if (widthMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY) {
|
||||||
|
|
||||||
// Don't bother sizing the text if both dimensions are already defined.
|
// Don't bother sizing the text if both dimensions are already defined.
|
||||||
@@ -544,7 +544,7 @@ public class LayoutEngine {
|
|||||||
measureDim.height + paddingAndBorderAxisColumn :
|
measureDim.height + paddingAndBorderAxisColumn :
|
||||||
availableHeight - marginAxisColumn);
|
availableHeight - marginAxisColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,7 +574,7 @@ public class LayoutEngine {
|
|||||||
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widthMeasureMode == CSSMeasureMode.AT_MOST && availableWidth <= 0) {
|
if (widthMeasureMode == CSSMeasureMode.AT_MOST && availableWidth <= 0) {
|
||||||
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
|
||||||
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, Float.isNaN(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, Float.isNaN(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
|
||||||
@@ -586,7 +586,7 @@ public class LayoutEngine {
|
|||||||
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
// If we're being asked to use an exact width/height, there's no need to measure the children.
|
||||||
if (widthMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY) {
|
if (widthMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY) {
|
||||||
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
|
||||||
@@ -610,7 +610,7 @@ public class LayoutEngine {
|
|||||||
float leadingPaddingAndBorderCross = (node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]));
|
float leadingPaddingAndBorderCross = (node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]));
|
||||||
float paddingAndBorderAxisMain = ((node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])));
|
float paddingAndBorderAxisMain = ((node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])));
|
||||||
float paddingAndBorderAxisCross = ((node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (node.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + node.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
float paddingAndBorderAxisCross = ((node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (node.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + node.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
||||||
|
|
||||||
CSSMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
CSSMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
||||||
CSSMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
CSSMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
||||||
|
|
||||||
@@ -635,7 +635,7 @@ public class LayoutEngine {
|
|||||||
CSSDirection childDirection = resolveDirection(child, direction);
|
CSSDirection childDirection = resolveDirection(child, direction);
|
||||||
setPosition(child, childDirection);
|
setPosition(child, childDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Absolute-positioned children don't participate in flex layout. Add them
|
// Absolute-positioned children don't participate in flex layout. Add them
|
||||||
// to a list that we can process later.
|
// to a list that we can process later.
|
||||||
if (child.style.positionType == CSSPositionType.ABSOLUTE) {
|
if (child.style.positionType == CSSPositionType.ABSOLUTE) {
|
||||||
@@ -651,27 +651,27 @@ public class LayoutEngine {
|
|||||||
currentAbsoluteChild = child;
|
currentAbsoluteChild = child;
|
||||||
child.nextChild = null;
|
child.nextChild = null;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
if (isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
||||||
|
|
||||||
// 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 = Math.max(child.style.dimensions[DIMENSION_WIDTH], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]))));
|
child.layout.flexBasis = Math.max(child.style.dimensions[DIMENSION_WIDTH], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]))));
|
||||||
} else if (!isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
} else if (!isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
||||||
|
|
||||||
// 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 = Math.max(child.style.dimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))));
|
child.layout.flexBasis = Math.max(child.style.dimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))));
|
||||||
} else if (!isFlexBasisAuto(child) && !Float.isNaN(availableInnerMainDim)) {
|
} else if (!isFlexBasisAuto(child) && !Float.isNaN(availableInnerMainDim)) {
|
||||||
|
|
||||||
// If the basis isn't 'auto', it is assumed to be zero.
|
// If the basis isn't 'auto', it is assumed to be zero.
|
||||||
child.layout.flexBasis = Math.max(0, ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
child.layout.flexBasis = Math.max(0, ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
|
||||||
childWidth = CSSConstants.UNDEFINED;
|
childWidth = CSSConstants.UNDEFINED;
|
||||||
childHeight = CSSConstants.UNDEFINED;
|
childHeight = CSSConstants.UNDEFINED;
|
||||||
childWidthMeasureMode = CSSMeasureMode.UNDEFINED;
|
childWidthMeasureMode = CSSMeasureMode.UNDEFINED;
|
||||||
childHeightMeasureMode = CSSMeasureMode.UNDEFINED;
|
childHeightMeasureMode = CSSMeasureMode.UNDEFINED;
|
||||||
|
|
||||||
if ((child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
if ((child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
||||||
childWidth = child.style.dimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = child.style.dimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
|
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
|
||||||
@@ -680,7 +680,7 @@ public class LayoutEngine {
|
|||||||
childHeight = child.style.dimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = child.style.dimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
childHeightMeasureMode = CSSMeasureMode.EXACTLY;
|
childHeightMeasureMode = CSSMeasureMode.EXACTLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -701,21 +701,21 @@ public class LayoutEngine {
|
|||||||
|
|
||||||
// Measure the child
|
// Measure the child
|
||||||
layoutNodeInternal(layoutContext, child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
layoutNodeInternal(layoutContext, child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
|
||||||
|
|
||||||
child.layout.flexBasis = Math.max(isMainAxisRow ? child.layout.measuredDimensions[DIMENSION_WIDTH] : child.layout.measuredDimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
child.layout.flexBasis = Math.max(isMainAxisRow ? child.layout.measuredDimensions[DIMENSION_WIDTH] : child.layout.measuredDimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
||||||
|
|
||||||
// Indexes of children that represent the first and last items in the line.
|
// Indexes of children that represent the first and last items in the line.
|
||||||
int startOfLineIndex = 0;
|
int startOfLineIndex = 0;
|
||||||
int endOfLineIndex = 0;
|
int endOfLineIndex = 0;
|
||||||
|
|
||||||
// Number of lines.
|
// Number of lines.
|
||||||
int lineCount = 0;
|
int lineCount = 0;
|
||||||
|
|
||||||
// Accumulated cross dimensions of all lines so far.
|
// Accumulated cross dimensions of all lines so far.
|
||||||
float totalLineCrossDim = 0;
|
float totalLineCrossDim = 0;
|
||||||
|
|
||||||
@@ -723,7 +723,7 @@ public class LayoutEngine {
|
|||||||
float maxLineMainDim = 0;
|
float maxLineMainDim = 0;
|
||||||
|
|
||||||
while (endOfLineIndex < childCount) {
|
while (endOfLineIndex < childCount) {
|
||||||
|
|
||||||
// Number of items on the currently line. May be different than the difference
|
// Number of items on the currently line. May be different than the difference
|
||||||
// between start and end indicates because we skip over absolute-positioned items.
|
// between start and end indicates because we skip over absolute-positioned items.
|
||||||
int itemsOnLine = 0;
|
int itemsOnLine = 0;
|
||||||
@@ -750,7 +750,7 @@ public class LayoutEngine {
|
|||||||
|
|
||||||
if (child.style.positionType != CSSPositionType.ABSOLUTE) {
|
if (child.style.positionType != CSSPositionType.ABSOLUTE) {
|
||||||
float outerFlexBasis = child.layout.flexBasis + (child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
float outerFlexBasis = child.layout.flexBasis + (child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
||||||
|
|
||||||
// If this is a multi-line flow and this item pushes us over the available size, we've
|
// If this is a multi-line flow and this item pushes us over the available size, we've
|
||||||
// hit the end of the current line. Break out of the loop and lay out the current line.
|
// hit the end of the current line. Break out of the loop and lay out the current line.
|
||||||
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
|
||||||
@@ -762,7 +762,7 @@ public class LayoutEngine {
|
|||||||
|
|
||||||
if ((child.style.positionType == CSSPositionType.RELATIVE && child.style.flex != 0)) {
|
if ((child.style.positionType == CSSPositionType.RELATIVE && child.style.flex != 0)) {
|
||||||
totalFlexGrowFactors += getFlexGrowFactor(child);
|
totalFlexGrowFactors += getFlexGrowFactor(child);
|
||||||
|
|
||||||
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
// Unlike the grow factor, the shrink factor is scaled relative to the child
|
||||||
// dimension.
|
// dimension.
|
||||||
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
|
||||||
@@ -778,11 +778,11 @@ public class LayoutEngine {
|
|||||||
currentRelativeChild = child;
|
currentRelativeChild = child;
|
||||||
child.nextChild = null;
|
child.nextChild = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
endOfLineIndex++;
|
endOfLineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
// If we don't need to measure the cross axis, we can skip the entire flex step.
|
||||||
boolean canSkipFlex = !performLayout && measureModeCrossDim == CSSMeasureMode.EXACTLY;
|
boolean canSkipFlex = !performLayout && measureModeCrossDim == CSSMeasureMode.EXACTLY;
|
||||||
|
|
||||||
@@ -805,7 +805,7 @@ public class LayoutEngine {
|
|||||||
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
||||||
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
remainingFreeSpace = -sizeConsumedOnCurrentLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
float originalRemainingFreeSpace = remainingFreeSpace;
|
float originalRemainingFreeSpace = remainingFreeSpace;
|
||||||
float deltaFreeSpace = 0;
|
float deltaFreeSpace = 0;
|
||||||
|
|
||||||
@@ -815,20 +815,20 @@ public class LayoutEngine {
|
|||||||
float flexGrowFactor;
|
float flexGrowFactor;
|
||||||
float baseMainSize;
|
float baseMainSize;
|
||||||
float boundMainSize;
|
float boundMainSize;
|
||||||
|
|
||||||
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
// Do two passes over the flex items to figure out how to distribute the remaining space.
|
||||||
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
// The first pass finds the items whose min/max constraints trigger, freezes them at those
|
||||||
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
|
||||||
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
// of each flexible item. It distributes the remaining space amongst the items whose min/max
|
||||||
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
// constraints didn't trigger in pass 1. For the other items, it sets their sizes by forcing
|
||||||
// their min/max constraints to trigger again.
|
// their min/max constraints to trigger again.
|
||||||
//
|
//
|
||||||
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
// This two pass approach for resolving min/max constraints deviates from the spec. The
|
||||||
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
// spec (https://www.w3.org/TR/css-flexbox-1/#resolve-flexible-lengths) describes a process
|
||||||
// that needs to be repeated a variable number of times. The algorithm implemented here
|
// that needs to be repeated a variable number of times. The algorithm implemented here
|
||||||
// won't handle all cases but it was simpler to implement and it mitigates performance
|
// won't handle all cases but it was simpler to implement and it mitigates performance
|
||||||
// concerns because we know exactly how many passes it'll do.
|
// concerns because we know exactly how many passes it'll do.
|
||||||
|
|
||||||
// First pass: detect the flex items whose min/max constraints trigger
|
// First pass: detect the flex items whose min/max constraints trigger
|
||||||
float deltaFlexShrinkScaledFactors = 0;
|
float deltaFlexShrinkScaledFactors = 0;
|
||||||
float deltaFlexGrowFactors = 0;
|
float deltaFlexGrowFactors = 0;
|
||||||
@@ -838,7 +838,7 @@ public class LayoutEngine {
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
baseMainSize = childFlexBasis +
|
baseMainSize = childFlexBasis +
|
||||||
@@ -869,14 +869,14 @@ public class LayoutEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
|
||||||
totalFlexGrowFactors += deltaFlexGrowFactors;
|
totalFlexGrowFactors += deltaFlexGrowFactors;
|
||||||
remainingFreeSpace += deltaFreeSpace;
|
remainingFreeSpace += deltaFreeSpace;
|
||||||
|
|
||||||
// Second pass: resolve the sizes of the flexible items
|
// Second pass: resolve the sizes of the flexible items
|
||||||
deltaFreeSpace = 0;
|
deltaFreeSpace = 0;
|
||||||
currentRelativeChild = firstRelativeChild;
|
currentRelativeChild = firstRelativeChild;
|
||||||
@@ -886,7 +886,7 @@ public class LayoutEngine {
|
|||||||
|
|
||||||
if (remainingFreeSpace < 0) {
|
if (remainingFreeSpace < 0) {
|
||||||
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
|
||||||
|
|
||||||
// Is this child able to shrink?
|
// Is this child able to shrink?
|
||||||
if (flexShrinkScaledFactor != 0) {
|
if (flexShrinkScaledFactor != 0) {
|
||||||
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
|
||||||
@@ -901,13 +901,13 @@ public class LayoutEngine {
|
|||||||
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
deltaFreeSpace -= updatedMainSize - childFlexBasis;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
childWidth = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
|
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
|
||||||
|
|
||||||
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
||||||
childHeight = availableInnerCrossDim;
|
childHeight = availableInnerCrossDim;
|
||||||
childHeightMeasureMode = Float.isNaN(childHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.AT_MOST;
|
childHeightMeasureMode = Float.isNaN(childHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.AT_MOST;
|
||||||
@@ -918,7 +918,7 @@ public class LayoutEngine {
|
|||||||
} else {
|
} else {
|
||||||
childHeight = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
childHeightMeasureMode = CSSMeasureMode.EXACTLY;
|
childHeightMeasureMode = CSSMeasureMode.EXACTLY;
|
||||||
|
|
||||||
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
if (!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
|
||||||
childWidth = availableInnerCrossDim;
|
childWidth = availableInnerCrossDim;
|
||||||
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.AT_MOST;
|
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.AT_MOST;
|
||||||
@@ -927,7 +927,7 @@ public class LayoutEngine {
|
|||||||
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
|
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean requiresStretchLayout = !(currentRelativeChild.style.dimensions[dim[crossAxis]] >= 0.0) &&
|
boolean requiresStretchLayout = !(currentRelativeChild.style.dimensions[dim[crossAxis]] >= 0.0) &&
|
||||||
getAlignItem(node, currentRelativeChild) == CSSAlign.STRETCH;
|
getAlignItem(node, currentRelativeChild) == CSSAlign.STRETCH;
|
||||||
|
|
||||||
@@ -937,7 +937,7 @@ public class LayoutEngine {
|
|||||||
currentRelativeChild = currentRelativeChild.nextChild;
|
currentRelativeChild = currentRelativeChild.nextChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
|
||||||
|
|
||||||
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
||||||
@@ -996,7 +996,7 @@ public class LayoutEngine {
|
|||||||
// we put it at the current accumulated offset.
|
// we put it at the current accumulated offset.
|
||||||
child.layout.position[pos[mainAxis]] += mainDim;
|
child.layout.position[pos[mainAxis]] += mainDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we placed the element, we need to update the variables.
|
// Now that we placed the element, we need to update the variables.
|
||||||
// We need to do that only for relative elements. Absolute elements
|
// We need to do that only for relative elements. Absolute elements
|
||||||
// do not take part in that phase.
|
// do not take part in that phase.
|
||||||
@@ -1010,7 +1010,7 @@ public class LayoutEngine {
|
|||||||
// The main dimension is the sum of all the elements dimension plus
|
// The main dimension is the sum of all the elements dimension plus
|
||||||
// the spacing.
|
// the spacing.
|
||||||
mainDim += betweenMainDim + (child.layout.measuredDimensions[dim[mainAxis]] + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
mainDim += betweenMainDim + (child.layout.measuredDimensions[dim[mainAxis]] + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
|
||||||
|
|
||||||
// The cross dimension is the max of the elements dimension since there
|
// The cross dimension is the max of the elements dimension since there
|
||||||
// can only be one element in that cross dimension.
|
// can only be one element in that cross dimension.
|
||||||
crossDim = Math.max(crossDim, (child.layout.measuredDimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
crossDim = Math.max(crossDim, (child.layout.measuredDimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
|
||||||
@@ -1020,12 +1020,12 @@ public class LayoutEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mainDim += trailingPaddingAndBorderMain;
|
mainDim += trailingPaddingAndBorderMain;
|
||||||
|
|
||||||
float containerCrossAxis = availableInnerCrossDim;
|
float containerCrossAxis = availableInnerCrossDim;
|
||||||
if (measureModeCrossDim == CSSMeasureMode.UNDEFINED || measureModeCrossDim == CSSMeasureMode.AT_MOST) {
|
if (measureModeCrossDim == CSSMeasureMode.UNDEFINED || measureModeCrossDim == CSSMeasureMode.AT_MOST) {
|
||||||
// Compute the cross axis from the max cross dimension of the children.
|
// Compute the cross axis from the max cross dimension of the children.
|
||||||
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
|
||||||
|
|
||||||
if (measureModeCrossDim == CSSMeasureMode.AT_MOST) {
|
if (measureModeCrossDim == CSSMeasureMode.AT_MOST) {
|
||||||
containerCrossAxis = Math.min(containerCrossAxis, availableInnerCrossDim);
|
containerCrossAxis = Math.min(containerCrossAxis, availableInnerCrossDim);
|
||||||
}
|
}
|
||||||
@@ -1062,14 +1062,14 @@ public class LayoutEngine {
|
|||||||
// For a relative children, we're either using alignItems (parent) or
|
// For a relative children, we're either using alignItems (parent) or
|
||||||
// alignSelf (child) in order to determine the position in the cross axis
|
// alignSelf (child) in order to determine the position in the cross axis
|
||||||
CSSAlign alignItem = getAlignItem(node, child);
|
CSSAlign alignItem = getAlignItem(node, child);
|
||||||
|
|
||||||
// If the child uses align stretch, we need to lay it out one more time, this time
|
// If the child uses align stretch, we need to lay it out one more time, this time
|
||||||
// forcing the cross-axis size to be the computed cross size for the current line.
|
// forcing the cross-axis size to be the computed cross size for the current line.
|
||||||
if (alignItem == CSSAlign.STRETCH) {
|
if (alignItem == CSSAlign.STRETCH) {
|
||||||
childWidth = child.layout.measuredDimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = child.layout.measuredDimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childHeight = child.layout.measuredDimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = child.layout.measuredDimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
boolean isCrossSizeDefinite = false;
|
boolean isCrossSizeDefinite = false;
|
||||||
|
|
||||||
if (isMainAxisRow) {
|
if (isMainAxisRow) {
|
||||||
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0);
|
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0);
|
||||||
childHeight = crossDim;
|
childHeight = crossDim;
|
||||||
@@ -1077,7 +1077,7 @@ public class LayoutEngine {
|
|||||||
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0);
|
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0);
|
||||||
childWidth = crossDim;
|
childWidth = crossDim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
// If the child defines a definite size for its cross axis, there's no need to stretch.
|
||||||
if (!isCrossSizeDefinite) {
|
if (!isCrossSizeDefinite) {
|
||||||
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
||||||
@@ -1204,7 +1204,7 @@ public class LayoutEngine {
|
|||||||
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
|
||||||
paddingAndBorderAxisCross);
|
paddingAndBorderAxisCross);
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
|
||||||
if (performLayout) {
|
if (performLayout) {
|
||||||
boolean needsMainTrailingPos = false;
|
boolean needsMainTrailingPos = false;
|
||||||
@@ -1235,7 +1235,7 @@ public class LayoutEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
||||||
currentAbsoluteChild = firstAbsoluteChild;
|
currentAbsoluteChild = firstAbsoluteChild;
|
||||||
while (currentAbsoluteChild != null) {
|
while (currentAbsoluteChild != null) {
|
||||||
@@ -1257,7 +1257,7 @@ public class LayoutEngine {
|
|||||||
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((currentAbsoluteChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
if ((currentAbsoluteChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
|
||||||
childHeight = currentAbsoluteChild.style.dimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = currentAbsoluteChild.style.dimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
} else {
|
} else {
|
||||||
@@ -1274,7 +1274,7 @@ public class LayoutEngine {
|
|||||||
if (Float.isNaN(childWidth) || Float.isNaN(childHeight)) {
|
if (Float.isNaN(childWidth) || Float.isNaN(childHeight)) {
|
||||||
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
||||||
childHeightMeasureMode = Float.isNaN(childHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
childHeightMeasureMode = Float.isNaN(childHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
|
||||||
|
|
||||||
// According to the spec, if the main size is not definite and the
|
// According to the spec, if the main size is not definite and the
|
||||||
// child's inline axis is parallel to the main axis (i.e. it's
|
// child's inline axis is parallel to the main axis (i.e. it's
|
||||||
// horizontal), the child should be sized using "UNDEFINED" in
|
// horizontal), the child should be sized using "UNDEFINED" in
|
||||||
@@ -1297,9 +1297,9 @@ public class LayoutEngine {
|
|||||||
childWidth = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_WIDTH] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
childWidth = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_WIDTH] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
|
||||||
childHeight = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
childHeight = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutNodeInternal(layoutContext, currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureMode.EXACTLY, CSSMeasureMode.EXACTLY, true, "abs-layout");
|
layoutNodeInternal(layoutContext, currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureMode.EXACTLY, CSSMeasureMode.EXACTLY, true, "abs-layout");
|
||||||
|
|
||||||
if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) &&
|
if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) &&
|
||||||
!!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_ROW]])) {
|
!!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_ROW]])) {
|
||||||
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
|
||||||
@@ -1307,7 +1307,7 @@ public class LayoutEngine {
|
|||||||
currentAbsoluteChild.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
currentAbsoluteChild.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
|
||||||
(Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]);
|
(Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) &&
|
if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) &&
|
||||||
!!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_COLUMN]])) {
|
!!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_COLUMN]])) {
|
||||||
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
|
||||||
|
@@ -43,7 +43,7 @@ public class LayoutCachingTest {
|
|||||||
root.addChildAt(c0, 0);
|
root.addChildAt(c0, 0);
|
||||||
root.addChildAt(c1, 1);
|
root.addChildAt(c1, 1);
|
||||||
c0.addChildAt(c0c0, 0);
|
c0.addChildAt(c0c0, 0);
|
||||||
|
|
||||||
root.calculateLayout(layoutContext);
|
root.calculateLayout(layoutContext);
|
||||||
assertTreeHasNewLayout(true, root);
|
assertTreeHasNewLayout(true, root);
|
||||||
markLayoutAppliedForTree(root);
|
markLayoutAppliedForTree(root);
|
||||||
|
Reference in New Issue
Block a user