Merge pull request #199 from emilsjolander/measure-fix

Correctly size cross axis when measuring flex basis
This commit is contained in:
Emil Sjölander
2016-07-08 16:47:19 +01:00
committed by GitHub
17 changed files with 362 additions and 307 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ a.out
/lib/ /lib/
/node_modules/ /node_modules/
npm-debug.log npm-debug.log
TestResult.xml

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?> <?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--This file represents the results of running a test suite--> <!--This file represents the results of running a test suite-->
<test-results name="src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll" total="0" failures="0" not-run="0" date="2016-07-08" time="14:42:41"> <test-results name="src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll" total="0" failures="0" not-run="0" date="2016-07-08" time="16:05:12">
<environment nunit-version="2.4.8.0" clr-version="4.0.30319.17020" os-version="Unix 15.5.0.0" platform="Unix" cwd="/Volumes/Source/css-layout" machine-name="emilsj-pro" user="emilsj" user-domain="emilsj-pro" /> <environment nunit-version="2.4.8.0" clr-version="4.0.30319.17020" os-version="Unix 15.5.0.0" platform="Unix" cwd="/Volumes/Source/css-layout" machine-name="emilsj-pro" user="emilsj" user-domain="emilsj-pro" />
<culture-info current-culture="en-US" current-uiculture="en-US" /> <culture-info current-culture="en-US" current-uiculture="en-US" />
<test-suite name="src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll" success="True" time="0.001" asserts="0"> <test-suite name="src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll" success="True" time="0.001" asserts="0">

87
dist/css-layout.h vendored
View File

@@ -1032,56 +1032,61 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
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).
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)) { // Main axis
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW); if (isMainAxisRow) {
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; if (widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
} childWidth = CSS_UNDEFINED;
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) { childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN); } else {
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; childWidth = availableInnerMainDim;
} childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// According to the spec, if the main size is not definite and the } else if (node->style.overflow == CSS_OVERFLOW_HIDDEN) {
// child's inline axis is parallel to the main axis (i.e. it's if (heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
// horizontal), the child should be sized using "UNDEFINED" in childHeight = CSS_UNDEFINED;
// the main size. Otherwise use "AT_MOST" in the cross axis. childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
if (!isMainAxisRow && isUndefined(childWidth) && !isUndefined(availableInnerWidth)) { } else {
childWidth = availableInnerWidth; childHeight = availableInnerMainDim;
childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (node->style.overflow == CSS_OVERFLOW_HIDDEN) {
if (isMainAxisRow && isUndefined(childHeight) && !isUndefined(availableInnerHeight)) {
childHeight = availableInnerHeight;
childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST; childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST;
} }
} }
// If child has no defined size in the cross axis and is set to stretch, set the cross // Cross axis
// axis to be measured exactly with the available inner width if (isMainAxisRow) {
if (!isMainAxisRow && if (node->style.overflow == CSS_OVERFLOW_HIDDEN) {
!isUndefined(availableInnerWidth) && if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) && !isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerWidth; childHeight = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} } else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
if (isMainAxisRow && childHeight = availableInnerCrossDim;
!isUndefined(availableInnerHeight) && childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) && } else {
heightMeasureMode == CSS_MEASURE_MODE_EXACTLY && childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
childHeight = availableInnerHeight; }
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; }
} else {
if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
} else {
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
}
} }
// Measure the child // Measure the child

BIN
dist/css-layout.jar vendored

Binary file not shown.

87
dist/css-layout.js vendored
View File

