Correctly size cross axis when measuring flex basis

Summary:
https://github.com/facebook/css-layout/pull/199

- Nodes were measured with the assumption of being text nodes (height depends on width) when determining flex basis. This is not always true. Even when we are just interested in the main axis (flex basis) we need to correctly constrain the cross axis.
- Some tests were wrong. Measuring texts.big and expecting it to have textSizes.smallHeight which doesn't make a lot of sense.

Reviewed By: vjeux

Differential Revision: D3510163

fbshipit-source-id: ee53b548dd078005fdd153d279e4c7fef3dd02d0
This commit is contained in:
Emil Sjolander 2016-07-08 09:22:45 -07:00 committed by Facebook Github Bot 7
parent 1ebd9c5dea
commit ca66383941
4 changed files with 96 additions and 86 deletions

View File

@ -7,7 +7,7 @@
*/ */
// NOTE: this file is auto-copied from https://github.com/facebook/css-layout // NOTE: this file is auto-copied from https://github.com/facebook/css-layout
// @generated SignedSource<<484d0d17453521463896ce24d946412b>> // @generated SignedSource<<8af322a110307b3277db5b00573da822>>
#include <assert.h> #include <assert.h>
@ -829,56 +829,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;
}
// 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
// horizontal), the child should be sized using "UNDEFINED" in
// the main size. Otherwise use "AT_MOST" in the cross axis.
if (!isMainAxisRow && isUndefined(childWidth) && !isUndefined(availableInnerWidth)) {
childWidth = availableInnerWidth;
childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST; childWidthMeasureMode = CSS_MEASURE_MODE_AT_MOST;
} }
} else if (node->style.overflow == CSS_OVERFLOW_HIDDEN) {
// The W3C spec doesn't say anything about the 'overflow' property, if (heightMeasureMode == CSS_MEASURE_MODE_UNDEFINED || isUndefined(availableInnerMainDim)) {
// but all major browsers appear to implement the following logic. childHeight = CSS_UNDEFINED;
if (node->style.overflow == CSS_OVERFLOW_HIDDEN) { childHeightMeasureMode = CSS_MEASURE_MODE_UNDEFINED;
if (isMainAxisRow && isUndefined(childHeight) && !isUndefined(availableInnerHeight)) { } else {
childHeight = availableInnerHeight; childHeight = availableInnerMainDim;
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) &&
widthMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childWidth = availableInnerWidth;
childWidthMeasureMode = CSS_MEASURE_MODE_EXACTLY;
}
if (isMainAxisRow &&
!isUndefined(availableInnerHeight) &&
!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) && !isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN) &&
heightMeasureMode == CSS_MEASURE_MODE_EXACTLY && heightMeasureMode == CSS_MEASURE_MODE_EXACTLY &&
getAlignItem(node, child) == CSS_ALIGN_STRETCH) { getAlignItem(node, child) == CSS_ALIGN_STRETCH) {
childHeight = availableInnerHeight; childHeight = availableInnerCrossDim;
childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY; childHeightMeasureMode = CSS_MEASURE_MODE_EXACTLY;
} else if (!isStyleDimDefined(child, CSS_FLEX_DIRECTION_COLUMN)) {
childHeight = availableInnerCrossDim;
childHeightMeasureMode = isUndefined(childHeight) ? CSS_MEASURE_MODE_UNDEFINED : CSS_MEASURE_MODE_AT_MOST;
} else {
childHeight = child->style.dimensions[CSS_HEIGHT] + getMarginAxis(child, CSS_FLEX_DIRECTION_COLUMN);
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

@ -1,7 +1,7 @@
The source of truth for css-layout is: https://github.com/facebook/css-layout The source of truth for css-layout is: https://github.com/facebook/css-layout
The code here should be kept in sync with GitHub. The code here should be kept in sync with GitHub.
HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/a1f36b53f5464c8ee7abc311765dc3ecb1b879c6 HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/ca34ff44460bce122d02b27c0409a825f8de90b1
There is generated code in: There is generated code in:
- README (this file) - README (this file)

View File

@ -7,7 +7,7 @@
*/ */
// NOTE: this file is auto-copied from https://github.com/facebook/css-layout // NOTE: this file is auto-copied from https://github.com/facebook/css-layout
// @generated SignedSource<<deeb1f1cd05dfd70ce35f67c6eebf277>> // @generated SignedSource<<9805b148b88d298edb7fcd7c13738ede>>
package com.facebook.csslayout; package com.facebook.csslayout;
@ -726,56 +726,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;
}
// 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
// horizontal), the child should be sized using "UNDEFINED" in
// the main size. Otherwise use "AT_MOST" in the cross axis.
if (!isMainAxisRow && Float.isNaN(childWidth) && !Float.isNaN(availableInnerWidth)) {
childWidth = availableInnerWidth;
childWidthMeasureMode = CSSMeasureMode.AT_MOST; childWidthMeasureMode = CSSMeasureMode.AT_MOST;
} }
} else if (node.style.overflow == CSSOverflow.HIDDEN) {
// The W3C spec doesn't say anything about the 'overflow' property, if (heightMeasureMode == CSSMeasureMode.UNDEFINED || Float.isNaN(availableInnerMainDim)) {
// but all major browsers appear to implement the following logic. childHeight = CSSConstants.UNDEFINED;
if (node.style.overflow == CSSOverflow.HIDDEN) { childHeightMeasureMode = CSSMeasureMode.UNDEFINED;
if (isMainAxisRow && Float.isNaN(childHeight) && !Float.isNaN(availableInnerHeight)) { } else {
childHeight = availableInnerHeight; childHeight = availableInnerMainDim;
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) &&
widthMeasureMode == CSSMeasureMode.EXACTLY &&
getAlignItem(node, child) == CSSAlign.STRETCH) {
childWidth = availableInnerWidth;
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
}
if (isMainAxisRow &&
!Float.isNaN(availableInnerHeight) &&
!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) && !(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) &&
heightMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY &&
getAlignItem(node, child) == CSSAlign.STRETCH) { getAlignItem(node, child) == CSSAlign.STRETCH) {
childHeight = availableInnerHeight; childHeight = availableInnerCrossDim;
childHeightMeasureMode = CSSMeasureMode.EXACTLY; childHeightMeasureMode = CSSMeasureMode.EXACTLY;
} else if (!(child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
childHeight = availableInnerCrossDim;
childHeightMeasureMode = Float.isNaN(childHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.AT_MOST;
} else {
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;
}
}
} 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

@ -1,7 +1,7 @@
The source of truth for css-layout is: https://github.com/facebook/css-layout The source of truth for css-layout is: https://github.com/facebook/css-layout
The code here should be kept in sync with GitHub. The code here should be kept in sync with GitHub.
HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/a1f36b53f5464c8ee7abc311765dc3ecb1b879c6 HEAD at the time this code was synced: https://github.com/facebook/css-layout/commit/ca34ff44460bce122d02b27c0409a825f8de90b1
There is generated code in: There is generated code in:
- README (this file) - README (this file)