Alter layout engine to conform closer to W3C spec

The primary goals of this change are:
  - Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
    and a clear articulation of the areas where it deviates from the spec.
  - Support for flex-shrink.
  - Conformance with layout effects of "overflow: hidden".

Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
  - Display property is always assumed to be 'flex' except for Text nodes, which
    are assumed to be 'inline-flex'.
  - The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
    stacked in document order.
  - The 'order' property is not supported. The order of flex items is always defined
    by document order.
  - The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
    and 'hidden' are not supported.
  - The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
    rarely-used 'wrap-reverse' is not supported.
  - Rather than allowing arbitrary combinations of flexGrow, flexShrink and
    flexBasis, this algorithm supports only the three most common combinations:
      - flex: 0 is equiavlent to flex: 0 0 auto
      - flex: n (where n is a positive value) is equivalent to flex: n 0 0
      - flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
  - Margins cannot be specified as 'auto'. They must be specified in terms of pixel
    values, and the default value is 0.
  - The 'baseline' value is not supported for alignItems and alignSelf properties.
  - Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
    specified as pixel values, not as percentages.
  - There is no support for calculation of dimensions based on intrinsic aspect ratios
    (e.g. images).
  - There is no support for forced breaks.
  - It does not support vertical inline directions (top-to-bottom or bottom-to-top text).

And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
  - Section 4.5 of the spec indicates that all flex items have a default minimum
    main size. For text blocks, for example, this is the width of the widest word.
    Calculating the minimum width is expensive, so we forego it and assume a default
    minimum main size of 0.
  - Min/Max sizes in the main axis are not honored when resolving flexible lengths.
  - The spec indicates that the default value for 'flexDirection' is 'row', but
    the algorithm below assumes a default of 'column'.
This commit is contained in:
Adam Comella
2016-04-26 16:35:46 -07:00
parent b0d00ad338
commit f3dd51ab97
36 changed files with 9789 additions and 4157 deletions

View File