@@ -795,56 +795,61 @@ var computeLayout = (function() {
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).
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)) { // Main axis
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW); if (isMainAxisRow) {
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; if (widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
} childWidth = CSS_UNDEFINED;
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) { childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN); } else {
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; childWidth = availableInnerMainDim;
} childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// According to the spec, if the main size is not definite and the } else if (getOverflow(node) === CSS_OVERFLOW_HIDDEN) {
// child's inline axis is parallel to the main axis (i.e. it's if (heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
// horizontal), the child should be sized using "UNDEFINED" in childHeight = CSS_UNDEFINED;
// the main size. Otherwise use "AT_MOST" in the cross axis. childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
if (!isMainAxisRow && isUndefined(childWidth) && !isUndefined(availableInnerWidth)) { } else {
childWidth = availableInnerWidth; childHeight = availableInnerMainDim;
childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (getOverflow(node) === CSS_OVERFLOW_HIDDEN) {
if (isMainAxisRow && isUndefined(childHeight) && !isUndefined(availableInnerHeight)) {
childHeight = availableInnerHeight;
childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST; childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST;
} }
} }
// If child has no defined size in the cross axis and is set to stretch, set the cross // Cross axis
// axis to be measured exactly with the available inner width if (isMainAxisRow) {
if (!isMainAxisRow && if (getOverflow(node) === CSS_OVERFLOW_HIDDEN) {
!isUndefined(availableInnerWidth) && if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) && !isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerWidth; childHeight = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} } else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
if (isMainAxisRow && childHeight = availableInnerCrossDim;
!isUndefined(availableInnerHeight) && childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) && } else {
heightMeasureMode == CSS_MEASURE_MODE_EXACTLY && childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
childHeight = availableInnerHeight; }
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; }
} else {
if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
} else {
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
}
} }
// Measure the child // Measure the child

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -90,23 +90,29 @@ css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, floa
width = 1000000; width = 1000000;
} }
dim.dimensions[CSS_WIDTH] = fminf(SMALL_WIDTH, width); dim.dimensions[CSS_WIDTH] = fminf(SMALL_WIDTH, width);
dim.dimensions[CSS_HEIGHT] = SMALL_HEIGHT; dim.dimensions[CSS_HEIGHT] = SMALL_WIDTH > width ? BIG_HEIGHT : SMALL_HEIGHT;
return dim; return dim;
} }
if (strcmp(text, LONG_TEXT) == 0) { if (strcmp(text, LONG_TEXT) == 0) {
if (widthMode == CSS_MEASURE_MODE_UNDEFINED) { if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
width = 1000000; width = 1000000;
} }
dim.dimensions[CSS_WIDTH] = width >= BIG_WIDTH ? BIG_WIDTH : fmaxf(BIG_MIN_WIDTH, width); dim.dimensions[CSS_WIDTH] = fminf(BIG_WIDTH, width);
dim.dimensions[CSS_HEIGHT] = width >= BIG_WIDTH ? SMALL_HEIGHT : BIG_HEIGHT; dim.dimensions[CSS_HEIGHT] = BIG_WIDTH > width ? BIG_HEIGHT : SMALL_HEIGHT;
return dim; return dim;
} }
if (strcmp(text, MEASURE_WITH_RATIO_2) == 0) { if (strcmp(text, MEASURE_WITH_RATIO_2) == 0) {
if (widthMode != CSS_MEASURE_MODE_UNDEFINED) { if (widthMode == CSS_MEASURE_MODE_EXACTLY) {
dim.dimensions[CSS_WIDTH] = width; dim.dimensions[CSS_WIDTH] = width;
dim.dimensions[CSS_HEIGHT] = width * 2; dim.dimensions[CSS_HEIGHT] = width * 2;
} else if (heightMode != CSS_MEASURE_MODE_UNDEFINED) { } else if (heightMode == CSS_MEASURE_MODE_EXACTLY) {
dim.dimensions[CSS_WIDTH] = height * 2;
dim.dimensions[CSS_HEIGHT] = height;
} else if (widthMode == CSS_MEASURE_MODE_AT_MOST) {
dim.dimensions[CSS_WIDTH] = width;
dim.dimensions[CSS_HEIGHT] = width * 2;
} else if (heightMode == CSS_MEASURE_MODE_AT_MOST) {
dim.dimensions[CSS_WIDTH] = height * 2; dim.dimensions[CSS_WIDTH] = height * 2;
dim.dimensions[CSS_HEIGHT] = height; dim.dimensions[CSS_HEIGHT] = height;
} else { } else {

View File

@@ -548,15 +548,14 @@ var layoutTestUtils = (function() {
if (text === texts.small) { if (text === texts.small) {
return { return {
width: Math.min(textSizes.smallWidth, width), width: Math.min(textSizes.smallWidth, width),
height: textSizes.smallHeight height: textSizes.smallWidth > width ? textSizes.bigHeight : textSizes.smallHeight
}; };
} }
if (text === texts.big) { if (text === texts.big) {
var res = { return {
width: width >= textSizes.bigWidth ? textSizes.bigWidth : Math.max(textSizes.bigMinWidth, width), width: Math.min(textSizes.bigWidth, width),
height: width >= textSizes.bigWidth ? textSizes.smallHeight : textSizes.bigHeight height: textSizes.bigWidth > width ? textSizes.bigHeight : textSizes.smallHeight
}; };
return res;
} }
}; };
// Name of the function is used in DOM tests as a text in the measured node // Name of the function is used in DOM tests as a text in the measured node
@@ -566,9 +565,13 @@ var layoutTestUtils = (function() {
}, },
measureWithRatio2: function() { measureWithRatio2: function() {
var fn = function(width, widthMode, height, heightMode) { var fn = function(width, widthMode, height, heightMode) {
if (widthMode !== 'undefined') { if (widthMode === 'exactly') {
height = width * 2; height = width * 2;
} else if (heightMode !== 'undefined') { } else if (heightMode === 'exactly') {
width = height * 2;
} else if (widthMode === 'at-most') {
height = width * 2;
} else if (heightMode === 'at-most') {
width = height * 2; width = height * 2;
} else { } else {
// This should be Infinity, but it would be pain to transpile, // This should be Infinity, but it would be pain to transpile,

View File

@@ -826,56 +826,61 @@ static void layoutNodeImpl(css_node_t* node, float availableWidth, float availab
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).
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)) { // Main axis
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW); if (isMainAxisRow) {
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; if (widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
} childWidth = CSS_UNDEFINED;
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) { childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN); } else {
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; childWidth = availableInnerMainDim;
} childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// According to the spec, if the main size is not definite and the } else if (node->style.overflow == CSS_OVERFLOW_HIDDEN) {
// child's inline axis is parallel to the main axis (i.e. it's if (heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
// horizontal), the child should be sized using "UNDEFINED" in childHeight = CSS_UNDEFINED;
// the main size. Otherwise use "AT_MOST" in the cross axis. childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
if (!isMainAxisRow && isUndefined(childWidth) && !isUndefined(availableInnerWidth)) { } else {
childWidth = availableInnerWidth; childHeight = availableInnerMainDim;
childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (node->style.overflow == CSS_OVERFLOW_HIDDEN) {
if (isMainAxisRow && isUndefined(childHeight) && !isUndefined(availableInnerHeight)) {
childHeight = availableInnerHeight;
childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST; childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST;
} }
} }
// If child has no defined size in the cross axis and is set to stretch, set the cross // Cross axis
// axis to be measured exactly with the available inner width if (isMainAxisRow) {
if (!isMainAxisRow && if (node->style.overflow == CSS_OVERFLOW_HIDDEN) {
!isUndefined(availableInnerWidth) && if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) && !isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerWidth; childHeight = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} } else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
if (isMainAxisRow && childHeight = availableInnerCrossDim;
!isUndefined(availableInnerHeight) && childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) && } else {
heightMeasureMode == CSS_MEASURE_MODE_EXACTLY && childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
childHeight = availableInnerHeight; }
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; }
} else {
if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
} else {
childWidth = child->style.dimensions[CSS_WIDTH] + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
}
} }
// Measure the child // Measure the child

