Merge pull request #185 from rigdern/rigdern/spec-conformance
Alter layout engine to conform closer to W3C spec
This commit is contained in:
12
README.md
12
README.md
@@ -92,10 +92,19 @@ borderWidth, borderLeftWidth, borderRightWidth, borderTopWidth, borderBottomWidt
|
||||
flexDirection | 'column', 'row'
|
||||
justifyContent | 'flex-start', 'center', 'flex-end', 'space-between', 'space-around'
|
||||
alignItems, alignSelf | 'flex-start', 'center', 'flex-end', 'stretch'
|
||||
flex | positive number
|
||||
flex | number
|
||||
flexWrap | 'wrap', 'nowrap'
|
||||
position | 'relative', 'absolute'
|
||||
overflow | 'visible', 'hidden'
|
||||
|
||||
- Rather than allowing arbitrary combinations of `flex-grow`, `flex-shrink`, and `flex-basis` the implementation only supports a few common combinations expressed as a single number using the `flex` attribute:
|
||||
|
||||
css-layout `flex` value | W3C `flex` short-hand equivalent
|
||||
---|---
|
||||
n (where n > 0) | n 0 0
|
||||
0 | 0 0 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.
|
||||
|
||||
|
||||
@@ -118,6 +127,7 @@ div, span {
|
||||
border: 0 solid black;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
```
|
||||
|
||||
|
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<!--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-04-01" time="11:01:04">
|
||||
<environment nunit-version="2.4.8.0" clr-version="4.0.30319.17020" os-version="Unix 15.4.0.0" platform="Unix" cwd="/Users/emilsj/css-layout" machine-name="emilsj-pro" user="emilsj" user-domain="emilsj-pro" />
|
||||
<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">
|
||||
<results />
|
||||
</test-suite>
|
||||
</test-results>
|
1851
dist/css-layout.h
vendored
1851
dist/css-layout.h
vendored
File diff suppressed because it is too large
Load Diff
BIN
dist/css-layout.jar
vendored
BIN
dist/css-layout.jar
vendored
Binary file not shown.
1691
dist/css-layout.js
vendored
1691
dist/css-layout.js
vendored
File diff suppressed because it is too large
Load Diff
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
@@ -9,11 +9,18 @@
|
||||
|
||||
function __transpileToCSharpCommon(code) {
|
||||
return code
|
||||
.replace(/'abs-layout'/g, '"abs-layout"')
|
||||
.replace(/'abs-measure'/g, '"abs-measure"')
|
||||
.replace(/'flex'/g, '"flex"')
|
||||
.replace(/'measure'/g, '"measure"')
|
||||
.replace(/'stretch'/g, '"stretch"')
|
||||
.replace(/undefined/g, 'null')
|
||||
.replace(/CSS_UNDEFINED/g, 'CSSConstants.UNDEFINED')
|
||||
.replace(/CSS_JUSTIFY_/g, 'CSSJustify.')
|
||||
.replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.')
|
||||
.replace(/CSS_ALIGN_/g, 'CSSAlign.')
|
||||
.replace(/CSS_POSITION_/g, 'CSSPositionType.')
|
||||
.replace(/CSS_OVERFLOW_/g, 'CSSOverflow.')
|
||||
.replace(/css_flex_direction_t/g, 'CSSFlexDirection')
|
||||
.replace(/css_direction_t/g, 'CSSDirection')
|
||||
.replace(/css_align_t/g, 'CSSAlign')
|
||||
@@ -21,6 +28,10 @@ function __transpileToCSharpCommon(code) {
|
||||
.replace(/css_measure_mode_t/g, 'CSSMeasureMode')
|
||||
.replace(/css_dim_t/g, 'MeasureOutput')
|
||||
.replace(/bool/g, 'boolean')
|
||||
.replace(/style\[CSS_LEFT/g, 'style.position[POSITION_LEFT')
|
||||
.replace(/style\[CSS_TOP/g, 'style.position[POSITION_TOP')
|
||||
.replace(/style\[CSS_RIGHT/g, 'style.position[POSITION_RIGHT')
|
||||
.replace(/style\[CSS_BOTTOM/g, 'style.position[POSITION_BOTTOM')
|
||||
.replace(/style\[dim/g, 'style.dimensions[dim')
|
||||
.replace(/(style|layout)\.width/g, '$1.dimensions[DIMENSION_WIDTH]')
|
||||
.replace(/(style|layout)\.height/g, '$1.dimensions[DIMENSION_HEIGHT]')
|
||||
@@ -28,22 +39,24 @@ function __transpileToCSharpCommon(code) {
|
||||
.replace(/layout\[pos/g, 'layout.position[pos')
|
||||
.replace(/layout\[leading/g, 'layout.position[leading')
|
||||
.replace(/layout\[trailing/g, 'layout.position[trailing')
|
||||
.replace(/layout\[measuredDim/g, 'layout.measuredDimensions[dim')
|
||||
.replace(/layout\.measuredWidth/g, 'layout.measuredDimensions[DIMENSION_WIDTH]')
|
||||
.replace(/layout\.measuredHeight/g, 'layout.measuredDimensions[DIMENSION_HEIGHT]')
|
||||
.replace(/getPositionType\((.+?)\)/g, '$1.style.positionType')
|
||||
.replace(/getJustifyContent\((.+?)\)/g, '$1.style.justifyContent')
|
||||
.replace(/getAlignContent\((.+?)\)/g, '$1.style.alignContent')
|
||||
.replace(/isPosDefined\((.+?),\s*(.+?)\)/g, '!isUndefined\($1.style.position[$2]\)')
|
||||
.replace(/isStyleDimDefined\((.+?),\s*(.+?)\)/g, '\(!isUndefined\($1.style.dimensions[dim[$2]]\) && $1.style.dimensions[dim[$2]] >= 0.0\)')
|
||||
.replace(/isLayoutDimDefined\((.+?),\s*(.+?)\)/g, '\(!isUndefined\($1.layout.dimensions[dim[$2]]\) && $1.layout.dimensions[dim[$2]] >= 0.0\)')
|
||||
.replace(/isStyleDimDefined\((.+?),\s*(.+?)\)/g, '($1.style.dimensions[dim[$2]] >= 0.0)')
|
||||
.replace(/isLayoutDimDefined\((.+?),\s*(.+?)\)/g, '($1.layout.measuredDimensions[dim[$2]] >= 0.0)')
|
||||
.replace(/getPosition\((.+?),\s*(.+?)\)/g, '\(isUndefined\($1.style.position[$2]\) ? 0 : $1.style.position[$2]\)')
|
||||
.replace(/setTrailingPosition\((.+?),\s*(.+?),\s*(.+?)\)/g, '$2.layout.position[trailing[$3]] = $1.layout.dimensions[dim[$3]] - $2.layout.dimensions[dim[$3]] - $2.layout.position[pos[$3]]')
|
||||
.replace(/isFlex\((.+?)\)/g, '\($1.style.positionType == CSSPositionType.RELATIVE && $1.style.flex > 0\)')
|
||||
.replace(/setTrailingPosition\((.+?),\s*(.+?),\s*(.+?)\)/g, '$2.layout.position[trailing[$3]] = $1.layout.measuredDimensions[dim[$3]] - ($2.style.positionType == CSSPositionType.Absolute ? 0 : $2.layout.measuredDimensions[dim[$3]]) - $2.layout.position[pos[$3]]')
|
||||
.replace(/isFlex\((.+?)\)/g, '\($1.style.positionType == CSSPositionType.RELATIVE && $1.style.flex != 0\)')
|
||||
.replace(/isFlexWrap\((.+?)\)/g, '\($1.style.flexWrap == CSSWrap.WRAP\)')
|
||||
.replace(/getPaddingAndBorderAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingPaddingAndBorder($1, $2) + getTrailingPaddingAndBorder($1, $2)\)')
|
||||
.replace(/getBorderAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingBorder($1, $2) + getTrailingBorder($1, $2)\)')
|
||||
.replace(/getMarginAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
|
||||
.replace(/getLeadingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getLeadingPadding($1, $2) + getLeadingBorder($1, $2)\)')
|
||||
.replace(/getTrailingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getTrailingPadding($1, $2) + getTrailingBorder($1, $2)\)')
|
||||
.replace(/getDimWithMargin\((.+?),\s*(.+?)\)/g, '\($1.layout.dimensions[dim[$2]] + getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
|
||||
.replace(/getDimWithMargin\((.+?),\s*(.+?)\)/g, '\($1.layout.measuredDimensions[dim[$2]] + getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
|
||||
.replace(/getLeadingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(leadingSpacing[$2], leading[$2])')
|
||||
.replace(/getTrailingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(trailingSpacing[$2], trailing[$2])')
|
||||
.replace(/getLeadingPadding\((.+?),\s*(.+?)\)/g, '$1.style.padding.getWithFallback(leadingSpacing[$2], leading[$2])')
|
||||
@@ -51,14 +64,18 @@ function __transpileToCSharpCommon(code) {
|
||||
.replace(/getLeadingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(leadingSpacing[$2], leading[$2])')
|
||||
.replace(/getTrailingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(trailingSpacing[$2], trailing[$2])')
|
||||
.replace(/isRowDirection\((.+?)\)/g, '\($1 == CSS_FLEX_DIRECTION_ROW || $1 == CSS_FLEX_DIRECTION_ROW_REVERSE\)')
|
||||
.replace(/assert\((.+?),\s*'(.+?)'\)/g, 'Assertions.assertCondition($1, "$2")')
|
||||
.replace(/isUndefined\((.+?)\)/g, 'float.IsNaN\($1\)')
|
||||
.replace(/getOverflow\((.+?)\)/g, '$1.style.overflow')
|
||||
.replace(/layoutNodeInternal\((.+?)\)/g, 'layoutNodeInternal(layoutContext, $1)')
|
||||
.replace(/style\.position\[CSS_/g, 'style.position[POSITION_')
|
||||
.replace(/\/\*\(c\)!([^*]+)\*\//g, '')
|
||||
.replace(/var\/\*\(java\)!([^*]+)\*\//g, '$1')
|
||||
.replace(/\/\*\(java\)!([^*]+)\*\//g, '$1')
|
||||
|
||||
// additional case conversions
|
||||
|
||||
.replace(/(CSSConstants|CSSWrap|CSSJustify|CSSMeasureMode|CSSAlign|CSSPositionType)\.([_A-Z]+)/g,
|
||||
.replace(/(CSSConstants|CSSWrap|CSSJustify|CSSMeasureMode|CSSAlign|CSSPositionType|CSSOverflow)\.([_A-Z]+)/g,
|
||||
function(str, match1, match2) {
|
||||
return match1 + '.' + constantToPascalCase(match2);
|
||||
});
|
||||
@@ -139,12 +156,12 @@ var CSharpTranspiler = {
|
||||
transpileLayoutEngine: function(code) {
|
||||
return indent(
|
||||
__transpileToCSharpCommon(code)
|
||||
.replace(/function\s+layoutNode.*/, '')
|
||||
.replace('node.style.measure', 'node.measure')
|
||||
.replace(/\.children\.length/g, '.getChildCount()')
|
||||
.replace(/node.children\[i\]/g, 'node.getChildAt(i)')
|
||||
.replace(/node.children\[ii\]/g, 'node.getChildAt(ii)')
|
||||
.replace(/node.children\[j\]/g, 'node.getChildAt(j)')
|
||||
.replace(/fmaxf/g, 'Math.Max')
|
||||
.replace(/fminf/g, 'Math.Min')
|
||||
.replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages
|
||||
.replace(/var\/\*([^\/]+)\*\//g, '$1')
|
||||
.replace(/ === /g, ' == ')
|
||||
|
@@ -9,11 +9,18 @@
|
||||
|
||||
function __transpileToJavaCommon(code) {
|
||||
return code
|
||||
.replace(/'abs-layout'/g, '"abs-layout"')
|
||||
.replace(/'abs-measure'/g, '"abs-measure"')
|
||||
.replace(/'flex'/g, '"flex"')
|
||||
.replace(/'measure'/g, '"measure"')
|
||||
.replace(/'stretch'/g, '"stretch"')
|
||||
.replace(/undefined/g, 'null')
|
||||
.replace(/CSS_UNDEFINED/g, 'CSSConstants.UNDEFINED')
|
||||
.replace(/CSS_JUSTIFY_/g, 'CSSJustify.')
|
||||
.replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.')
|
||||
.replace(/CSS_ALIGN_/g, 'CSSAlign.')
|
||||
.replace(/CSS_POSITION_/g, 'CSSPositionType.')
|
||||
.replace(/CSS_OVERFLOW_/g, 'CSSOverflow.')
|
||||
.replace(/css_flex_direction_t/g, 'CSSFlexDirection')
|
||||
.replace(/css_direction_t/g, 'CSSDirection')
|
||||
.replace(/css_align_t/g, 'CSSAlign')
|
||||
@@ -21,6 +28,10 @@ function __transpileToJavaCommon(code) {
|
||||
.replace(/css_measure_mode_t/g, 'CSSMeasureMode')
|
||||
.replace(/css_dim_t/g, 'MeasureOutput')
|
||||
.replace(/bool/g, 'boolean')
|
||||
.replace(/style\[CSS_LEFT/g, 'style.position[POSITION_LEFT')
|
||||
.replace(/style\[CSS_TOP/g, 'style.position[POSITION_TOP')
|
||||
.replace(/style\[CSS_RIGHT/g, 'style.position[POSITION_RIGHT')
|
||||
.replace(/style\[CSS_BOTTOM/g, 'style.position[POSITION_BOTTOM')
|
||||
.replace(/style\[dim/g, 'style.dimensions[dim')
|
||||
.replace(/(style|layout)\.width/g, '$1.dimensions[DIMENSION_WIDTH]')
|
||||
.replace(/(style|layout)\.height/g, '$1.dimensions[DIMENSION_HEIGHT]')
|
||||
@@ -28,22 +39,24 @@ function __transpileToJavaCommon(code) {
|
||||
.replace(/layout\[pos/g, 'layout.position[pos')
|
||||
.replace(/layout\[leading/g, 'layout.position[leading')
|
||||
.replace(/layout\[trailing/g, 'layout.position[trailing')
|
||||
.replace(/layout\[measuredDim/g, 'layout.measuredDimensions[dim')
|
||||
.replace(/layout\.measuredWidth/g, 'layout.measuredDimensions[DIMENSION_WIDTH]')
|
||||
.replace(/layout\.measuredHeight/g, 'layout.measuredDimensions[DIMENSION_HEIGHT]')
|
||||
.replace(/getPositionType\((.+?)\)/g, '$1.style.positionType')
|
||||
.replace(/getJustifyContent\((.+?)\)/g, '$1.style.justifyContent')
|
||||
.replace(/getAlignContent\((.+?)\)/g, '$1.style.alignContent')
|
||||
.replace(/isPosDefined\((.+?),\s*(.+?)\)/g, '!isUndefined\($1.style.position[$2]\)')
|
||||
.replace(/isStyleDimDefined\((.+?),\s*(.+?)\)/g, '\(!isUndefined\($1.style.dimensions[dim[$2]]\) && $1.style.dimensions[dim[$2]] >= 0.0\)')
|
||||
.replace(/isLayoutDimDefined\((.+?),\s*(.+?)\)/g, '\(!isUndefined\($1.layout.dimensions[dim[$2]]\) && $1.layout.dimensions[dim[$2]] >= 0.0\)')
|
||||
.replace(/isStyleDimDefined\((.+?),\s*(.+?)\)/g, '($1.style.dimensions[dim[$2]] >= 0.0)')
|
||||
.replace(/isLayoutDimDefined\((.+?),\s*(.+?)\)/g, '($1.layout.measuredDimensions[dim[$2]] >= 0.0)')
|
||||
.replace(/getPosition\((.+?),\s*(.+?)\)/g, '\(isUndefined\($1.style.position[$2]\) ? 0 : $1.style.position[$2]\)')
|
||||
.replace(/setTrailingPosition\((.+?),\s*(.+?),\s*(.+?)\)/g, '$2.layout.position[trailing[$3]] = $1.layout.dimensions[dim[$3]] - $2.layout.dimensions[dim[$3]] - $2.layout.position[pos[$3]]')
|
||||
.replace(/isFlex\((.+?)\)/g, '\($1.style.positionType == CSSPositionType.RELATIVE && $1.style.flex > 0\)')
|
||||
.replace(/setTrailingPosition\((.+?),\s*(.+?),\s*(.+?)\)/g, '$2.layout.position[trailing[$3]] = $1.layout.measuredDimensions[dim[$3]] - ($2.style.positionType == CSSPositionType.ABSOLUTE ? 0 : $2.layout.measuredDimensions[dim[$3]]) - $2.layout.position[pos[$3]]')
|
||||
.replace(/isFlex\((.+?)\)/g, '\($1.style.positionType == CSSPositionType.RELATIVE && $1.style.flex != 0\)')
|
||||
.replace(/isFlexWrap\((.+?)\)/g, '\($1.style.flexWrap == CSSWrap.WRAP\)')
|
||||
.replace(/getPaddingAndBorderAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingPaddingAndBorder($1, $2) + getTrailingPaddingAndBorder($1, $2)\)')
|
||||
.replace(/getBorderAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingBorder($1, $2) + getTrailingBorder($1, $2)\)')
|
||||
.replace(/getMarginAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
|
||||
.replace(/getLeadingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getLeadingPadding($1, $2) + getLeadingBorder($1, $2)\)')
|
||||
.replace(/getTrailingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getTrailingPadding($1, $2) + getTrailingBorder($1, $2)\)')
|
||||
.replace(/getDimWithMargin\((.+?),\s*(.+?)\)/g, '\($1.layout.dimensions[dim[$2]] + getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
|
||||
.replace(/getDimWithMargin\((.+?),\s*(.+?)\)/g, '\($1.layout.measuredDimensions[dim[$2]] + getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
|
||||
.replace(/getLeadingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(leadingSpacing[$2], leading[$2])')
|
||||
.replace(/getTrailingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(trailingSpacing[$2], trailing[$2])')
|
||||
.replace(/getLeadingPadding\((.+?),\s*(.+?)\)/g, '$1.style.padding.getWithFallback(leadingSpacing[$2], leading[$2])')
|
||||
@@ -51,7 +64,11 @@ function __transpileToJavaCommon(code) {
|
||||
.replace(/getLeadingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(leadingSpacing[$2], leading[$2])')
|
||||
.replace(/getTrailingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(trailingSpacing[$2], trailing[$2])')
|
||||
.replace(/isRowDirection\((.+?)\)/g, '\($1 == CSS_FLEX_DIRECTION_ROW || $1 == CSS_FLEX_DIRECTION_ROW_REVERSE\)')
|
||||
.replace(/assert\((.+?),\s*'(.+?)'\)/g, 'Assertions.assertCondition($1, "$2")')
|
||||
.replace(/isUndefined\((.+?)\)/g, 'Float.isNaN\($1\)')
|
||||
.replace(/getOverflow\((.+?)\)/g, '$1.style.overflow')
|
||||
.replace(/layoutNodeInternal\((.+?)\)/g, 'layoutNodeInternal(layoutContext, $1)')
|
||||
.replace(/style\.position\[CSS_/g, 'style.position[POSITION_')
|
||||
.replace(/\/\*\(c\)!([^*]+)\*\//g, '')
|
||||
.replace(/var\/\*\(java\)!([^*]+)\*\//g, '$1')
|
||||
.replace(/\/\*\(java\)!([^*]+)\*\//g, '$1');
|
||||
@@ -118,12 +135,12 @@ var JavaTranspiler = {
|
||||
transpileLayoutEngine: function(code) {
|
||||
return indent(
|
||||
__transpileToJavaCommon(code)
|
||||
.replace(/function\s+layoutNode.*/, '')
|
||||
.replace('node.style.measure', 'node.measure')
|
||||
.replace(/\.children\.length/g, '.getChildCount()')
|
||||
.replace(/node.children\[i\]/g, 'node.getChildAt(i)')
|
||||
.replace(/node.children\[ii\]/g, 'node.getChildAt(ii)')
|
||||
.replace(/node.children\[j\]/g, 'node.getChildAt(j)')
|
||||
.replace(/fmaxf/g, 'Math.max')
|
||||
.replace(/fminf/g, 'Math.min')
|
||||
.replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages
|
||||
.replace(/var\/\*([^\/]+)\*\//g, '$1')
|
||||
.replace(/ === /g, ' == ')
|
||||
|
@@ -92,6 +92,7 @@ var layoutTestUtils = (function() {
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
hack to ignore three hundred px width of the body {}
|
||||
@@ -115,20 +116,28 @@ var layoutTestUtils = (function() {
|
||||
if (typeof computeLayout === 'object') {
|
||||
var fillNodes = computeLayout.fillNodes;
|
||||
var realComputeLayout = computeLayout.computeLayout;
|
||||
var canUseCachedMeasurement = computeLayout.canUseCachedMeasurement;
|
||||
}
|
||||
|
||||
function extractNodes(node) {
|
||||
var layout = node.layout;
|
||||
delete node.layout;
|
||||
var keysToCopy = [
|
||||
'width',
|
||||
'height',
|
||||
'left',
|
||||
'top'
|
||||
];
|
||||
var layout = {};
|
||||
keysToCopy.forEach(function(key) {
|
||||
layout[key] = node.layout[key];
|
||||
});
|
||||
|
||||
if (node.children && node.children.length > 0) {
|
||||
layout.children = node.children.map(extractNodes);
|
||||
} else {
|
||||
delete node.children;
|
||||
}
|
||||
|
||||
delete layout.right;
|
||||
delete layout.bottom;
|
||||
delete layout.direction;
|
||||
|
||||
delete node.layout;
|
||||
|
||||
return layout;
|
||||
}
|
||||
@@ -183,13 +192,17 @@ var layoutTestUtils = (function() {
|
||||
|
||||
function computeDOMLayout(node) {
|
||||
var body = getIframe().contentDocument.body;
|
||||
|
||||
|
||||
function setStyle(div, name, value) {
|
||||
div.style['-webkit-' + name] = value;
|
||||
div.style['webkit' + capitalizeFirst(name)] = value;
|
||||
div.style[name] = value;
|
||||
}
|
||||
|
||||
function transfer(div, node, name, ext) {
|
||||
if (name in node.style) {
|
||||
var value = node.style[name] + (ext || '');
|
||||
div.style['-webkit-' + name] = value;
|
||||
div.style['webkit' + capitalizeFirst(name)] = value;
|
||||
div.style[name] = value;
|
||||
setStyle(div, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +215,19 @@ var layoutTestUtils = (function() {
|
||||
transfer(div, node, type + 'Start' + suffix, 'px');
|
||||
transfer(div, node, type + 'End' + suffix, 'px');
|
||||
}
|
||||
|
||||
|
||||
function transferFlex(div, node) {
|
||||
if ('flex' in node.style) {
|
||||
var flex = node.style.flex;
|
||||
var resolvedFlex = (
|
||||
flex < 0 ? '0 1 auto' :
|
||||
flex > 0 ? (flex + ' 0 0') :
|
||||
'0 0 auto'
|
||||
);
|
||||
setStyle(div, 'flex', resolvedFlex);
|
||||
}
|
||||
}
|
||||
|
||||
function renderNode(parent, node) {
|
||||
var div = document.createElement('div');
|
||||
transfer(div, node, 'width', 'px');
|
||||
@@ -220,13 +245,14 @@ var layoutTestUtils = (function() {
|
||||
transferSpacing(div, node, 'border', 'Width');
|
||||
transfer(div, node, 'flexDirection');
|
||||
transfer(div, node, 'direction');
|
||||
transfer(div, node, 'flex');
|
||||
transferFlex(div, node);
|
||||
transfer(div, node, 'flexWrap');
|
||||
transfer(div, node, 'justifyContent');
|
||||
transfer(div, node, 'alignSelf');
|
||||
transfer(div, node, 'alignItems');
|
||||
transfer(div, node, 'alignContent');
|
||||
transfer(div, node, 'position');
|
||||
transfer(div, node, 'overflow');
|
||||
parent.appendChild(div);
|
||||
(node.children || []).forEach(function(child) {
|
||||
renderNode(div, child);
|
||||
@@ -299,6 +325,22 @@ var layoutTestUtils = (function() {
|
||||
function testExtractNodes(node, extractedNode) {
|
||||
expect(extractNodes(node)).toEqual(extractedNode);
|
||||
}
|
||||
|
||||
function testCanUseCachedMeasurement(canReuse, spec, cacheEntry) {
|
||||
var availableWidth = spec.availableWidth;
|
||||
var availableHeight = spec.availableHeight;
|
||||
var widthMeasureMode = spec.widthMeasureMode;
|
||||
var heightMeasureMode = spec.heightMeasureMode;
|
||||
|
||||
expect(
|
||||
canUseCachedMeasurement(
|
||||
availableWidth, availableHeight,
|
||||
0, 0,
|
||||
widthMeasureMode, heightMeasureMode,
|
||||
cacheEntry
|
||||
)
|
||||
).toEqual(canReuse);
|
||||
}
|
||||
|
||||
function testNamedLayout(name, layoutA, layoutB) {
|
||||
expect(nameLayout(name, layoutA))
|
||||
@@ -479,6 +521,7 @@ var layoutTestUtils = (function() {
|
||||
},
|
||||
testFillNodes: testFillNodes,
|
||||
testExtractNodes: testExtractNodes,
|
||||
testCanUseCachedMeasurement: testCanUseCachedMeasurement,
|
||||
testRandomLayout: function(node) {
|
||||
var layout = computeCSSLayout(node);
|
||||
var domLayout = computeDOMLayout(node);
|
||||
|
1799
src/Layout.c
1799
src/Layout.c
File diff suppressed because it is too large
Load Diff
52
src/Layout.h
52
src/Layout.h
@@ -44,6 +44,11 @@ typedef enum {
|
||||
CSS_JUSTIFY_SPACE_AROUND
|
||||
} css_justify_t;
|
||||
|
||||
typedef enum {
|
||||
CSS_OVERFLOW_VISIBLE = 0,
|
||||
CSS_OVERFLOW_HIDDEN
|
||||
} css_overflow_t;
|
||||
|
||||
// Note: auto is only a valid value for alignSelf. It is NOT a valid value for
|
||||
// alignItems.
|
||||
typedef enum {
|
||||
@@ -79,7 +84,8 @@ typedef enum {
|
||||
typedef enum {
|
||||
CSS_MEASURE_MODE_UNDEFINED = 0,
|
||||
CSS_MEASURE_MODE_EXACTLY,
|
||||
CSS_MEASURE_MODE_AT_MOST
|
||||
CSS_MEASURE_MODE_AT_MOST,
|
||||
CSS_MEASURE_MODE_COUNT
|
||||
} css_measure_mode_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -87,20 +93,40 @@ typedef enum {
|
||||
CSS_HEIGHT
|
||||
} css_dimension_t;
|
||||
|
||||
typedef struct {
|
||||
float available_width;
|
||||
float available_height;
|
||||
css_measure_mode_t width_measure_mode;
|
||||
css_measure_mode_t height_measure_mode;
|
||||
|
||||
float computed_width;
|
||||
float computed_height;
|
||||
} css_cached_measurement_t;
|
||||
|
||||
enum {
|
||||
// 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.
|
||||
CSS_MAX_CACHED_RESULT_COUNT = 16
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float position[4];
|
||||
float dimensions[2];
|
||||
css_direction_t direction;
|
||||
|
||||
float flex_basis;
|
||||
|
||||
// Instead of recomputing the entire layout every single time, we
|
||||
// cache some information to break early when nothing changed
|
||||
bool should_update;
|
||||
float last_requested_dimensions[2];
|
||||
float last_parent_max_width;
|
||||
float last_parent_max_height;
|
||||
float last_dimensions[2];
|
||||
float last_position[2];
|
||||
css_direction_t last_direction;
|
||||
int generation_count;
|
||||
css_direction_t last_parent_direction;
|
||||
|
||||
int next_cached_measurements_index;
|
||||
css_cached_measurement_t cached_measurements[CSS_MAX_CACHED_RESULT_COUNT];
|
||||
float measured_dimensions[2];
|
||||
|
||||
css_cached_measurement_t cached_layout;
|
||||
} css_layout_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -116,6 +142,7 @@ typedef struct {
|
||||
css_align_t align_self;
|
||||
css_position_type_t position_type;
|
||||
css_wrap_type_t flex_wrap;
|
||||
css_overflow_t overflow;
|
||||
float flex;
|
||||
float margin[6];
|
||||
float position[4];
|
||||
@@ -143,8 +170,7 @@ struct css_node {
|
||||
int children_count;
|
||||
int line_index;
|
||||
|
||||
css_node_t *next_absolute_child;
|
||||
css_node_t *next_flex_child;
|
||||
css_node_t* next_child;
|
||||
|
||||
css_dim_t (*measure)(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode);
|
||||
void (*print)(void *context);
|
||||
@@ -166,12 +192,8 @@ typedef enum {
|
||||
} css_print_options_t;
|
||||
void print_css_node(css_node_t *node, css_print_options_t options);
|
||||
|
||||
// Function that computes the layout!
|
||||
void layoutNode(css_node_t *node, float availableWidth, float availableHeight, css_direction_t parentDirection);
|
||||
bool isUndefined(float value);
|
||||
|
||||
// Function that computes the layout!
|
||||
void layoutNode(css_node_t *node, float maxWidth, float maxHeight, css_direction_t parentDirection);
|
||||
|
||||
// Reset the calculated layout values for a given node. You should call this before `layoutNode`.
|
||||
void resetNodeLayout(css_node_t *node);
|
||||
|
||||
#endif
|
||||
|
1691
src/Layout.js
1691
src/Layout.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ var testLayout = layoutTestUtils.testLayout;
|
||||
var testLayoutAgainstDomOnly = layoutTestUtils.testLayoutAgainstDomOnly;
|
||||
var testLayoutAgainstExpectedOnly = layoutTestUtils.testLayoutAgainstExpectedOnly;
|
||||
var testFillNodes = layoutTestUtils.testFillNodes;
|
||||
var testCanUseCachedMeasurement = layoutTestUtils.testCanUseCachedMeasurement;
|
||||
var text = layoutTestUtils.text;
|
||||
var texts = layoutTestUtils.texts;
|
||||
var textSizes = layoutTestUtils.textSizes;
|
||||
@@ -38,6 +39,152 @@ describe('Javascript Only', function() {
|
||||
{layout: {width: 200}},
|
||||
{layout: {width: 200}, style: {}, children: []}
|
||||
);
|
||||
});
|
||||
it('should only invoke measure function one time in simple layout', function() {
|
||||
var measureInvocations = 0;
|
||||
function measure(width, widthMode, height, heightMode) {
|
||||
measureInvocations++;
|
||||
return { width: 25, height: 25 };
|
||||
}
|
||||
|
||||
testLayoutAgainstExpectedOnly(
|
||||
{style: {width: 100, height: 100}, children: [
|
||||
{style: {measure: measure}}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 25, top: 0, left: 0}
|
||||
]}
|
||||
);
|
||||
|
||||
expect(measureInvocations).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('JavaScript Only: canUseCachedTextMeasurement', function() {
|
||||
var measureModes = ['undefined', 'exactly', 'at-most'];
|
||||
|
||||
var assertCanReuse = testCanUseCachedMeasurement.bind(null, true);
|
||||
var assertCannotReuse = testCanUseCachedMeasurement.bind(null, false);
|
||||
|
||||
it('should not reuse when width mode is "exactly" and available width != measurement', function() {
|
||||
measureModes.forEach(function(widthMeasureMode) {
|
||||
measureModes.forEach(function(heightMeasureMode) {
|
||||
var computedWidth = 100;
|
||||
var computedHeight = 200;
|
||||
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
||||
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
||||
|
||||
var cacheEntry = {
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: computedWidth,
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: computedHeight
|
||||
};
|
||||
|
||||
assertCannotReuse(
|
||||
{
|
||||
availableWidth: computedWidth - 1, widthMeasureMode: 'exactly',
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode
|
||||
},
|
||||
cacheEntry
|
||||
);
|
||||
|
||||
assertCannotReuse(
|
||||
{
|
||||
availableWidth: computedWidth + 1, widthMeasureMode: 'exactly',
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode
|
||||
},
|
||||
cacheEntry
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not reuse when height mode is "exactly" and available height != measurement', function() {
|
||||
measureModes.forEach(function(widthMeasureMode) {
|
||||
measureModes.forEach(function(heightMeasureMode) {
|
||||
var computedWidth = 100;
|
||||
var computedHeight = 200;
|
||||
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
||||
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
||||
|
||||
var cacheEntry = {
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: computedWidth,
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: computedHeight
|
||||
};
|
||||
|
||||
assertCannotReuse(
|
||||
{
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
||||
availableHeight: computedHeight - 1, heightMeasureMode: 'exactly'
|
||||
},
|
||||
cacheEntry
|
||||
);
|
||||
|
||||
assertCannotReuse(
|
||||
{
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
||||
availableHeight: computedHeight + 1, heightMeasureMode: 'exactly'
|
||||
},
|
||||
cacheEntry
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should reuse exact matches', function() {
|
||||
measureModes.forEach(function(widthMeasureMode) {
|
||||
measureModes.forEach(function(heightMeasureMode) {
|
||||
var availableWidth = widthMeasureMode === 'undefined' ? undefined : 100;
|
||||
var availableHeight = heightMeasureMode === 'undefined' ? undefined : 200;
|
||||
assertCanReuse(
|
||||
{
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode
|
||||
},
|
||||
{
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: 1,
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: 2
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should reuse cache entry with unconstrained width when width mode is "exactly" and available width == measurement', function() {
|
||||
measureModes.forEach(function(heightMeasureMode) {
|
||||
var computedWidth = 100;
|
||||
var computedHeight = 200;
|
||||
var availableHeight = heightMeasureMode === 'undefined' ? undefined : computedHeight;
|
||||
|
||||
assertCanReuse(
|
||||
{
|
||||
availableWidth: computedWidth, widthMeasureMode: 'exactly',
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode
|
||||
},
|
||||
{
|
||||
availableWidth: undefined, widthMeasureMode: 'undefined', computedWidth: computedWidth,
|
||||
availableHeight: availableHeight, heightMeasureMode: heightMeasureMode, computedHeight: computedHeight
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should reuse cache entry with unconstrained height when height mode is "exactly" and height == measurement', function() {
|
||||
measureModes.forEach(function(widthMeasureMode) {
|
||||
var computedWidth = 100;
|
||||
var computedHeight = 200;
|
||||
var availableWidth = widthMeasureMode === 'undefined' ? undefined : computedWidth;
|
||||
|
||||
assertCanReuse(
|
||||
{
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode,
|
||||
availableHeight: computedHeight, heightMeasureMode: 'exactly'
|
||||
},
|
||||
{
|
||||
availableWidth: availableWidth, widthMeasureMode: widthMeasureMode, computedWidth: computedWidth,
|
||||
availableHeight: undefined, heightMeasureMode: 'undefined', computedHeight: computedHeight
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1238,7 +1385,7 @@ describe('Layout', function() {
|
||||
testLayoutAgainstExpectedOnly(
|
||||
{style: {width: 320, flexDirection: 'column'}, children: [
|
||||
{style: {measure: measureWithRatio2}},
|
||||
{style: {height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {height: 100, flexDirection: 'row', overflow: 'hidden'}, children: [
|
||||
{style: {measure: measureWithRatio2}},
|
||||
{style: {measure: measureWithRatio2}}
|
||||
]},
|
||||
@@ -1354,14 +1501,16 @@ describe('Layout', function() {
|
||||
});
|
||||
|
||||
it('should layout node with text bounded by grand-parent', function() {
|
||||
testLayout(
|
||||
testLayoutAgainstExpectedOnly(
|
||||
{style: {width: 100, padding: 10, alignSelf: 'flex-start'}, children: [
|
||||
{style: {margin: 10, alignSelf: 'flex-start'}, children: [
|
||||
{style: {measure: text(texts.big)}}
|
||||
]}
|
||||
]},
|
||||
{width: 100, height: 40 + textSizes.bigHeight, top: 0, left: 0, children: [
|
||||
{width: textSizes.bigMinWidth, height: textSizes.bigHeight, top: 20, left: 20, children: [
|
||||
// In the flexbox engine implementation, min width of text is not supported so we max
|
||||
// out at the amount of available space (60)
|
||||
{width: Math.min(60, textSizes.bigMinWidth), height: textSizes.bigHeight, top: 20, left: 20, children: [
|
||||
{width: textSizes.bigMinWidth, height: textSizes.bigHeight, top: 0, left: 0}
|
||||
]}
|
||||
]}
|
||||
@@ -2149,6 +2298,30 @@ describe('Layout', function() {
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should center flexible item with max size', function() {
|
||||
testLayout(
|
||||
{style: {width: 1000, height: 1000, flexDirection: 'row', justifyContent: 'center'}, children: [
|
||||
{style: {flex: 1, maxWidth: 600, height: 1000}}
|
||||
]},
|
||||
{width: 1000, height: 1000, top: 0, left: 0, children: [
|
||||
{width: 600, height: 1000, top: 0, left: 200}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should correctly size flexible items with flex basis and a max width', function() {
|
||||
testLayout(
|
||||
{style: {width: 1000, height: 1000, flexDirection: 'row'}, children: [
|
||||
{style: {flex: 1, width: 100, height: 1000}},
|
||||
{style: {flex: 1, width: 100, maxWidth: 200, height: 1000}}
|
||||
]},
|
||||
{width: 1000, height: 1000, top: 0, left: 0, children: [
|
||||
{width: 800, height: 1000, top: 0, left: 0},
|
||||
{width: 200, height: 1000, top: 0, left: 800}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
xit('should layout node with a nested sibling child with width', function() {
|
||||
testLayout(
|
||||
@@ -2485,6 +2658,307 @@ describe('Layout', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Layout flex:-1', function() {
|
||||
// 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() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100}, children: [
|
||||
{style: {width: 100, flex: -1}, children: [
|
||||
{style: {width: 100, height: 25}}
|
||||
]}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 25, top: 0, left: 0, children: [
|
||||
{width: 100, height: 25, top: 0, left: 0}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink column node when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100}, children: [
|
||||
{style: {width: 100, flex: -1}, children: [
|
||||
{style: {width: 100, height: 200}}
|
||||
]}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 200, top: 0, left: 0}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should not shrink column node with siblings when there is space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100}, children: [
|
||||
{style: {width: 100, height: 25}},
|
||||
{style: {width: 100, flex: -1}, children: [
|
||||
{style: {width: 100, height: 30}}
|
||||
]},
|
||||
{style: {width: 100, height: 15}},
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 25, top: 0, left: 0},
|
||||
{width: 100, height: 30, top: 25, left: 0, children: [
|
||||
{width: 100, height: 30, top: 0, left: 0}
|
||||
]},
|
||||
{width: 100, height: 15, top: 55, left: 0},
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink column node with siblings when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100}, children: [
|
||||
{style: {width: 100, height: 25}},
|
||||
{style: {width: 100, flex: -1}, children: [
|
||||
{style: {width: 100, height: 80}}
|
||||
]},
|
||||
{style: {width: 100, height: 15}},
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 25, top: 0, left: 0},
|
||||
{width: 100, height: 60, top: 25, left: 0, children: [
|
||||
{width: 100, height: 80, top: 0, left: 0}
|
||||
]},
|
||||
{width: 100, height: 15, top: 85, left: 0},
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink column nodes proportional to their main size when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100}, children: [
|
||||
{style: {width: 100, height: 30, flex: -1}},
|
||||
{style: {width: 100, height: 40}},
|
||||
{style: {width: 100, height: 50, flex: -1}}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 22.5, top: 0, left: 0},
|
||||
{width: 100, height: 40, top: 22.5, left: 0},
|
||||
{width: 100, height: 37.5, top: 62.5, left: 0}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
// 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() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {height: 100, flex: -1}, children: [
|
||||
{style: {width: 25, height: 100}}
|
||||
]}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink visible row node when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {height: 100, flex: -1}, children: [
|
||||
{style: {width: 200, height: 100}}
|
||||
]}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
// width would be 100 if we implemented https://www.w3.org/TR/css-flexbox-1/#min-size-auto and min-width didn't default to 0
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 200, height: 100, top: 0, left: 0}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should not shrink visible row node with siblings when there is space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 25, height: 100}},
|
||||
{style: {height: 100, flex: -1}, children: [
|
||||
{style: {width: 30, height: 100}}
|
||||
]},
|
||||
{style: {width: 15, height: 100}},
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0},
|
||||
{width: 30, height: 100, top: 0, left: 25, children: [
|
||||
{width: 30, height: 100, top: 0, left: 0}
|
||||
]},
|
||||
{width: 15, height: 100, top: 0, left: 55},
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink visible row node with siblings when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 25, height: 100}},
|
||||
{style: {height: 100, flex: -1}, children: [
|
||||
{style: {width: 80, height: 100}}
|
||||
]},
|
||||
{style: {width: 15, height: 100}},
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0},
|
||||
// width would be 80 if we implemented https://www.w3.org/TR/css-flexbox-1/#min-size-auto and min-width didn't default to 0
|
||||
{width: 60, height: 100, top: 0, left: 25, children: [
|
||||
{width: 80, height: 100, top: 0, left: 0}
|
||||
]},
|
||||
{width: 15, height: 100, top: 0, left: 85},
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink visible row nodes when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 30, height: 100, flex: -1}},
|
||||
{style: {width: 40, height: 100}},
|
||||
{style: {width: 50, height: 100, flex: -1}}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
// width would be 30 if we implemented https://www.w3.org/TR/css-flexbox-1/#min-size-auto and min-width didn't default to 0
|
||||
{width: 22.5, height: 100, top: 0, left: 0},
|
||||
{width: 40, height: 100, top: 0, left: 22.5},
|
||||
// width would be 50 if we implemented https://www.w3.org/TR/css-flexbox-1/#min-size-auto and min-width didn't default to 0
|
||||
{width: 37.5, height: 100, top: 0, left: 62.5}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
// 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() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {height: 100, flex: -1, overflow: 'hidden'}, children: [
|
||||
{style: {width: 25, height: 100}}
|
||||
]}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink hidden row node when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {height: 100, flex: -1, overflow: 'hidden'}, children: [
|
||||
{style: {width: 200, height: 100}}
|
||||
]}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 200, height: 100, top: 0, left: 0}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should not shrink hidden row node with siblings when there is space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 25, height: 100}},
|
||||
{style: {height: 100, flex: -1, overflow: 'hidden'}, children: [
|
||||
{style: {width: 30, height: 100}}
|
||||
]},
|
||||
{style: {width: 15, height: 100}},
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0},
|
||||
{width: 30, height: 100, top: 0, left: 25, children: [
|
||||
{width: 30, height: 100, top: 0, left: 0}
|
||||
]},
|
||||
{width: 15, height: 100, top: 0, left: 55},
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink hidden row node with siblings when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 25, height: 100}},
|
||||
{style: {height: 100, flex: -1, overflow: 'hidden'}, children: [
|
||||
{style: {width: 80, height: 100}}
|
||||
]},
|
||||
{style: {width: 15, height: 100}},
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0},
|
||||
{width: 60, height: 100, top: 0, left: 25, children: [
|
||||
{width: 80, height: 100, top: 0, left: 0}
|
||||
]},
|
||||
{width: 15, height: 100, top: 0, left: 85},
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink hidden row nodes proportional to their main size when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 100, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 30, height: 100, flex: -1, overflow: 'hidden'}},
|
||||
{style: {width: 40, height: 100}},
|
||||
{style: {width: 50, height: 100, flex: -1, overflow: 'hidden'}}
|
||||
]},
|
||||
{width: 100, height: 100, top: 0, left: 0, children: [
|
||||
{width: 22.5, height: 100, top: 0, left: 0},
|
||||
{width: 40, height: 100, top: 0, left: 22.5},
|
||||
{width: 37.5, height: 100, top: 0, left: 62.5}
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
// 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() {
|
||||
testLayoutAgainstExpectedOnly(
|
||||
{style: {width: 213, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 25, height: 100}},
|
||||
{style: {height: 100, flex: -1, flexDirection: 'row', alignItems: 'flex-start'}, children: [
|
||||
{style: {measure: text(texts.big)}}
|
||||
]},
|
||||
{style: {width: 15, height: 100}},
|
||||
]},
|
||||
{width: 213, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0},
|
||||
{width: textSizes.bigWidth, height: 100, top: 0, left: 25, children: [
|
||||
{width: textSizes.bigWidth, height: textSizes.smallHeight, top: 0, left: 0}
|
||||
]},
|
||||
{width: 15, height: 100, top: 0, left: 25 + textSizes.bigWidth},
|
||||
]}
|
||||
);
|
||||
});
|
||||
|
||||
it('should shrink text node with siblings when there is not any space left over', function() {
|
||||
testLayout(
|
||||
{style: {width: 140, height: 100, flexDirection: 'row'}, children: [
|
||||
{style: {width: 25, height: 100}},
|
||||
{style: {height: 100, flex: -1, flexDirection: 'row', alignItems: 'flex-start'}, children: [
|
||||
{style: {flex: -1, measure: text(texts.big)}}
|
||||
]},
|
||||
{style: {width: 15, height: 100}},
|
||||
]},
|
||||
{width: 140, height: 100, top: 0, left: 0, children: [
|
||||
{width: 25, height: 100, top: 0, left: 0},
|
||||
{width: textSizes.bigMinWidth, height: 100, top: 0, left: 25, children: [
|
||||
{width: textSizes.bigMinWidth, height: textSizes.bigHeight, top: 0, left: 0}
|
||||
]},
|
||||
{width: 15, height: 100, top: 0, left: 25 + textSizes.bigMinWidth},
|
||||
]}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Layout alignContent', function() {
|
||||
|
||||
it('should layout with alignContent: stretch, and alignItems: flex-start', function() {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -18,5 +18,10 @@ namespace Facebook.CSSLayout
|
||||
Debug.Assert(v != null);
|
||||
return v;
|
||||
}
|
||||
|
||||
public static void assertCondition(bool condition, string explanation)
|
||||
{
|
||||
Debug.Assert(condition, explanation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
src/csharp/Facebook.CSSLayout/CSSCachedMeasurement.cs
Normal file
22
src/csharp/Facebook.CSSLayout/CSSCachedMeasurement.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
namespace Facebook.CSSLayout
|
||||
{
|
||||
sealed class CSSCachedMeasurement
|
||||
{
|
||||
public float availableWidth;
|
||||
public float availableHeight;
|
||||
public CSSMeasureMode? widthMeasureMode = null;
|
||||
public CSSMeasureMode? heightMeasureMode = null;
|
||||
|
||||
public float computedWidth;
|
||||
public float computedHeight;
|
||||
}
|
||||
}
|
@@ -16,6 +16,10 @@ namespace Facebook.CSSLayout
|
||||
|
||||
class CSSLayout
|
||||
{
|
||||
// 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.
|
||||
public const int MAX_CACHED_RESULT_COUNT = 16;
|
||||
|
||||
public const int POSITION_LEFT = 0;
|
||||
public const int POSITION_TOP = 1;
|
||||
public const int POSITION_RIGHT = 2;
|
||||
@@ -25,12 +29,25 @@ namespace Facebook.CSSLayout
|
||||
public const int DIMENSION_HEIGHT = 1;
|
||||
|
||||
public float[] position = new float[4];
|
||||
public float[] dimensions = new float[2];
|
||||
public float[] dimensions = {
|
||||
CSSConstants.Undefined,
|
||||
CSSConstants.Undefined
|
||||
};
|
||||
public CSSDirection direction = CSSDirection.LTR;
|
||||
|
||||
/**
|
||||
* This should always get called before calling {@link LayoutEngine#layoutNode(CSSNode, float)}
|
||||
*/
|
||||
public float flexBasis;
|
||||
|
||||
public int generationCount;
|
||||
public CSSDirection? lastParentDirection;
|
||||
|
||||
public int nextCachedMeasurementsIndex;
|
||||
public CSSCachedMeasurement[] cachedMeasurements = new CSSCachedMeasurement[MAX_CACHED_RESULT_COUNT];
|
||||
public float[] measuredDimensions = {
|
||||
CSSConstants.Undefined,
|
||||
CSSConstants.Undefined
|
||||
};
|
||||
|
||||
public CSSCachedMeasurement cachedLayout = new CSSCachedMeasurement();
|
||||
|
||||
public void resetResult()
|
||||
{
|
||||
@@ -38,17 +55,18 @@ namespace Facebook.CSSLayout
|
||||
FillArray(dimensions, CSSConstants.Undefined);
|
||||
|
||||
direction = CSSDirection.LTR;
|
||||
}
|
||||
|
||||
public void copy(CSSLayout layout)
|
||||
{
|
||||
position[POSITION_LEFT] = layout.position[POSITION_LEFT];
|
||||
position[POSITION_TOP] = layout.position[POSITION_TOP];
|
||||
position[POSITION_RIGHT] = layout.position[POSITION_RIGHT];
|
||||
position[POSITION_BOTTOM] = layout.position[POSITION_BOTTOM];
|
||||
dimensions[DIMENSION_WIDTH] = layout.dimensions[DIMENSION_WIDTH];
|
||||
dimensions[DIMENSION_HEIGHT] = layout.dimensions[DIMENSION_HEIGHT];
|
||||
direction = layout.direction;
|
||||
flexBasis = 0;
|
||||
|
||||
generationCount = 0;
|
||||
lastParentDirection = null;
|
||||
|
||||
nextCachedMeasurementsIndex = 0;
|
||||
measuredDimensions[DIMENSION_WIDTH] = CSSConstants.Undefined;
|
||||
measuredDimensions[DIMENSION_HEIGHT] = CSSConstants.Undefined;
|
||||
|
||||
cachedLayout.widthMeasureMode = null;
|
||||
cachedLayout.heightMeasureMode = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
@@ -22,5 +22,6 @@ namespace Facebook.CSSLayout
|
||||
{
|
||||
/*package*/
|
||||
public MeasureOutput measureOutput = new MeasureOutput();
|
||||
public int currentGenerationCount;
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* Copyright (c) 2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
|
@@ -58,8 +58,7 @@ namespace Facebook.CSSLayout
|
||||
internal readonly CachedCSSLayout lastLayout = new CachedCSSLayout();
|
||||
|
||||
internal int lineIndex = 0;
|
||||
internal /*package*/ CSSNode nextAbsoluteChild;
|
||||
internal /*package*/ CSSNode nextFlexChild;
|
||||
internal /*package*/ CSSNode nextChild;
|
||||
|
||||
// 4 is kinda arbitrary, but the default of 10 seems really high for an average View.
|
||||
readonly List<CSSNode> mChildren = new List<CSSNode>(4);
|
||||
@@ -155,7 +154,6 @@ namespace Facebook.CSSLayout
|
||||
|
||||
public void CalculateLayout()
|
||||
{
|
||||
layout.resetResult();
|
||||
LayoutEngine.layoutNode(DummyLayoutContext, this, CSSConstants.Undefined, CSSConstants.Undefined, null);
|
||||
}
|
||||
|
||||
|
17
src/csharp/Facebook.CSSLayout/CSSOverflow.cs
Normal file
17
src/csharp/Facebook.CSSLayout/CSSOverflow.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
namespace Facebook.CSSLayout
|
||||
{
|
||||
public enum CSSOverflow
|
||||
{
|
||||
Visible,
|
||||
Hidden
|
||||
}
|
||||
}
|
@@ -22,6 +22,7 @@ namespace Facebook.CSSLayout
|
||||
public CSSAlign alignSelf = CSSAlign.Auto;
|
||||
public CSSPositionType positionType = CSSPositionType.Relative;
|
||||
public CSSWrap flexWrap = CSSWrap.NoWrap;
|
||||
public CSSOverflow overflow = CSSOverflow.Visible;
|
||||
public float flex;
|
||||
|
||||
public Spacing margin = new Spacing();
|
||||
|
@@ -41,14 +41,16 @@
|
||||
<Compile Include="Assertions.cs" />
|
||||
<Compile Include="CachedCSSLayout.cs" />
|
||||
<Compile Include="CSSAlign.cs" />
|
||||
<Compile Include="CSSCachedMeasurement.cs" />
|
||||
<Compile Include="CSSConstants.cs" />
|
||||
<Compile Include="CSSDirection.cs" />
|
||||
<Compile Include="CSSFlexDirection.cs" />
|
||||
<Compile Include="CSSJustify.cs" />
|
||||
<Compile Include="CSSMeasureMode.cs" />
|
||||
<Compile Include="CSSLayout.cs" />
|
||||
<Compile Include="CSSLayoutContext.cs" />
|
||||
<Compile Include="CSSMeasureMode.cs" />
|
||||
<Compile Include="CSSNode.cs" />
|
||||
<Compile Include="CSSOverflow.cs" />
|
||||
<Compile Include="CSSPositionType.cs" />
|
||||
<Compile Include="CSSStyle.cs" />
|
||||
<Compile Include="CSSWrap.cs" />
|
||||
@@ -68,4 +70,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public class CSSCachedMeasurement {
|
||||
public float availableWidth;
|
||||
public float availableHeight;
|
||||
public CSSMeasureMode widthMeasureMode = null;
|
||||
public CSSMeasureMode heightMeasureMode = null;
|
||||
|
||||
public float computedWidth;
|
||||
public float computedHeight;
|
||||
}
|
@@ -14,6 +14,10 @@ import java.util.Arrays;
|
||||
* Where the output of {@link LayoutEngine#layoutNode(CSSNode, float)} will go in the CSSNode.
|
||||
*/
|
||||
public class CSSLayout {
|
||||
// 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.
|
||||
public static final int MAX_CACHED_RESULT_COUNT = 16;
|
||||
|
||||
public static final int POSITION_LEFT = 0;
|
||||
public static final int POSITION_TOP = 1;
|
||||
public static final int POSITION_RIGHT = 2;
|
||||
@@ -25,24 +29,38 @@ public class CSSLayout {
|
||||
public float[] position = new float[4];
|
||||
public float[] dimensions = new float[2];
|
||||
public CSSDirection direction = CSSDirection.LTR;
|
||||
|
||||
/**
|
||||
* This should always get called before calling {@link LayoutEngine#layoutNode(CSSNode, float)}
|
||||
*/
|
||||
|
||||
public float flexBasis;
|
||||
|
||||
public int generationCount;
|
||||
public CSSDirection lastParentDirection;
|
||||
|
||||
public int nextCachedMeasurementsIndex;
|
||||
public CSSCachedMeasurement[] cachedMeasurements = new CSSCachedMeasurement[MAX_CACHED_RESULT_COUNT];
|
||||
public float[] measuredDimensions = new float[2];
|
||||
|
||||
public CSSCachedMeasurement cachedLayout = new CSSCachedMeasurement();
|
||||
|
||||
CSSLayout() {
|
||||
resetResult();
|
||||
}
|
||||
|
||||
public void resetResult() {
|
||||
Arrays.fill(position, 0);
|
||||
Arrays.fill(dimensions, CSSConstants.UNDEFINED);
|
||||
direction = CSSDirection.LTR;
|
||||
}
|
||||
|
||||
public void copy(CSSLayout layout) {
|
||||
position[POSITION_LEFT] = layout.position[POSITION_LEFT];
|
||||
position[POSITION_TOP] = layout.position[POSITION_TOP];
|
||||
position[POSITION_RIGHT] = layout.position[POSITION_RIGHT];
|
||||
position[POSITION_BOTTOM] = layout.position[POSITION_BOTTOM];
|
||||
dimensions[DIMENSION_WIDTH] = layout.dimensions[DIMENSION_WIDTH];
|
||||
dimensions[DIMENSION_HEIGHT] = layout.dimensions[DIMENSION_HEIGHT];
|
||||
direction = layout.direction;
|
||||
|
||||
flexBasis = 0;
|
||||
|
||||
generationCount = 0;
|
||||
lastParentDirection = null;
|
||||
|
||||
nextCachedMeasurementsIndex = 0;
|
||||
measuredDimensions[DIMENSION_WIDTH] = CSSConstants.UNDEFINED;
|
||||
measuredDimensions[DIMENSION_HEIGHT] = CSSConstants.UNDEFINED;
|
||||
|
||||
cachedLayout.widthMeasureMode = null;
|
||||
cachedLayout.heightMeasureMode = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -17,4 +17,5 @@ package com.facebook.csslayout;
|
||||
*/
|
||||
public class CSSLayoutContext {
|
||||
/*package*/ final MeasureOutput measureOutput = new MeasureOutput();
|
||||
int currentGenerationCount;
|
||||
}
|
||||
|
@@ -63,9 +63,8 @@ public class CSSNode {
|
||||
|
||||
public int lineIndex = 0;
|
||||
|
||||
/*package*/ CSSNode nextAbsoluteChild;
|
||||
/*package*/ CSSNode nextFlexChild;
|
||||
|
||||
/*package*/ CSSNode nextChild;
|
||||
|
||||
private @Nullable ArrayList<CSSNode> mChildren;
|
||||
private @Nullable CSSNode mParent;
|
||||
private @Nullable MeasureFunction mMeasureFunction = null;
|
||||
@@ -139,7 +138,6 @@ public class CSSNode {
|
||||
* Performs the actual layout and saves the results in {@link #layout}
|
||||
*/
|
||||
public void calculateLayout(CSSLayoutContext layoutContext) {
|
||||
layout.resetResult();
|
||||
LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, null);
|
||||
}
|
||||
|
||||
|
14
src/java/src/com/facebook/csslayout/CSSOverflow.java
Normal file
14
src/java/src/com/facebook/csslayout/CSSOverflow.java
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSOverflow {
|
||||
VISIBLE,
|
||||
HIDDEN,
|
||||
}
|
@@ -23,6 +23,7 @@ public class CSSStyle {
|
||||
public CSSAlign alignSelf;
|
||||
public CSSPositionType positionType;
|
||||
public CSSWrap flexWrap;
|
||||
public CSSOverflow overflow;
|
||||
public float flex;
|
||||
|
||||
public Spacing margin = new Spacing();
|
||||
@@ -51,6 +52,7 @@ public class CSSStyle {
|
||||
alignSelf = CSSAlign.AUTO;
|
||||
positionType = CSSPositionType.RELATIVE;
|
||||
flexWrap = CSSWrap.NOWRAP;
|
||||
overflow = CSSOverflow.VISIBLE;
|
||||
flex = 0f;
|
||||
|
||||
margin.reset();;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -43,7 +43,7 @@ public class LayoutCachingTest {
|
||||
root.addChildAt(c0, 0);
|
||||
root.addChildAt(c1, 1);
|
||||
c0.addChildAt(c0c0, 0);
|
||||
|
||||
|
||||
root.calculateLayout(layoutContext);
|
||||
assertTreeHasNewLayout(true, root);
|
||||
markLayoutAppliedForTree(root);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -39,8 +39,7 @@ global.layoutTestUtils = {
|
||||
};
|
||||
|
||||
global.describe = function(name, cb) {
|
||||
if (name === 'Layout' ||
|
||||
name === 'Layout alignContent') {
|
||||
if (name.toLowerCase().indexOf('javascript only') === -1) {
|
||||
cb();
|
||||
}
|
||||
};
|
||||
@@ -175,6 +174,10 @@ function printLayout(test) {
|
||||
'exactly': 'CSS_MEASURE_MODE_EXACTLY',
|
||||
'at-most': 'CSS_MEASURE_MODE_AT_MOST'
|
||||
});
|
||||
addEnum(node, 'overflow', 'overflow', {
|
||||
'visible': 'CSS_OVERFLOW_VISIBLE',
|
||||
'hidden': 'CSS_OVERFLOW_HIDDEN'
|
||||
});
|
||||
addFloat(node, 'flex', 'flex');
|
||||
addFloat(node, 'width', 'dimensions[CSS_WIDTH]');
|
||||
addFloat(node, 'height', 'dimensions[CSS_HEIGHT]');
|
||||
@@ -256,8 +259,13 @@ function printLayout(test) {
|
||||
|
||||
function transpileAnnotatedJStoC(jsCode) {
|
||||
return jsCode
|
||||
.replace(/'abs-layout'/g, '"abs-layout"')
|
||||
.replace(/'abs-measure'/g, '"abs-measure"')
|
||||
.replace(/'flex'/g, '"flex"')
|
||||
.replace(/'measure'/g, '"measure"')
|
||||
.replace(/'stretch'/g, '"stretch"')
|
||||
.replace('node.style.measure', 'node.measure')
|
||||
.replace(/null/g, 'NULL')
|
||||
.replace(/undefined/g, 'NULL')
|
||||
.replace(/\.children\.length/g, '.children_count')
|
||||
.replace(/\.width/g, '.dimensions[CSS_WIDTH]')
|
||||
.replace(/\.height/g, '.dimensions[CSS_HEIGHT]')
|
||||
@@ -266,23 +274,30 @@ function transpileAnnotatedJStoC(jsCode) {
|
||||
.replace(/\.minWidth/g, '.minDimensions[CSS_WIDTH]')
|
||||
.replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]')
|
||||
.replace(/\.lineIndex/g, '.line_index')
|
||||
.replace(/\.nextAbsoluteChild/g, '.next_absolute_child')
|
||||
.replace(/\.nextFlexChild/g, '.next_flex_child')
|
||||
.replace(/layout\[dim/g, 'layout.dimensions[dim')
|
||||
.replace(/\.nextChild/g, '.next_child')
|
||||
.replace(/\.flexBasis/g, '.flex_basis')
|
||||
.replace(/layout\[pos/g, 'layout.position[pos')
|
||||
.replace(/layout\[leading/g, 'layout.position[leading')
|
||||
.replace(/layout\[trailing/g, 'layout.position[trailing')
|
||||
.replace(/layout\[measuredDim/g, 'layout.measured_dimensions[dim')
|
||||
.replace(/layout\.measuredWidth/g, 'layout.measured_dimensions[CSS_WIDTH]')
|
||||
.replace(/layout\.measuredHeight/g, 'layout.measured_dimensions[CSS_HEIGHT]')
|
||||
.replace(/style\[dim/g, 'style.dimensions[dim')
|
||||
.replace(/style\[CSS_LEFT/g, 'style.position[CSS_LEFT')
|
||||
.replace(/style\[CSS_TOP/g, 'style.position[CSS_TOP')
|
||||
.replace(/style\[CSS_RIGHT/g, 'style.position[CSS_RIGHT')
|
||||
.replace(/style\[CSS_BOTTOM/g, 'style.position[CSS_BOTTOM')
|
||||
.replace(/node.children\[i\]/g, 'node->get_child(node->context, i)')
|
||||
.replace(/node.children\[ii\]/g, 'node->get_child(node->context, ii)')
|
||||
.replace(/node.children\[j\]/g, 'node->get_child(node->context, j)')
|
||||
.replace(/node\./g, 'node->')
|
||||
.replace(/child\./g, 'child->')
|
||||
.replace(/parent\./g, 'parent->')
|
||||
.replace(/currentAbsoluteChild\./g, 'currentAbsoluteChild->')
|
||||
.replace(/currentFlexChild\./g, 'currentFlexChild->')
|
||||
.replace(/currentRelativeChild\./g, 'currentRelativeChild->')
|
||||
.replace(/getPositionType\((.+?)\)/g, '$1->style.position_type')
|
||||
.replace(/getJustifyContent\((.+?)\)/g, '$1->style.justify_content')
|
||||
.replace(/getAlignContent\((.+?)\)/g, '$1->style.align_content')
|
||||
.replace(/assert\((.+?),\s*'(.+?)'\);/g, 'assert($1); // $2')
|
||||
.replace(/getOverflow\((.+?)\)/g, '$1->style.overflow')
|
||||
.replace(/var\/\*\(c\)!([^*]+)\*\//g, '$1')
|
||||
.replace(/var\/\*([^\/]+)\*\//g, '$1')
|
||||
.replace(/ === /g, ' == ')
|
||||
@@ -290,8 +305,7 @@ function transpileAnnotatedJStoC(jsCode) {
|
||||
.replace(/\n {2}/g, '\n')
|
||||
.replace(/\/\*\(c\)!([^*]+)\*\//g, '$1')
|
||||
.replace(/\/[*]!([^*]+)[*]\//g, '$1')
|
||||
.replace(/\/\*\(java\)!([^*]+)\*\//g, '')
|
||||
.split('\n').slice(1, -1).join('\n');
|
||||
.replace(/\/\*\(java\)!([^*]+)\*\//g, '');
|
||||
}
|
||||
|
||||
function makeConstDefs() {
|
||||
@@ -318,14 +332,18 @@ function generateFile(fileName, generatedContent) {
|
||||
fs.writeFileSync(fileName, content);
|
||||
}
|
||||
|
||||
// Extract the function body by trimming the first ('function layoutNode(...) {') and
|
||||
// last ('}') lines. Also, start the function body with a blank line so that regexes
|
||||
// that use \n to match the start of a line will match the actual first line.
|
||||
var computeLayoutCode = [''].concat(computeLayout.toString().split('\n').slice(1, -1)).join('\n');
|
||||
|
||||
var allTestsInC = allTests.map(printLayout);
|
||||
generateFile(__dirname + '/__tests__/Layout-test.c', allTestsInC.join('\n\n'));
|
||||
generateFile(__dirname + '/Layout-test-utils.c', makeConstDefs());
|
||||
generateFile(__dirname + '/Layout.c', transpileAnnotatedJStoC(computeLayout.toString()));
|
||||
generateFile(__dirname + '/java/src/com/facebook/csslayout/LayoutEngine.java', JavaTranspiler.transpileLayoutEngine(computeLayout.toString()));
|
||||
generateFile(__dirname + '/Layout.c', transpileAnnotatedJStoC(computeLayoutCode));
|
||||
generateFile(__dirname + '/java/src/com/facebook/csslayout/LayoutEngine.java', JavaTranspiler.transpileLayoutEngine(computeLayoutCode));
|
||||
generateFile(__dirname + '/java/tests/com/facebook/csslayout/TestConstants.java', JavaTranspiler.transpileCConstDefs(makeConstDefs()));
|
||||
generateFile(__dirname + '/java/tests/com/facebook/csslayout/LayoutEngineTest.java', JavaTranspiler.transpileCTestsArray(allTestsInC));
|
||||
generateFile(__dirname + '/csharp/Facebook.CSSLayout/LayoutEngine.cs', CSharpTranspiler.transpileLayoutEngine(computeLayout.toString()));
|
||||
generateFile(__dirname + '/csharp/Facebook.CSSLayout/LayoutEngine.cs', CSharpTranspiler.transpileLayoutEngine(computeLayoutCode));
|
||||
generateFile(__dirname + '/csharp/Facebook.CSSLayout.Tests/TestConstants.cs', CSharpTranspiler.transpileCConstDefs(makeConstDefs()));
|
||||
generateFile(__dirname + '/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs', CSharpTranspiler.transpileCTestsArray(allTestsInC));
|
||||
|
Reference in New Issue
Block a user