@@ -92,9 +92,18 @@ borderWidth, borderLeftWidth, borderRightWidth, borderTopWidth, borderBottomWidt
flexDirection | 'column', 'row' flexDirection | 'column', 'row'
justifyContent | 'flex-start', 'center', 'flex-end', 'space-between', 'space-around' justifyContent | 'flex-start', 'center', 'flex-end', 'space-between', 'space-around'
alignItems, alignSelf | 'flex-start', 'center', 'flex-end', 'stretch' alignItems, alignSelf | 'flex-start', 'center', 'flex-end', 'stretch'
flex | positive number flex | number
flexWrap | 'wrap', 'nowrap' flexWrap | 'wrap', 'nowrap'
position | 'relative', 'absolute' 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. - `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; border: 0 solid black;
margin: 0; margin: 0;
padding: 0; padding: 0;
min-width: 0;
} }
``` ```

View File

@@ -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>

1786
dist/css-layout.h vendored

File diff suppressed because it is too large Load Diff

BIN
dist/css-layout.jar vendored

Binary file not shown.

1603
dist/css-layout.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -9,11 +9,18 @@
function __transpileToCSharpCommon(code) { function __transpileToCSharpCommon(code) {
return 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_UNDEFINED/g, 'CSSConstants.UNDEFINED')
.replace(/CSS_JUSTIFY_/g, 'CSSJustify.') .replace(/CSS_JUSTIFY_/g, 'CSSJustify.')
.replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.') .replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.')
.replace(/CSS_ALIGN_/g, 'CSSAlign.') .replace(/CSS_ALIGN_/g, 'CSSAlign.')
.replace(/CSS_POSITION_/g, 'CSSPositionType.') .replace(/CSS_POSITION_/g, 'CSSPositionType.')
.replace(/CSS_OVERFLOW_/g, 'CSSOverflow.')
.replace(/css_flex_direction_t/g, 'CSSFlexDirection') .replace(/css_flex_direction_t/g, 'CSSFlexDirection')
.replace(/css_direction_t/g, 'CSSDirection') .replace(/css_direction_t/g, 'CSSDirection')
.replace(/css_align_t/g, 'CSSAlign') .replace(/css_align_t/g, 'CSSAlign')
@@ -21,6 +28,10 @@ function __transpileToCSharpCommon(code) {
.replace(/css_measure_mode_t/g, 'CSSMeasureMode') .replace(/css_measure_mode_t/g, 'CSSMeasureMode')
.replace(/css_dim_t/g, 'MeasureOutput') .replace(/css_dim_t/g, 'MeasureOutput')
.replace(/bool/g, 'boolean') .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\[dim/g, 'style.dimensions[dim')
.replace(/(style|layout)\.width/g, '$1.dimensions[DIMENSION_WIDTH]') .replace(/(style|layout)\.width/g, '$1.dimensions[DIMENSION_WIDTH]')
.replace(/(style|layout)\.height/g, '$1.dimensions[DIMENSION_HEIGHT]') .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\[pos/g, 'layout.position[pos')
.replace(/layout\[leading/g, 'layout.position[leading') .replace(/layout\[leading/g, 'layout.position[leading')
.replace(/layout\[trailing/g, 'layout.position[trailing') .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(/getPositionType\((.+?)\)/g, '$1.style.positionType')
.replace(/getJustifyContent\((.+?)\)/g, '$1.style.justifyContent') .replace(/getJustifyContent\((.+?)\)/g, '$1.style.justifyContent')
.replace(/getAlignContent\((.+?)\)/g, '$1.style.alignContent') .replace(/getAlignContent\((.+?)\)/g, '$1.style.alignContent')
.replace(/isPosDefined\((.+?),\s*(.+?)\)/g, '!isUndefined\($1.style.position[$2]\)') .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(/isStyleDimDefined\((.+?),\s*(.+?)\)/g, '($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(/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(/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(/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(/isFlex\((.+?)\)/g, '\($1.style.positionType == CSSPositionType.RELATIVE && $1.style.flex != 0\)')
.replace(/isFlexWrap\((.+?)\)/g, '\($1.style.flexWrap == CSSWrap.WRAP\)') .replace(/isFlexWrap\((.+?)\)/g, '\($1.style.flexWrap == CSSWrap.WRAP\)')
.replace(/getPaddingAndBorderAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingPaddingAndBorder($1, $2) + getTrailingPaddingAndBorder($1, $2)\)') .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(/getMarginAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
.replace(/getLeadingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getLeadingPadding($1, $2) + getLeadingBorder($1, $2)\)') .replace(/getLeadingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getLeadingPadding($1, $2) + getLeadingBorder($1, $2)\)')
.replace(/getTrailingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getTrailingPadding($1, $2) + getTrailingBorder($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(/getLeadingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(leadingSpacing[$2], leading[$2])')
.replace(/getTrailingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(trailingSpacing[$2], trailing[$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])') .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(/getLeadingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(leadingSpacing[$2], leading[$2])')
.replace(/getTrailingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(trailingSpacing[$2], trailing[$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(/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(/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(/\/\*\(c\)!([^*]+)\*\//g, '')
.replace(/var\/\*\(java\)!([^*]+)\*\//g, '$1') .replace(/var\/\*\(java\)!([^*]+)\*\//g, '$1')
.replace(/\/\*\(java\)!([^*]+)\*\//g, '$1') .replace(/\/\*\(java\)!([^*]+)\*\//g, '$1')
// additional case conversions // 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) { function(str, match1, match2) {
return match1 + '.' + constantToPascalCase(match2); return match1 + '.' + constantToPascalCase(match2);
}); });
@@ -139,12 +156,12 @@ var CSharpTranspiler = {
transpileLayoutEngine: function(code) { transpileLayoutEngine: function(code) {
return indent( return indent(
__transpileToCSharpCommon(code) __transpileToCSharpCommon(code)
.replace(/function\s+layoutNode.*/, '')
.replace('node.style.measure', 'node.measure') .replace('node.style.measure', 'node.measure')
.replace(/\.children\.length/g, '.getChildCount()') .replace(/\.children\.length/g, '.getChildCount()')
.replace(/node.children\[i\]/g, 'node.getChildAt(i)') .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(/fmaxf/g, 'Math.Max')
.replace(/fminf/g, 'Math.Min')
.replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages .replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages
.replace(/var\/\*([^\/]+)\*\//g, '$1') .replace(/var\/\*([^\/]+)\*\//g, '$1')
.replace(/ === /g, ' == ') .replace(/ === /g, ' == ')

View File

@@ -9,11 +9,18 @@
function __transpileToJavaCommon(code) { function __transpileToJavaCommon(code) {
return 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_UNDEFINED/g, 'CSSConstants.UNDEFINED')
.replace(/CSS_JUSTIFY_/g, 'CSSJustify.') .replace(/CSS_JUSTIFY_/g, 'CSSJustify.')
.replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.') .replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.')
.replace(/CSS_ALIGN_/g, 'CSSAlign.') .replace(/CSS_ALIGN_/g, 'CSSAlign.')
.replace(/CSS_POSITION_/g, 'CSSPositionType.') .replace(/CSS_POSITION_/g, 'CSSPositionType.')
.replace(/CSS_OVERFLOW_/g, 'CSSOverflow.')
.replace(/css_flex_direction_t/g, 'CSSFlexDirection') .replace(/css_flex_direction_t/g, 'CSSFlexDirection')
.replace(/css_direction_t/g, 'CSSDirection') .replace(/css_direction_t/g, 'CSSDirection')
.replace(/css_align_t/g, 'CSSAlign') .replace(/css_align_t/g, 'CSSAlign')
@@ -21,6 +28,10 @@ function __transpileToJavaCommon(code) {
.replace(/css_measure_mode_t/g, 'CSSMeasureMode') .replace(/css_measure_mode_t/g, 'CSSMeasureMode')
.replace(/css_dim_t/g, 'MeasureOutput') .replace(/css_dim_t/g, 'MeasureOutput')
.replace(/bool/g, 'boolean') .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\[dim/g, 'style.dimensions[dim')
.replace(/(style|layout)\.width/g, '$1.dimensions[DIMENSION_WIDTH]') .replace(/(style|layout)\.width/g, '$1.dimensions[DIMENSION_WIDTH]')
.replace(/(style|layout)\.height/g, '$1.dimensions[DIMENSION_HEIGHT]') .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\[pos/g, 'layout.position[pos')
.replace(/layout\[leading/g, 'layout.position[leading') .replace(/layout\[leading/g, 'layout.position[leading')
.replace(/layout\[trailing/g, 'layout.position[trailing') .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(/getPositionType\((.+?)\)/g, '$1.style.positionType')
.replace(/getJustifyContent\((.+?)\)/g, '$1.style.justifyContent') .replace(/getJustifyContent\((.+?)\)/g, '$1.style.justifyContent')
.replace(/getAlignContent\((.+?)\)/g, '$1.style.alignContent') .replace(/getAlignContent\((.+?)\)/g, '$1.style.alignContent')
.replace(/isPosDefined\((.+?),\s*(.+?)\)/g, '!isUndefined\($1.style.position[$2]\)') .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(/isStyleDimDefined\((.+?),\s*(.+?)\)/g, '($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(/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(/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(/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(/isFlex\((.+?)\)/g, '\($1.style.positionType == CSSPositionType.RELATIVE && $1.style.flex != 0\)')
.replace(/isFlexWrap\((.+?)\)/g, '\($1.style.flexWrap == CSSWrap.WRAP\)') .replace(/isFlexWrap\((.+?)\)/g, '\($1.style.flexWrap == CSSWrap.WRAP\)')
.replace(/getPaddingAndBorderAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingPaddingAndBorder($1, $2) + getTrailingPaddingAndBorder($1, $2)\)') .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(/getMarginAxis\((.+?),\s*(.+?)\)/g, '\(getLeadingMargin($1, $2) + getTrailingMargin($1, $2)\)')
.replace(/getLeadingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getLeadingPadding($1, $2) + getLeadingBorder($1, $2)\)') .replace(/getLeadingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getLeadingPadding($1, $2) + getLeadingBorder($1, $2)\)')
.replace(/getTrailingPaddingAndBorder\((.+?),\s*(.+?)\)/g, '\(getTrailingPadding($1, $2) + getTrailingBorder($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(/getLeadingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(leadingSpacing[$2], leading[$2])')
.replace(/getTrailingMargin\((.+?),\s*(.+?)\)/g, '$1.style.margin.getWithFallback(trailingSpacing[$2], trailing[$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])') .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(/getLeadingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(leadingSpacing[$2], leading[$2])')
.replace(/getTrailingBorder\((.+?),\s*(.+?)\)/g, '$1.style.border.getWithFallback(trailingSpacing[$2], trailing[$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(/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(/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(/\/\*\(c\)!([^*]+)\*\//g, '')
.replace(/var\/\*\(java\)!([^*]+)\*\//g, '$1') .replace(/var\/\*\(java\)!([^*]+)\*\//g, '$1')
.replace(/\/\*\(java\)!([^*]+)\*\//g, '$1'); .replace(/\/\*\(java\)!([^*]+)\*\//g, '$1');
@@ -118,12 +135,12 @@ var JavaTranspiler = {
transpileLayoutEngine: function(code) { transpileLayoutEngine: function(code) {
return indent( return indent(
__transpileToJavaCommon(code) __transpileToJavaCommon(code)
.replace(/function\s+layoutNode.*/, '')
.replace('node.style.measure', 'node.measure') .replace('node.style.measure', 'node.measure')
.replace(/\.children\.length/g, '.getChildCount()') .replace(/\.children\.length/g, '.getChildCount()')
.replace(/node.children\[i\]/g, 'node.getChildAt(i)') .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(/fmaxf/g, 'Math.max')
.replace(/fminf/g, 'Math.min')
.replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages .replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages
.replace(/var\/\*([^\/]+)\*\//g, '$1') .replace(/var\/\*([^\/]+)\*\//g, '$1')
.replace(/ === /g, ' == ') .replace(/ === /g, ' == ')

View File

@@ -92,6 +92,7 @@ var layoutTestUtils = (function() {
margin: 0; margin: 0;
padding: 0; padding: 0;
min-width: 0;
} }
hack to ignore three hundred px width of the body {} hack to ignore three hundred px width of the body {}
@@ -118,17 +119,24 @@ var layoutTestUtils = (function() {
} }
function extractNodes(node) { function extractNodes(node) {
var layout = node.layout; var keysToCopy = [
delete node.layout; 'width',
'height',
'left',
'top'
];
var layout = {};
keysToCopy.forEach(function(key) {
layout[key] = node.layout[key];
});
if (node.children && node.children.length > 0) { if (node.children && node.children.length > 0) {
layout.children = node.children.map(extractNodes); layout.children = node.children.map(extractNodes);
} else { } else {
delete node.children; delete node.children;
} }
delete layout.right; delete node.layout;
delete layout.bottom;
delete layout.direction;
return layout; return layout;
} }
@@ -184,12 +192,16 @@ var layoutTestUtils = (function() {
function computeDOMLayout(node) { function computeDOMLayout(node) {
var body = getIframe().contentDocument.body; 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) { function transfer(div, node, name, ext) {
if (name in node.style) { if (name in node.style) {
var value = node.style[name] + (ext || ''); var value = node.style[name] + (ext || '');
div.style['-webkit-' + name] = value; setStyle(div, name, value);
div.style['webkit' + capitalizeFirst(name)] = value;
div.style[name] = value;
} }
} }
@@ -203,6 +215,18 @@ var layoutTestUtils = (function() {
transfer(div, node, type + 'End' + 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) { function renderNode(parent, node) {
var div = document.createElement('div'); var div = document.createElement('div');
transfer(div, node, 'width', 'px'); transfer(div, node, 'width', 'px');
@@ -220,13 +244,14 @@ var layoutTestUtils = (function() {
transferSpacing(div, node, 'border', 'Width'); transferSpacing(div, node, 'border', 'Width');
transfer(div, node, 'flexDirection'); transfer(div, node, 'flexDirection');
transfer(div, node, 'direction'); transfer(div, node, 'direction');
transfer(div, node, 'flex'); transferFlex(div, node);
transfer(div, node, 'flexWrap'); transfer(div, node, 'flexWrap');
transfer(div, node, 'justifyContent'); transfer(div, node, 'justifyContent');
transfer(div, node, 'alignSelf'); transfer(div, node, 'alignSelf');
transfer(div, node, 'alignItems'); transfer(div, node, 'alignItems');
transfer(div, node, 'alignContent'); transfer(div, node, 'alignContent');
transfer(div, node, 'position'); transfer(div, node, 'position');
transfer(div, node, 'overflow');
parent.appendChild(div); parent.appendChild(div);
(node.children || []).forEach(function(child) { (node.children || []).forEach(function(child) {
renderNode(div, child); renderNode(div, child);

File diff suppressed because it is too large Load Diff

View File

@@ -44,6 +44,11 @@ typedef enum {
CSS_JUSTIFY_SPACE_AROUND CSS_JUSTIFY_SPACE_AROUND
} css_justify_t; } 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 // Note: auto is only a valid value for alignSelf. It is NOT a valid value for
// alignItems. // alignItems.
typedef enum { typedef enum {
@@ -79,7 +84,8 @@ typedef enum {
typedef enum { typedef enum {
CSS_MEASURE_MODE_UNDEFINED = 0, CSS_MEASURE_MODE_UNDEFINED = 0,
CSS_MEASURE_MODE_EXACTLY, CSS_MEASURE_MODE_EXACTLY,
CSS_MEASURE_MODE_AT_MOST CSS_MEASURE_MODE_AT_MOST,
CSS_MEASURE_MODE_COUNT
} css_measure_mode_t; } css_measure_mode_t;
typedef enum { typedef enum {
@@ -87,20 +93,40 @@ typedef enum {
CSS_HEIGHT CSS_HEIGHT
} css_dimension_t; } 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 { typedef struct {
float position[4]; float position[4];
float dimensions[2]; float dimensions[2];
css_direction_t direction; css_direction_t direction;
float flex_basis;
// Instead of recomputing the entire layout every single time, we // Instead of recomputing the entire layout every single time, we
// cache some information to break early when nothing changed // cache some information to break early when nothing changed
bool should_update; bool should_update;
float last_requested_dimensions[2]; int generation_count;
float last_parent_max_width; css_direction_t last_parent_direction;
float last_parent_max_height;
float last_dimensions[2]; int next_cached_measurements_index;
float last_position[2]; css_cached_measurement_t cached_measurements[CSS_MAX_CACHED_RESULT_COUNT];
css_direction_t last_direction; float measured_dimensions[2];
css_cached_measurement_t cached_layout;
} css_layout_t; } css_layout_t;
typedef struct { typedef struct {
@@ -116,6 +142,7 @@ typedef struct {
css_align_t align_self; css_align_t align_self;
css_position_type_t position_type; css_position_type_t position_type;
css_wrap_type_t flex_wrap; css_wrap_type_t flex_wrap;
css_overflow_t overflow;
float flex; float flex;
float margin[6]; float margin[6];
float position[4]; float position[4];
@@ -143,8 +170,7 @@ struct css_node {
int children_count; int children_count;
int line_index; int line_index;
css_node_t *next_absolute_child; css_node_t* next_child;
css_node_t *next_flex_child;
css_dim_t (*measure)(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode); css_dim_t (*measure)(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode);
void (*print)(void *context); void (*print)(void *context);
@@ -166,12 +192,8 @@ typedef enum {
} css_print_options_t; } css_print_options_t;
void print_css_node(css_node_t *node, css_print_options_t options); 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); 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 #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1238,7 +1238,7 @@ describe('Layout', function() {
testLayoutAgainstExpectedOnly( testLayoutAgainstExpectedOnly(
{style: {width: 320, flexDirection: 'column'}, children: [ {style: {width: 320, flexDirection: 'column'}, children: [
{style: {measure: measureWithRatio2}}, {style: {measure: measureWithRatio2}},
{style: {height: 100, flexDirection: 'row'}, children: [ {style: {height: 100, flexDirection: 'row', overflow: 'hidden'}, children: [
{style: {measure: measureWithRatio2}}, {style: {measure: measureWithRatio2}},
{style: {measure: measureWithRatio2}} {style: {measure: measureWithRatio2}}
]}, ]},
@@ -1354,14 +1354,16 @@ describe('Layout', function() {
}); });
it('should layout node with text bounded by grand-parent', function() { it('should layout node with text bounded by grand-parent', function() {
testLayout( testLayoutAgainstExpectedOnly(
{style: {width: 100, padding: 10, alignSelf: 'flex-start'}, children: [ {style: {width: 100, padding: 10, alignSelf: 'flex-start'}, children: [
{style: {margin: 10, alignSelf: 'flex-start'}, children: [ {style: {margin: 10, alignSelf: 'flex-start'}, children: [
{style: {measure: text(texts.big)}} {style: {measure: text(texts.big)}}
]} ]}
]}, ]},
{width: 100, height: 40 + textSizes.bigHeight, top: 0, left: 0, children: [ {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} {width: textSizes.bigMinWidth, height: textSizes.bigHeight, top: 0, left: 0}
]} ]}
]} ]}
@@ -2485,6 +2487,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() { describe('Layout alignContent', function() {
it('should layout with alignContent: stretch, and alignItems: flex-start', function() { it('should layout with alignContent: stretch, and alignItems: flex-start', function() {

File diff suppressed because it is too large Load Diff

View File

@@ -18,5 +18,10 @@ namespace Facebook.CSSLayout
Debug.Assert(v != null); Debug.Assert(v != null);
return v; return v;
} }
public static void assertCondition(bool condition, string explanation)
{
Debug.Assert(condition, explanation);
}
} }
} }

View 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;
}
}

View File

@@ -16,6 +16,10 @@ namespace Facebook.CSSLayout
class 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_LEFT = 0;
public const int POSITION_TOP = 1; public const int POSITION_TOP = 1;
public const int POSITION_RIGHT = 2; public const int POSITION_RIGHT = 2;
@@ -25,12 +29,25 @@ namespace Facebook.CSSLayout
public const int DIMENSION_HEIGHT = 1; public const int DIMENSION_HEIGHT = 1;
public float[] position = new float[4]; public float[] position = new float[4];
public float[] dimensions = new float[2]; public float[] dimensions = {
CSSConstants.Undefined,
CSSConstants.Undefined
};
public CSSDirection direction = CSSDirection.LTR; public CSSDirection direction = CSSDirection.LTR;
/** public float flexBasis;
* This should always get called before calling {@link LayoutEngine#layoutNode(CSSNode, float)}
*/ 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() public void resetResult()
{ {
@@ -38,17 +55,18 @@ namespace Facebook.CSSLayout
FillArray(dimensions, CSSConstants.Undefined); FillArray(dimensions, CSSConstants.Undefined);
direction = CSSDirection.LTR; direction = CSSDirection.LTR;
}
public void copy(CSSLayout layout) flexBasis = 0;
{
position[POSITION_LEFT] = layout.position[POSITION_LEFT]; generationCount = 0;
position[POSITION_TOP] = layout.position[POSITION_TOP]; lastParentDirection = null;
position[POSITION_RIGHT] = layout.position[POSITION_RIGHT];
position[POSITION_BOTTOM] = layout.position[POSITION_BOTTOM]; nextCachedMeasurementsIndex = 0;
dimensions[DIMENSION_WIDTH] = layout.dimensions[DIMENSION_WIDTH]; measuredDimensions[DIMENSION_WIDTH] = CSSConstants.Undefined;
dimensions[DIMENSION_HEIGHT] = layout.dimensions[DIMENSION_HEIGHT]; measuredDimensions[DIMENSION_HEIGHT] = CSSConstants.Undefined;
direction = layout.direction;
cachedLayout.widthMeasureMode = null;
cachedLayout.heightMeasureMode = null;
} }
public override string ToString() public override string ToString()

View File

@@ -22,5 +22,6 @@ namespace Facebook.CSSLayout
{ {
/*package*/ /*package*/
public MeasureOutput measureOutput = new MeasureOutput(); public MeasureOutput measureOutput = new MeasureOutput();
public int currentGenerationCount;
} }
} }

View File

@@ -1,4 +1,4 @@
/** /**
* Copyright (c) 2014, Facebook, Inc. * Copyright (c) 2014, Facebook, Inc.
* All rights reserved. * All rights reserved.
* *

View File

@@ -58,8 +58,7 @@ namespace Facebook.CSSLayout
internal readonly CachedCSSLayout lastLayout = new CachedCSSLayout(); internal readonly CachedCSSLayout lastLayout = new CachedCSSLayout();
internal int lineIndex = 0; internal int lineIndex = 0;
internal /*package*/ CSSNode nextAbsoluteChild; internal /*package*/ CSSNode nextChild;
internal /*package*/ CSSNode nextFlexChild;
// 4 is kinda arbitrary, but the default of 10 seems really high for an average View. // 4 is kinda arbitrary, but the default of 10 seems really high for an average View.
readonly List<CSSNode> mChildren = new List<CSSNode>(4); readonly List<CSSNode> mChildren = new List<CSSNode>(4);
@@ -155,7 +154,6 @@ namespace Facebook.CSSLayout
public void CalculateLayout() public void CalculateLayout()
{ {
layout.resetResult();
LayoutEngine.layoutNode(DummyLayoutContext, this, CSSConstants.Undefined, CSSConstants.Undefined, null); LayoutEngine.layoutNode(DummyLayoutContext, this, CSSConstants.Undefined, CSSConstants.Undefined, null);
} }

View 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
}
}

View File

@@ -22,6 +22,7 @@ namespace Facebook.CSSLayout
public CSSAlign alignSelf = CSSAlign.Auto; public CSSAlign alignSelf = CSSAlign.Auto;
public CSSPositionType positionType = CSSPositionType.Relative; public CSSPositionType positionType = CSSPositionType.Relative;
public CSSWrap flexWrap = CSSWrap.NoWrap; public CSSWrap flexWrap = CSSWrap.NoWrap;
public CSSOverflow overflow = CSSOverflow.Visible;
public float flex; public float flex;
public Spacing margin = new Spacing(); public Spacing margin = new Spacing();

View File

@@ -41,14 +41,16 @@
<Compile Include="Assertions.cs" /> <Compile Include="Assertions.cs" />
<Compile Include="CachedCSSLayout.cs" /> <Compile Include="CachedCSSLayout.cs" />
<Compile Include="CSSAlign.cs" /> <Compile Include="CSSAlign.cs" />
<Compile Include="CSSCachedMeasurement.cs" />
<Compile Include="CSSConstants.cs" /> <Compile Include="CSSConstants.cs" />
<Compile Include="CSSDirection.cs" /> <Compile Include="CSSDirection.cs" />
<Compile Include="CSSFlexDirection.cs" /> <Compile Include="CSSFlexDirection.cs" />
<Compile Include="CSSJustify.cs" /> <Compile Include="CSSJustify.cs" />
<Compile Include="CSSMeasureMode.cs" />
<Compile Include="CSSLayout.cs" /> <Compile Include="CSSLayout.cs" />
<Compile Include="CSSLayoutContext.cs" /> <Compile Include="CSSLayoutContext.cs" />
<Compile Include="CSSMeasureMode.cs" />
<Compile Include="CSSNode.cs" /> <Compile Include="CSSNode.cs" />
<Compile Include="CSSOverflow.cs" />
<Compile Include="CSSPositionType.cs" /> <Compile Include="CSSPositionType.cs" />
<Compile Include="CSSStyle.cs" /> <Compile Include="CSSStyle.cs" />
<Compile Include="CSSWrap.cs" /> <Compile Include="CSSWrap.cs" />

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -14,6 +14,10 @@ import java.util.Arrays;
* Where the output of {@link LayoutEngine#layoutNode(CSSNode, float)} will go in the CSSNode. * Where the output of {@link LayoutEngine#layoutNode(CSSNode, float)} will go in the CSSNode.
*/ */
public class CSSLayout { 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_LEFT = 0;
public static final int POSITION_TOP = 1; public static final int POSITION_TOP = 1;
public static final int POSITION_RIGHT = 2; public static final int POSITION_RIGHT = 2;
@@ -26,23 +30,37 @@ public class CSSLayout {
public float[] dimensions = new float[2]; public float[] dimensions = new float[2];
public CSSDirection direction = CSSDirection.LTR; public CSSDirection direction = CSSDirection.LTR;
/** public float flexBasis;
* This should always get called before calling {@link LayoutEngine#layoutNode(CSSNode, float)}
*/ 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() { public void resetResult() {
Arrays.fill(position, 0); Arrays.fill(position, 0);
Arrays.fill(dimensions, CSSConstants.UNDEFINED); Arrays.fill(dimensions, CSSConstants.UNDEFINED);
direction = CSSDirection.LTR; direction = CSSDirection.LTR;
}
public void copy(CSSLayout layout) { flexBasis = 0;
position[POSITION_LEFT] = layout.position[POSITION_LEFT];
position[POSITION_TOP] = layout.position[POSITION_TOP]; generationCount = 0;
position[POSITION_RIGHT] = layout.position[POSITION_RIGHT]; lastParentDirection = null;
position[POSITION_BOTTOM] = layout.position[POSITION_BOTTOM];
dimensions[DIMENSION_WIDTH] = layout.dimensions[DIMENSION_WIDTH]; nextCachedMeasurementsIndex = 0;
dimensions[DIMENSION_HEIGHT] = layout.dimensions[DIMENSION_HEIGHT]; measuredDimensions[DIMENSION_WIDTH] = CSSConstants.UNDEFINED;
direction = layout.direction; measuredDimensions[DIMENSION_HEIGHT] = CSSConstants.UNDEFINED;
cachedLayout.widthMeasureMode = null;
cachedLayout.heightMeasureMode = null;
} }
@Override @Override

View File

@@ -17,4 +17,5 @@ package com.facebook.csslayout;
*/ */
public class CSSLayoutContext { public class CSSLayoutContext {
/*package*/ final MeasureOutput measureOutput = new MeasureOutput(); /*package*/ final MeasureOutput measureOutput = new MeasureOutput();
int currentGenerationCount;
} }

View File

@@ -63,8 +63,7 @@ public class CSSNode {
public int lineIndex = 0; public int lineIndex = 0;
/*package*/ CSSNode nextAbsoluteChild; /*package*/ CSSNode nextChild;
/*package*/ CSSNode nextFlexChild;
private @Nullable ArrayList<CSSNode> mChildren; private @Nullable ArrayList<CSSNode> mChildren;
private @Nullable CSSNode mParent; private @Nullable CSSNode mParent;
@@ -139,7 +138,6 @@ public class CSSNode {
* Performs the actual layout and saves the results in {@link #layout} * Performs the actual layout and saves the results in {@link #layout}
*/ */
public void calculateLayout(CSSLayoutContext layoutContext) { public void calculateLayout(CSSLayoutContext layoutContext) {
layout.resetResult();
LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, null); LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, null);
} }

View 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,
}

View File

@@ -23,6 +23,7 @@ public class CSSStyle {
public CSSAlign alignSelf; public CSSAlign alignSelf;
public CSSPositionType positionType; public CSSPositionType positionType;
public CSSWrap flexWrap; public CSSWrap flexWrap;
public CSSOverflow overflow;
public float flex; public float flex;
public Spacing margin = new Spacing(); public Spacing margin = new Spacing();
@@ -51,6 +52,7 @@ public class CSSStyle {
alignSelf = CSSAlign.AUTO; alignSelf = CSSAlign.AUTO;
positionType = CSSPositionType.RELATIVE; positionType = CSSPositionType.RELATIVE;
flexWrap = CSSWrap.NOWRAP; flexWrap = CSSWrap.NOWRAP;
overflow = CSSOverflow.VISIBLE;
flex = 0f; flex = 0f;
margin.reset();; margin.reset();;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -39,8 +39,7 @@ global.layoutTestUtils = {
}; };
global.describe = function(name, cb) { global.describe = function(name, cb) {
if (name === 'Layout' || if (name.toLowerCase().indexOf('javascript only') === -1) {
name === 'Layout alignContent') {
cb(); cb();
} }
}; };
@@ -175,6 +174,10 @@ function printLayout(test) {
'exactly': 'CSS_MEASURE_MODE_EXACTLY', 'exactly': 'CSS_MEASURE_MODE_EXACTLY',
'at-most': 'CSS_MEASURE_MODE_AT_MOST' '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, 'flex', 'flex');
addFloat(node, 'width', 'dimensions[CSS_WIDTH]'); addFloat(node, 'width', 'dimensions[CSS_WIDTH]');
addFloat(node, 'height', 'dimensions[CSS_HEIGHT]'); addFloat(node, 'height', 'dimensions[CSS_HEIGHT]');
@@ -256,8 +259,13 @@ function printLayout(test) {
function transpileAnnotatedJStoC(jsCode) { function transpileAnnotatedJStoC(jsCode) {
return 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('node.style.measure', 'node.measure')
.replace(/null/g, 'NULL') .replace(/undefined/g, 'NULL')
.replace(/\.children\.length/g, '.children_count') .replace(/\.children\.length/g, '.children_count')
.replace(/\.width/g, '.dimensions[CSS_WIDTH]') .replace(/\.width/g, '.dimensions[CSS_WIDTH]')
.replace(/\.height/g, '.dimensions[CSS_HEIGHT]') .replace(/\.height/g, '.dimensions[CSS_HEIGHT]')
@@ -266,23 +274,30 @@ function transpileAnnotatedJStoC(jsCode) {
.replace(/\.minWidth/g, '.minDimensions[CSS_WIDTH]') .replace(/\.minWidth/g, '.minDimensions[CSS_WIDTH]')
.replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]') .replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]')
.replace(/\.lineIndex/g, '.line_index') .replace(/\.lineIndex/g, '.line_index')
.replace(/\.nextAbsoluteChild/g, '.next_absolute_child') .replace(/\.nextChild/g, '.next_child')
.replace(/\.nextFlexChild/g, '.next_flex_child') .replace(/\.flexBasis/g, '.flex_basis')
.replace(/layout\[dim/g, 'layout.dimensions[dim')
.replace(/layout\[pos/g, 'layout.position[pos') .replace(/layout\[pos/g, 'layout.position[pos')
.replace(/layout\[leading/g, 'layout.position[leading') .replace(/layout\[leading/g, 'layout.position[leading')
.replace(/layout\[trailing/g, 'layout.position[trailing') .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\[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\[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(/node\./g, 'node->')
.replace(/child\./g, 'child->') .replace(/child\./g, 'child->')
.replace(/parent\./g, 'parent->')
.replace(/currentAbsoluteChild\./g, 'currentAbsoluteChild->') .replace(/currentAbsoluteChild\./g, 'currentAbsoluteChild->')
.replace(/currentFlexChild\./g, 'currentFlexChild->') .replace(/currentRelativeChild\./g, 'currentRelativeChild->')
.replace(/getPositionType\((.+?)\)/g, '$1->style.position_type') .replace(/getPositionType\((.+?)\)/g, '$1->style.position_type')
.replace(/getJustifyContent\((.+?)\)/g, '$1->style.justify_content') .replace(/getJustifyContent\((.+?)\)/g, '$1->style.justify_content')
.replace(/getAlignContent\((.+?)\)/g, '$1->style.align_content') .replace(/getAlignContent\((.+?)\)/g, '$1->style.align_content')
.replace(/assert\((.+?),\s*'(.+?)'\);/g, 'assert($1); // $2')
.replace(/getOverflow\((.+?)\)/g, '$1->style.overflow')
.replace(/var\/\*\(c\)!([^*]+)\*\//g, '$1') .replace(/var\/\*\(c\)!([^*]+)\*\//g, '$1')
.replace(/var\/\*([^\/]+)\*\//g, '$1') .replace(/var\/\*([^\/]+)\*\//g, '$1')
.replace(/ === /g, ' == ') .replace(/ === /g, ' == ')
@@ -290,8 +305,7 @@ function transpileAnnotatedJStoC(jsCode) {
.replace(/\n {2}/g, '\n') .replace(/\n {2}/g, '\n')
.replace(/\/\*\(c\)!([^*]+)\*\//g, '$1') .replace(/\/\*\(c\)!([^*]+)\*\//g, '$1')
.replace(/\/[*]!([^*]+)[*]\//g, '$1') .replace(/\/[*]!([^*]+)[*]\//g, '$1')
.replace(/\/\*\(java\)!([^*]+)\*\//g, '') .replace(/\/\*\(java\)!([^*]+)\*\//g, '');
.split('\n').slice(1, -1).join('\n');
} }
function makeConstDefs() { function makeConstDefs() {
@@ -318,14 +332,18 @@ function generateFile(fileName, generatedContent) {
fs.writeFileSync(fileName, content); 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); var allTestsInC = allTests.map(printLayout);
generateFile(__dirname + '/__tests__/Layout-test.c', allTestsInC.join('\n\n')); generateFile(__dirname + '/__tests__/Layout-test.c', allTestsInC.join('\n\n'));
generateFile(__dirname + '/Layout-test-utils.c', makeConstDefs()); generateFile(__dirname + '/Layout-test-utils.c', makeConstDefs());
generateFile(__dirname + '/Layout.c', transpileAnnotatedJStoC(computeLayout.toString())); generateFile(__dirname + '/Layout.c', transpileAnnotatedJStoC(computeLayoutCode));
generateFile(__dirname + '/java/src/com/facebook/csslayout/LayoutEngine.java', JavaTranspiler.transpileLayoutEngine(computeLayout.toString())); 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/TestConstants.java', JavaTranspiler.transpileCConstDefs(makeConstDefs()));
generateFile(__dirname + '/java/tests/com/facebook/csslayout/LayoutEngineTest.java', JavaTranspiler.transpileCTestsArray(allTestsInC)); 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/TestConstants.cs', CSharpTranspiler.transpileCConstDefs(makeConstDefs()));
generateFile(__dirname + '/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs', CSharpTranspiler.transpileCTestsArray(allTestsInC)); generateFile(__dirname + '/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs', CSharpTranspiler.transpileCTestsArray(allTestsInC));