View File

@@ -776,56 +776,61 @@ var computeLayout = (function() {
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).
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)) { // Main axis
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW); if (isMainAxisRow) {
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; if (widthMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
} childWidth = CSS_UNDEFINED;
if (isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) { childWidthMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN); } else {
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; childWidth = availableInnerMainDim;
} childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// According to the spec, if the main size is not definite and the } else if (getOverflow(node) === CSS_OVERFLOW_HIDDEN) {
// child's inline axis is parallel to the main axis (i.e. it's if (heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
// horizontal), the child should be sized using "UNDEFINED" in childHeight = CSS_UNDEFINED;
// the main size. Otherwise use "AT_MOST" in the cross axis. childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
if (!isMainAxisRow && isUndefined(childWidth) && !isUndefined(availableInnerWidth)) { } else {
childWidth = availableInnerWidth; childHeight = availableInnerMainDim;
childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (getOverflow(node) === CSS_OVERFLOW_HIDDEN) {
if (isMainAxisRow && isUndefined(childHeight) && !isUndefined(availableInnerHeight)) {
childHeight = availableInnerHeight;
childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST; childHeightMeasureMode = CSS_MEASURE_MODE_AT_MOST;
} }
} }
// If child has no defined size in the cross axis and is set to stretch, set the cross // Cross axis
// axis to be measured exactly with the available inner width if (isMainAxisRow) {
if (!isMainAxisRow && if (getOverflow(node) === CSS_OVERFLOW_HIDDEN) {
!isUndefined(availableInnerWidth) && if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) && !isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerWidth; childHeight = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY; childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} } else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
if (isMainAxisRow && childHeight = availableInnerCrossDim;
!isUndefined(availableInnerHeight) && childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) && } else {
heightMeasureMode == CSS_MEASURE_MODE_EXACTLY && childHeight = child.style.height + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
childHeight = availableInnerHeight; }
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; }
} else {
if (!isUndefined(availableInnerCrossDim) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_ROW)) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = isUndefined(childWidth) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
} else {
childWidth = child.style.width + getMarginAxis(child, CSS_FLEX_DIRECTION_ROW);
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
}
} }
// Measure the child // Measure the child

View File

@@ -4140,7 +4140,7 @@ int main()
node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_TOP] = 0;
node_0->layout.position[CSS_LEFT] = 0; node_0->layout.position[CSS_LEFT] = 0;
node_0->layout.dimensions[CSS_WIDTH] = 10; node_0->layout.dimensions[CSS_WIDTH] = 10;
node_0->layout.dimensions[CSS_HEIGHT] = 18; node_0->layout.dimensions[CSS_HEIGHT] = 36;
} }
test("should layout node with text and width", root_node, root_layout); test("should layout node with text and width", root_node, root_layout);
@@ -4512,7 +4512,7 @@ int main()
node_2 = node_1->get_child(node_1->context, 0); node_2 = node_1->get_child(node_1->context, 0);
node_2->layout.position[CSS_TOP] = 0; node_2->layout.position[CSS_TOP] = 0;
node_2->layout.position[CSS_LEFT] = 0; node_2->layout.position[CSS_LEFT] = 0;
node_2->layout.dimensions[CSS_WIDTH] = 100; node_2->layout.dimensions[CSS_WIDTH] = 60;
node_2->layout.dimensions[CSS_HEIGHT] = 36; node_2->layout.dimensions[CSS_HEIGHT] = 36;
} }
} }
@@ -4698,7 +4698,7 @@ int main()
node_2->style.margin[CSS_START] = 20; node_2->style.margin[CSS_START] = 20;
node_2->style.margin[CSS_END] = 20; node_2->style.margin[CSS_END] = 20;
node_2->measure = measure; node_2->measure = measure;
node_2->context = "loooooooooong with space"; node_2->context = "small";
} }
} }
} }
@@ -4724,7 +4724,7 @@ int main()
node_2 = node_1->get_child(node_1->context, 0); node_2 = node_1->get_child(node_1->context, 0);
node_2->layout.position[CSS_TOP] = 20; node_2->layout.position[CSS_TOP] = 20;
node_2->layout.position[CSS_LEFT] = 20; node_2->layout.position[CSS_LEFT] = 20;
node_2->layout.dimensions[CSS_WIDTH] = 172; node_2->layout.dimensions[CSS_WIDTH] = 35;
node_2->layout.dimensions[CSS_HEIGHT] = 18; node_2->layout.dimensions[CSS_HEIGHT] = 18;
} }
} }
@@ -4755,7 +4755,7 @@ int main()
node_2->style.margin[CSS_START] = 20; node_2->style.margin[CSS_START] = 20;
node_2->style.margin[CSS_END] = 20; node_2->style.margin[CSS_END] = 20;
node_2->measure = measure; node_2->measure = measure;
node_2->context = "loooooooooong with space"; node_2->context = "small";
} }
} }
} }
@@ -4780,8 +4780,8 @@ int main()
css_node_t *node_2; css_node_t *node_2;
node_2 = node_1->get_child(node_1->context, 0); node_2 = node_1->get_child(node_1->context, 0);
node_2->layout.position[CSS_TOP] = 20; node_2->layout.position[CSS_TOP] = 20;
node_2->layout.position[CSS_LEFT] = 8; node_2->layout.position[CSS_LEFT] = 145;
node_2->layout.dimensions[CSS_WIDTH] = 172; node_2->layout.dimensions[CSS_WIDTH] = 35;
node_2->layout.dimensions[CSS_HEIGHT] = 18; node_2->layout.dimensions[CSS_HEIGHT] = 18;
} }
} }

View File

@@ -1403,7 +1403,7 @@ describe('Layout', function() {
it('should layout node with text and width', function() { it('should layout node with text and width', function() {
testLayout( testLayout(
{style: {measure: text(texts.small), width: 10}}, {style: {measure: text(texts.small), width: 10}},
{width: 10, height: textSizes.smallHeight, top: 0, left: 0} {width: 10, height: textSizes.bigHeight, top: 0, left: 0}
); );
}); });
@@ -1508,10 +1508,8 @@ describe('Layout', function() {
]} ]}
]}, ]},
{width: 100, height: 40 + textSizes.bigHeight, top: 0, left: 0, children: [ {width: 100, height: 40 + textSizes.bigHeight, top: 0, left: 0, children: [
// In the flexbox engine implementation, min width of text is not supported so we max {width: 60, height: textSizes.bigHeight, top: 20, left: 20, children: [
// out at the amount of available space (60) {width: 60, height: textSizes.bigHeight, top: 0, left: 0}
{width: Math.min(60, textSizes.bigMinWidth), height: textSizes.bigHeight, top: 20, left: 20, children: [
{width: textSizes.bigMinWidth, height: textSizes.bigHeight, top: 0, left: 0}
]} ]}
]} ]}
); );
@@ -1569,12 +1567,12 @@ describe('Layout', function() {
testLayout( testLayout(
{style: {}, children: [ {style: {}, children: [
{style: {width: 200, flexDirection: 'row'}, children: [ {style: {width: 200, flexDirection: 'row'}, children: [
{style: {margin: 20, measure: text(texts.big)}} {style: {margin: 20, measure: text(texts.small)}}
]} ]}
]}, ]},
{width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [ {width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [
{width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [ {width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [
{width: textSizes.bigWidth, height: textSizes.smallHeight, top: 20, left: 20} {width: textSizes.smallWidth, height: textSizes.smallHeight, top: 20, left: 20}
]} ]}
]} ]}
); );
@@ -1584,12 +1582,12 @@ describe('Layout', function() {
testLayout( testLayout(
{style: { direction: 'rtl' }, children: [ {style: { direction: 'rtl' }, children: [
{style: {width: 200, flexDirection: 'row'}, children: [ {style: {width: 200, flexDirection: 'row'}, children: [
{style: {margin: 20, measure: text(texts.big)}} {style: {margin: 20, measure: text(texts.small)}}
]} ]}
]}, ]},
{width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [ {width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [
{width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [ {width: 200, height: textSizes.smallHeight + 40, top: 0, left: 0, children: [
{width: textSizes.bigWidth, height: textSizes.smallHeight, top: 20, left: 8} {width: textSizes.smallWidth, height: textSizes.smallHeight, top: 20, left: 200 - 20 - textSizes.smallWidth}
]} ]}
]} ]}
); );

View File

@@ -32,23 +32,36 @@ public class LayoutEngineTest
if (widthMode == CSSMeasureMode.Undefined) { if (widthMode == CSSMeasureMode.Undefined) {
width = 10000000; width = 10000000;
} }
float textHeight = TestConstants.SMALL_HEIGHT;
if (TestConstants.SMALL_WIDTH > width) {
textHeight = TestConstants.BIG_HEIGHT;
}
return new MeasureOutput( return new MeasureOutput(
Math.Min(width, TestConstants.SMALL_WIDTH), Math.Min(width, TestConstants.SMALL_WIDTH),
TestConstants.SMALL_HEIGHT); textHeight);
} else if (testNode.context.Equals(TestConstants.LONG_TEXT)) { } else if (testNode.context.Equals(TestConstants.LONG_TEXT)) {
if (widthMode == CSSMeasureMode.Undefined) { if (widthMode == CSSMeasureMode.Undefined) {
width = 10000000; width = 10000000;
} }
return new MeasureOutput(width >= TestConstants.BIG_WIDTH
? TestConstants.BIG_WIDTH float textHeight = TestConstants.SMALL_HEIGHT;
: Math.Max(TestConstants.BIG_MIN_WIDTH, width), if (TestConstants.BIG_WIDTH > width) {
width >= TestConstants.BIG_WIDTH textHeight = TestConstants.BIG_HEIGHT;
? TestConstants.SMALL_HEIGHT }
: TestConstants.BIG_HEIGHT);
return new MeasureOutput(
Math.Min(width, TestConstants.BIG_WIDTH),
textHeight);
} else if (testNode.context.Equals(TestConstants.MEASURE_WITH_RATIO_2)) { } else if (testNode.context.Equals(TestConstants.MEASURE_WITH_RATIO_2)) {
if (widthMode != CSSMeasureMode.Undefined) { if (widthMode == CSSMeasureMode.Exactly) {
return new MeasureOutput(width, width * 2); return new MeasureOutput(width, width * 2);
} else if (heightMode != CSSMeasureMode.Undefined) { } else if (heightMode == CSSMeasureMode.Exactly) {
return new MeasureOutput(height * 2, height);
} else if (widthMode == CSSMeasureMode.AtMost) {
return new MeasureOutput(width, width * 2);
} else if (heightMode == CSSMeasureMode.AtMost) {
return new MeasureOutput(height * 2, height); return new MeasureOutput(height * 2, height);
} else { } else {
return new MeasureOutput(99999, 99999); return new MeasureOutput(99999, 99999);
@@ -4443,7 +4456,7 @@ public class LayoutEngineTest
node_0.layout.position[POSITION_TOP] = 0; node_0.layout.position[POSITION_TOP] = 0;
node_0.layout.position[POSITION_LEFT] = 0; node_0.layout.position[POSITION_LEFT] = 0;
node_0.layout.dimensions[DIMENSION_WIDTH] = 10; node_0.layout.dimensions[DIMENSION_WIDTH] = 10;
node_0.layout.dimensions[DIMENSION_HEIGHT] = 18; node_0.layout.dimensions[DIMENSION_HEIGHT] = 36;
} }
test("should layout node with text and width", root_node, root_layout); test("should layout node with text and width", root_node, root_layout);
@@ -4831,7 +4844,7 @@ public class LayoutEngineTest
node_2 = node_1.getChildAt(0); node_2 = node_1.getChildAt(0);
node_2.layout.position[POSITION_TOP] = 0; node_2.layout.position[POSITION_TOP] = 0;
node_2.layout.position[POSITION_LEFT] = 0; node_2.layout.position[POSITION_LEFT] = 0;
node_2.layout.dimensions[DIMENSION_WIDTH] = 100; node_2.layout.dimensions[DIMENSION_WIDTH] = 60;
node_2.layout.dimensions[DIMENSION_HEIGHT] = 36; node_2.layout.dimensions[DIMENSION_HEIGHT] = 36;
} }
} }
@@ -5027,7 +5040,7 @@ public class LayoutEngineTest
node_2.setMargin(Spacing.START, 20); node_2.setMargin(Spacing.START, 20);
node_2.setMargin(Spacing.END, 20); node_2.setMargin(Spacing.END, 20);
node_2.setMeasureFunction(sTestMeasureFunction); node_2.setMeasureFunction(sTestMeasureFunction);
node_2.context = "loooooooooong with space"; node_2.context = "small";
} }
} }
} }
@@ -5053,7 +5066,7 @@ public class LayoutEngineTest
node_2 = node_1.getChildAt(0); node_2 = node_1.getChildAt(0);
node_2.layout.position[POSITION_TOP] = 20; node_2.layout.position[POSITION_TOP] = 20;
node_2.layout.position[POSITION_LEFT] = 20; node_2.layout.position[POSITION_LEFT] = 20;
node_2.layout.dimensions[DIMENSION_WIDTH] = 172; node_2.layout.dimensions[DIMENSION_WIDTH] = 35;
node_2.layout.dimensions[DIMENSION_HEIGHT] = 18; node_2.layout.dimensions[DIMENSION_HEIGHT] = 18;
} }
} }
@@ -5086,7 +5099,7 @@ public class LayoutEngineTest
node_2.setMargin(Spacing.START, 20); node_2.setMargin(Spacing.START, 20);
node_2.setMargin(Spacing.END, 20); node_2.setMargin(Spacing.END, 20);
node_2.setMeasureFunction(sTestMeasureFunction); node_2.setMeasureFunction(sTestMeasureFunction);
node_2.context = "loooooooooong with space"; node_2.context = "small";
} }
} }
} }
@@ -5111,8 +5124,8 @@ public class LayoutEngineTest
TestCSSNode node_2; TestCSSNode node_2;
node_2 = node_1.getChildAt(0); node_2 = node_1.getChildAt(0);
node_2.layout.position[POSITION_TOP] = 20; node_2.layout.position[POSITION_TOP] = 20;
node_2.layout.position[POSITION_LEFT] = 8; node_2.layout.position[POSITION_LEFT] = 145;
node_2.layout.dimensions[DIMENSION_WIDTH] = 172; node_2.layout.dimensions[DIMENSION_WIDTH] = 35;
node_2.layout.dimensions[DIMENSION_HEIGHT] = 18; node_2.layout.dimensions[DIMENSION_HEIGHT] = 18;
} }
} }

View File

@@ -762,56 +762,61 @@ namespace Facebook.CSSLayout
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).
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)) { // Main axis
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])); if (isMainAxisRow) {
childWidthMeasureMode = CSSMeasureMode.Exactly; if (widthMeasureMode == CSSMeasureMode.Undefined || float.IsNaN(availableInnerMainDim)) {
} childWidth = CSSConstants.Undefined;
if ((child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) { childWidthMeasureMode = CSSMeasureMode.Undefined;
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])); } else {
childHeightMeasureMode = CSSMeasureMode.Exactly; childWidth = availableInnerMainDim;
} childWidthMeasureMode = CSSMeasureMode.AtMost;
}
// According to the spec, if the main size is not definite and the } else if (node.style.overflow == CSSOverflow.Hidden) {
// child's inline axis is parallel to the main axis (i.e. it's if (heightMeasureMode == CSSMeasureMode.Undefined || float.IsNaN(availableInnerMainDim)) {
// horizontal), the child should be sized using "UNDEFINED" in childHeight = CSSConstants.Undefined;
// the main size. Otherwise use "AT_MOST" in the cross axis. childHeightMeasureMode = CSSMeasureMode.Undefined;
if (!isMainAxisRow && float.IsNaN(childWidth) && !float.IsNaN(availableInnerWidth)) { } else {
childWidth = availableInnerWidth; childHeight = availableInnerMainDim;
childWidthMeasureMode = CSSMeasureMode.AtMost;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (node.style.overflow == CSSOverflow.Hidden) {
if (isMainAxisRow && float.IsNaN(childHeight) && !float.IsNaN(availableInnerHeight)) {
childHeight = availableInnerHeight;
childHeightMeasureMode = CSSMeasureMode.AtMost; childHeightMeasureMode = CSSMeasureMode.AtMost;
} }
} }
// If child has no defined size in the cross axis and is set to stretch, set the cross // Cross axis
// axis to be measured exactly with the available inner width if (isMainAxisRow) {
if (!isMainAxisRow && if (node.style.overflow == CSSOverflow.Hidden) {
!float.IsNaN(availableInnerWidth) && if (!float.IsNaN(availableInnerCrossDim) &&
!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0) && !(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) &&
widthMeasureMode == CSSMeasureMode.Exactly && heightMeasureMode == CSSMeasureMode.Exactly &&
getAlignItem(node, child) == CSSAlign.Stretch) { getAlignItem(node, child) == CSSAlign.Stretch) {
childWidth = availableInnerWidth; childHeight = availableInnerCrossDim;
childWidthMeasureMode = CSSMeasureMode.Exactly; childHeightMeasureMode = CSSMeasureMode.Exactly;
} } else if (!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
if (isMainAxisRow && childHeight = availableInnerCrossDim;
!float.IsNaN(availableInnerHeight) && childHeightMeasureMode = float.IsNaN(childHeight) ? CSSMeasureMode.Undefined : CSSMeasureMode.AtMost;
!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) && } else {
heightMeasureMode == CSSMeasureMode.Exactly && 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]));
getAlignItem(node, child) == CSSAlign.Stretch) { childHeightMeasureMode = CSSMeasureMode.Exactly;
childHeight = availableInnerHeight; }
childHeightMeasureMode = CSSMeasureMode.Exactly; }
} else {
if (!float.IsNaN(availableInnerCrossDim) &&
!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0) &&
widthMeasureMode == CSSMeasureMode.Exactly &&
getAlignItem(node, child) == CSSAlign.Stretch) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = CSSMeasureMode.Exactly;
} else if (!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = float.IsNaN(childWidth) ? CSSMeasureMode.Undefined : CSSMeasureMode.AtMost;
} else {
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;
}
} }
// Measure the child // Measure the child

View File

@@ -723,56 +723,61 @@ public class LayoutEngine {
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).
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)) { // Main axis
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])); if (isMainAxisRow) {
childWidthMeasureMode = CSSMeasureMode.EXACTLY; if (widthMeasureMode == CSSMeasureMode.UNDEFINED || Float.isNaN(availableInnerMainDim)) {
} childWidth = CSSConstants.UNDEFINED;
if ((child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) { childWidthMeasureMode = CSSMeasureMode.UNDEFINED;
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])); } else {
childHeightMeasureMode = CSSMeasureMode.EXACTLY; childWidth = availableInnerMainDim;
} childWidthMeasureMode = CSSMeasureMode.AT_MOST;
}
// According to the spec, if the main size is not definite and the } else if (node.style.overflow == CSSOverflow.HIDDEN) {
// child's inline axis is parallel to the main axis (i.e. it's if (heightMeasureMode == CSSMeasureMode.UNDEFINED || Float.isNaN(availableInnerMainDim)) {
// horizontal), the child should be sized using "UNDEFINED" in childHeight = CSSConstants.UNDEFINED;
// the main size. Otherwise use "AT_MOST" in the cross axis. childHeightMeasureMode = CSSMeasureMode.UNDEFINED;
if (!isMainAxisRow && Float.isNaN(childWidth) && !Float.isNaN(availableInnerWidth)) { } else {
childWidth = availableInnerWidth; childHeight = availableInnerMainDim;
childWidthMeasureMode = CSSMeasureMode.AT_MOST;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (node.style.overflow == CSSOverflow.HIDDEN) {
if (isMainAxisRow && Float.isNaN(childHeight) && !Float.isNaN(availableInnerHeight)) {
childHeight = availableInnerHeight;
childHeightMeasureMode = CSSMeasureMode.AT_MOST; childHeightMeasureMode = CSSMeasureMode.AT_MOST;
} }
} }
// If child has no defined size in the cross axis and is set to stretch, set the cross // Cross axis
// axis to be measured exactly with the available inner width if (isMainAxisRow) {
if (!isMainAxisRow && if (node.style.overflow == CSSOverflow.HIDDEN) {
!Float.isNaN(availableInnerWidth) && if (!Float.isNaN(availableInnerCrossDim) &&
!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0) && !(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) &&
widthMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY &&
getAlignItem(node, child) == CSSAlign.STRETCH) { getAlignItem(node, child) == CSSAlign.STRETCH) {
childWidth = availableInnerWidth; childHeight = availableInnerCrossDim;
childWidthMeasureMode = CSSMeasureMode.EXACTLY; childHeightMeasureMode = CSSMeasureMode.EXACTLY;
} } else if (!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
if (isMainAxisRow && childHeight = availableInnerCrossDim;
!Float.isNaN(availableInnerHeight) && childHeightMeasureMode = Float.isNaN(childHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.AT_MOST;
!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) && } else {
heightMeasureMode == CSSMeasureMode.EXACTLY && 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]));
getAlignItem(node, child) == CSSAlign.STRETCH) { childHeightMeasureMode = CSSMeasureMode.EXACTLY;
childHeight = availableInnerHeight; }
childHeightMeasureMode = CSSMeasureMode.EXACTLY; }
} else {
if (!Float.isNaN(availableInnerCrossDim) &&
!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0) &&
widthMeasureMode == CSSMeasureMode.EXACTLY &&
getAlignItem(node, child) == CSSAlign.STRETCH) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
} else if (!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
childWidth = availableInnerCrossDim;
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.AT_MOST;
} else {
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;
}
} }
// Measure the child // Measure the child

View File

@@ -34,20 +34,24 @@ public class LayoutEngineTest {
width = 10000000; width = 10000000;
} }
measureOutput.width = Math.min(width, TestConstants.SMALL_WIDTH); measureOutput.width = Math.min(width, TestConstants.SMALL_WIDTH);
measureOutput.height = TestConstants.SMALL_HEIGHT; measureOutput.height = TestConstants.SMALL_WIDTH > width ? TestConstants.BIG_HEIGHT : TestConstants.SMALL_HEIGHT;
} else if (testNode.context.equals(TestConstants.LONG_TEXT)) { } else if (testNode.context.equals(TestConstants.LONG_TEXT)) {
if (widthMode == CSSMeasureMode.UNDEFINED) { if (widthMode == CSSMeasureMode.UNDEFINED) {
width = 10000000; width = 10000000;
} }
measureOutput.width = width >= TestConstants.BIG_WIDTH ? measureOutput.width = Math.min(width, TestConstants.BIG_WIDTH);
TestConstants.BIG_WIDTH : Math.max(TestConstants.BIG_MIN_WIDTH, width); measureOutput.height = TestConstants.BIG_WIDTH > width ? TestConstants.BIG_HEIGHT : TestConstants.SMALL_HEIGHT;
measureOutput.height = width >= TestConstants.BIG_WIDTH ?
TestConstants.SMALL_HEIGHT : TestConstants.BIG_HEIGHT;
} else if (testNode.context.equals(TestConstants.MEASURE_WITH_RATIO_2)) { } else if (testNode.context.equals(TestConstants.MEASURE_WITH_RATIO_2)) {
if (widthMode != CSSMeasureMode.UNDEFINED) { if (widthMode == CSSMeasureMode.EXACTLY) {
measureOutput.width = width; measureOutput.width = width;
measureOutput.height = width * 2; measureOutput.height = width * 2;
} else if (heightMode != CSSMeasureMode.UNDEFINED) { } else if (heightMode == CSSMeasureMode.EXACTLY) {
measureOutput.width = height * 2;
measureOutput.height = height;
} else if (widthMode == CSSMeasureMode.AT_MOST) {
measureOutput.width = width;
measureOutput.height = width * 2;
} else if (heightMode == CSSMeasureMode.AT_MOST) {
measureOutput.width = height * 2; measureOutput.width = height * 2;
measureOutput.height = height; measureOutput.height = height;
} else { } else {
@@ -4446,7 +4450,7 @@ public class LayoutEngineTest {
node_0.layout.position[POSITION_TOP] = 0; node_0.layout.position[POSITION_TOP] = 0;
node_0.layout.position[POSITION_LEFT] = 0; node_0.layout.position[POSITION_LEFT] = 0;
node_0.layout.dimensions[DIMENSION_WIDTH] = 10; node_0.layout.dimensions[DIMENSION_WIDTH] = 10;
node_0.layout.dimensions[DIMENSION_HEIGHT] = 18; node_0.layout.dimensions[DIMENSION_HEIGHT] = 36;
} }
test("should layout node with text and width", root_node, root_layout); test("should layout node with text and width", root_node, root_layout);
@@ -4834,7 +4838,7 @@ public class LayoutEngineTest {
node_2 = node_1.getChildAt(0); node_2 = node_1.getChildAt(0);
node_2.layout.position[POSITION_TOP] = 0; node_2.layout.position[POSITION_TOP] = 0;
node_2.layout.position[POSITION_LEFT] = 0; node_2.layout.position[POSITION_LEFT] = 0;
node_2.layout.dimensions[DIMENSION_WIDTH] = 100; node_2.layout.dimensions[DIMENSION_WIDTH] = 60;
node_2.layout.dimensions[DIMENSION_HEIGHT] = 36; node_2.layout.dimensions[DIMENSION_HEIGHT] = 36;
} }
} }
@@ -5030,7 +5034,7 @@ public class LayoutEngineTest {
node_2.setMargin(Spacing.START, 20); node_2.setMargin(Spacing.START, 20);
node_2.setMargin(Spacing.END, 20); node_2.setMargin(Spacing.END, 20);
node_2.setMeasureFunction(sTestMeasureFunction); node_2.setMeasureFunction(sTestMeasureFunction);
node_2.context = "loooooooooong with space"; node_2.context = "small";
} }
} }
} }
@@ -5056,7 +5060,7 @@ public class LayoutEngineTest {
node_2 = node_1.getChildAt(0); node_2 = node_1.getChildAt(0);
node_2.layout.position[POSITION_TOP] = 20; node_2.layout.position[POSITION_TOP] = 20;
node_2.layout.position[POSITION_LEFT] = 20; node_2.layout.position[POSITION_LEFT] = 20;
node_2.layout.dimensions[DIMENSION_WIDTH] = 172; node_2.layout.dimensions[DIMENSION_WIDTH] = 35;
node_2.layout.dimensions[DIMENSION_HEIGHT] = 18; node_2.layout.dimensions[DIMENSION_HEIGHT] = 18;
} }
} }
@@ -5089,7 +5093,7 @@ public class LayoutEngineTest {
node_2.setMargin(Spacing.START, 20); node_2.setMargin(Spacing.START, 20);
node_2.setMargin(Spacing.END, 20); node_2.setMargin(Spacing.END, 20);
node_2.setMeasureFunction(sTestMeasureFunction); node_2.setMeasureFunction(sTestMeasureFunction);
node_2.context = "loooooooooong with space"; node_2.context = "small";
} }
} }
} }
@@ -5114,8 +5118,8 @@ public class LayoutEngineTest {
TestCSSNode node_2; TestCSSNode node_2;
node_2 = node_1.getChildAt(0); node_2 = node_1.getChildAt(0);
node_2.layout.position[POSITION_TOP] = 20; node_2.layout.position[POSITION_TOP] = 20;
node_2.layout.position[POSITION_LEFT] = 8; node_2.layout.position[POSITION_LEFT] = 145;
node_2.layout.dimensions[DIMENSION_WIDTH] = 172; node_2.layout.dimensions[DIMENSION_WIDTH] = 35;
node_2.layout.dimensions[DIMENSION_HEIGHT] = 18; node_2.layout.dimensions[DIMENSION_HEIGHT] = 18;
} }
} }