Import new C source of truth css-layout

fbshipit-source-id: e866918d6c62fc1cf3a04c269f782b94db9b875a
This commit is contained in:
FBShipIt
2016-07-25 06:31:32 -07:00
committed by Emil Sjolander
parent 93809b69c8
commit fdd8552c4e
118 changed files with 11099 additions and 34574 deletions

View File

@@ -1,195 +0,0 @@
/**
* 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.
*/
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')
.replace(/css_justify_t/g, 'CSSJustify')
.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]')
.replace(/layout\[dim/g, 'layout.dimensions[dim')
.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, '($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.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(/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.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])')
.replace(/getTrailingPadding\((.+?),\s*(.+?)\)/g, '$1.style.padding.getWithFallback(trailingSpacing[$2], trailing[$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(/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|CSSOverflow)\.([_A-Z]+)/g,
function(str, match1, match2) {
return match1 + '.' + constantToPascalCase(match2);
});
}
function __transpileSingleTestToCSharp(code) {
return __transpileToCSharpCommon(code)
.replace(/CSS_DIRECTION_/g, 'CSSDirection.')
.replace(/CSS_FLEX_DIRECTION_/g, 'CSSFlexDirection.')
.replace(/CSS_WRAP/g, 'CSSWrap.WRAP')
.replace(/new_test_css_node/g, 'new TestCSSNode')
.replace(// style.position[CSS_TOP] => style.position[CSSLayout.POSITION_TOP]
/(style|layout)\.position\[CSS_(LEFT|TOP|RIGHT|BOTTOM)\]/g,
function(str, match1, match2) {
return match1 + '.position[POSITION_' + match2 + ']';
})
.replace(// style.dimensions[CSS_WIDTH] => style.dimensions[CSSLayout.DIMENSION_WIDTH]
/(style|layout)\.dimensions\[CSS_(WIDTH|HEIGHT)\]/g,
function(str, match1, match2) {
return match1 + '.dimensions[DIMENSION_' + match2 + ']';
})
.replace(// style.maxDimensions[CSS_WIDTH] => style.maxWidth
/(style|layout)\.maxDimensions\[CSS_(WIDTH|HEIGHT)\]/g,
function(str, match1, match2) {
return match1 + '.max' + match2.substr(0, 1).toUpperCase() + match2.substr(1).toLowerCase();
})
.replace(// style.minDimensions[CSS_WIDTH] => style.minWidth
/(style|layout)\.minDimensions\[CSS_(WIDTH|HEIGHT)\]/g,
function(str, match1, match2) {
return match1 + '.min' + match2.substr(0, 1).toUpperCase() + match2.substr(1).toLowerCase();
})
.replace(// style.margin[CSS_TOP] = 12.3 => style.margin[Spacing.TOP].set(12.3)
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]\s+=\s+(-?[\.\d]+)/g,
function(str, match1, match2, match3) {
var propertyCap = match1.charAt(0).toUpperCase() + match1.slice(1);
return 'set' + propertyCap + '(Spacing.' + match2 + ', ' + match3 + ')';
})
.replace(// style.margin[CSS_TOP] => style.margin[Spacing.TOP]
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]/g,
function(str, match1, match2) {
return 'style.' + match1 + '.get(Spacing.' + match2 + ')';
})
.replace(/get_child\(.*context\,\s([^\)]+)\)/g, 'getChildAt($1)')
.replace(/init_css_node_children/g, 'addChildren')
.replace(/css_node_t(\s)\*/g, 'TestCSSNode$1')
.replace(/\->/g, '.')
.replace(/(\d+\.\d+)/g, '$1f')
.replace(// style.flex_direction => style.flexDirection
/style\.([^_\[\]\s]+)_(\w)(\w+)/g,
function(str, match1, match2, match3) {
return 'style.' + match1 + match2.toUpperCase() + match3;
})
.replace(/(\w+)\.measure\s+=\s+.+/g, '$1.setMeasureFunction(sTestMeasureFunction);')
// additional case conversions
.replace(/(CSSWrap|CSSFlexDirection)\.([_A-Z]+)/g,
function(str, match1, match2) {
return match1 + '.' + constantToPascalCase(match2);
});
}
function indent(code) {
return code
.split('\n')
.map(function(line) { return ' ' + line; })
.join('\n');
}
function constantToPascalCase(str) {
return str[0] + str.substr(1)
.toLowerCase()
.replace(/_(.)/g,
function(_, m) { return m.toUpperCase(); });
}
var CSharpTranspiler = {
transpileLayoutEngine: function(code) {
return indent(
__transpileToCSharpCommon(code)
.replace('node.style.measure', 'node.measure')
.replace(/\.children\.length/g, '.getChildCount()')
.replace(/node.children\[i\]/g, 'node.getChildAt(i)')
.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, ' == ')
.replace(/ !== /g, ' != ')
.replace(/\n {2}/g, '\n')
.replace(/\/[*]!([^*]+)[*]\//g, '$1')
.replace(/css_node_t\*/g, 'CSSNode'));
},
transpileCConstDefs: function(cConstDefs) {
return indent(
cConstDefs
.replace(/#define\s+(\w+)\s+(\"[^\"]+\")/g, 'public static readonly string $1 = $2;')
.replace(/#define\s+(\w+)\s+(.+)/g, 'public static readonly float $1 = $2f;'));
},
transpileCTestsArray: function(allTestsInC) {
var allTestsInCSharp = [];
for (var i = 0; i < allTestsInC.length; i++) {
allTestsInCSharp[i] =
' [Test]\n' +
' public void TestCase' + i + '()\n' +
__transpileSingleTestToCSharp(allTestsInC[i]);
}
return allTestsInCSharp.join('\n\n');
}
};
if (typeof module !== 'undefined') {
module.exports = CSharpTranspiler;
}

View File

@@ -1,174 +0,0 @@
/**
* 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.
*/
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')
.replace(/css_justify_t/g, 'CSSJustify')
.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]')
.replace(/layout\[dim/g, 'layout.dimensions[dim')
.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, '($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.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(/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.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])')
.replace(/getTrailingPadding\((.+?),\s*(.+?)\)/g, '$1.style.padding.getWithFallback(trailingSpacing[$2], trailing[$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(/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');
}
function __transpileSingleTestToJava(code) {
return __transpileToJavaCommon(code)
.replace(/CSS_DIRECTION_/g, 'CSSDirection.')
.replace(/CSS_FLEX_DIRECTION_/g, 'CSSFlexDirection.')
.replace(/CSS_WRAP/g, 'CSSWrap.WRAP')
.replace(/new_test_css_node/g, 'new TestCSSNode')
.replace(// style.position[CSS_TOP] => style.position[CSSLayout.POSITION_TOP]
/(style|layout)\.position\[CSS_(LEFT|TOP|RIGHT|BOTTOM)\]/g,
function(str, match1, match2) {
return match1 + '.position[POSITION_' + match2 + ']';
})
.replace(// style.dimensions[CSS_WIDTH] => style.dimensions[CSSLayout.DIMENSION_WIDTH]
/(style|layout)\.dimensions\[CSS_(WIDTH|HEIGHT)\]/g,
function(str, match1, match2) {
return match1 + '.dimensions[DIMENSION_' + match2 + ']';
})
.replace(// style.maxDimensions[CSS_WIDTH] => style.maxWidth
/(style|layout)\.maxDimensions\[CSS_(WIDTH|HEIGHT)\]/g,
function(str, match1, match2) {
return match1 + '.max' + match2.substr(0, 1).toUpperCase() + match2.substr(1).toLowerCase();
})
.replace(// style.minDimensions[CSS_WIDTH] => style.minWidth
/(style|layout)\.minDimensions\[CSS_(WIDTH|HEIGHT)\]/g,
function(str, match1, match2) {
return match1 + '.min' + match2.substr(0, 1).toUpperCase() + match2.substr(1).toLowerCase();
})
.replace(// style.margin[CSS_TOP] = 12.3 => style.margin[Spacing.TOP].set(12.3)
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]\s+=\s+(-?[\.\d]+)/g,
function(str, match1, match2, match3) {
var propertyCap = match1.charAt(0).toUpperCase() + match1.slice(1);
return 'set' + propertyCap + '(Spacing.' + match2 + ', ' + match3 + ')';
})
.replace(// style.margin[CSS_TOP] => style.margin[Spacing.TOP]
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]/g,
function(str, match1, match2) {
return 'style.' + match1 + '.get(Spacing.' + match2 + ')';
})
.replace(/get_child\(.*context\,\s([^\)]+)\)/g, 'getChildAt($1)')
.replace(/init_css_node_children/g, 'addChildren')
.replace(/css_node_t(\s)\*/g, 'TestCSSNode$1')
.replace(/\->/g, '.')
.replace(/(\d+\.\d+)/g, '$1f')
.replace(// style.flex_direction => style.flexDirection
/style\.([^_\[\]\s]+)_(\w)(\w+)/g,
function(str, match1, match2, match3) {
return 'style.' + match1 + match2.toUpperCase() + match3;
})
.replace(/(\w+)\.measure\s+=\s+.+/g, '$1.setMeasureFunction(sTestMeasureFunction);');
}
function indent(code) {
return code
.split('\n')
.map(function(line) { return ' ' + line; })
.join('\n');
}
var JavaTranspiler = {
transpileLayoutEngine: function(code) {
return indent(
__transpileToJavaCommon(code)
.replace('node.style.measure', 'node.measure')
.replace(/\.children\.length/g, '.getChildCount()')
.replace(/node.children\[i\]/g, 'node.getChildAt(i)')
.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, ' == ')
.replace(/ !== /g, ' != ')
.replace(/\n {2}/g, '\n')
.replace(/\/[*]!([^*]+)[*]\//g, '$1')
.replace(/css_node_t\*/g, 'CSSNode'));
},
transpileCConstDefs: function(cConstDefs) {
return indent(
cConstDefs
.replace(/#define\s+(\w+)\s+(\"[^\"]+\")/g, 'public static final String $1 = $2;')
.replace(/#define\s+(\w+)\s+(.+)/g, 'public static final float $1 = $2f;'));
},
transpileCTestsArray: function(allTestsInC) {
var allTestsInJava = [];
for (var i = 0; i < allTestsInC.length; i++) {
allTestsInJava[i] =
' @Test\n' +
' public void testCase' + i + '()\n' +
__transpileSingleTestToJava(allTestsInC[i]);
}
return allTestsInJava.join('\n\n');
}
};
if (typeof module !== 'undefined') {
module.exports = JavaTranspiler;
}

View File

@@ -1,216 +0,0 @@
/**
* 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.
*/
#include "Layout-test-utils.h"
#include <stdlib.h>
#ifdef _MSC_VER
#include <float.h>
#define isnan _isnan
/* define fmaxf & fminf if < VC12 */
#if _MSC_VER < 1800
__forceinline const float fmaxf(const float a, const float b) {
return (a > b) ? a : b;
}
__forceinline const float fminf(const float a, const float b) {
return (a < b) ? a : b;
}
#endif
#endif
/** START_GENERATED **/
#define SMALL_WIDTH 35
#define SMALL_HEIGHT 18
#define BIG_WIDTH 172
#define BIG_HEIGHT 36
#define BIG_MIN_WIDTH 100
#define SMALL_TEXT "small"
#define LONG_TEXT "loooooooooong with space"
#define MEASURE_WITH_RATIO_2 "measureWithRatio2"
#define MEASURE_WITH_MATCH_PARENT "measureWithMatchParent"
/** END_GENERATED **/
typedef struct failed_test_t {
struct failed_test_t *next;
const char *name;
css_node_t *style;
css_node_t *expected;
} failed_test_t;
static failed_test_t *failed_test_head = NULL;
static failed_test_t *failed_test_tail = NULL;
static void add_failed_test(const char *name, css_node_t *style, css_node_t *expected) {
failed_test_t *failed_test = (failed_test_t *)malloc(sizeof(failed_test_t));
failed_test->next = NULL;
failed_test->name = name;
failed_test->style = style;
failed_test->expected = expected;
if (!failed_test_head) {
failed_test_head = failed_test;
failed_test_tail = failed_test;
} else {
failed_test_tail->next = failed_test;
failed_test_tail = failed_test;
}
}
static bool eq(float a, float b) {
return fabs(a - b) < 0.0001;
}
static bool are_layout_equal(css_node_t *a, css_node_t *b) {
if (!eq(a->layout.dimensions[CSS_WIDTH], b->layout.dimensions[CSS_WIDTH]) ||
!eq(a->layout.dimensions[CSS_HEIGHT], b->layout.dimensions[CSS_HEIGHT]) ||
!eq(a->layout.position[CSS_TOP], b->layout.position[CSS_TOP]) ||
!eq(a->layout.position[CSS_LEFT], b->layout.position[CSS_LEFT]) ||
!eq(a->children_count, b->children_count)) {
return false;
}
for (int i = 0; i < a->children_count; ++i) {
if (!are_layout_equal(a->get_child(a->context, i), b->get_child(b->context, i))) {
return false;
}
}
return true;
}
css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode) {
const char *text = (const char *)context;
css_dim_t dim;
if (strcmp(text, SMALL_TEXT) == 0) {
if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
width = 1000000;
}
dim.dimensions[CSS_WIDTH] = fminf(SMALL_WIDTH, width);
dim.dimensions[CSS_HEIGHT] = SMALL_HEIGHT;
return dim;
}
if (strcmp(text, LONG_TEXT) == 0) {
if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
width = 1000000;
}
dim.dimensions[CSS_WIDTH] = width >= BIG_WIDTH ? BIG_WIDTH : fmaxf(BIG_MIN_WIDTH, width);
dim.dimensions[CSS_HEIGHT] = width >= BIG_WIDTH ? SMALL_HEIGHT : BIG_HEIGHT;
return dim;
}
if (strcmp(text, MEASURE_WITH_RATIO_2) == 0) {
if (widthMode != CSS_MEASURE_MODE_UNDEFINED) {
dim.dimensions[CSS_WIDTH] = width;
dim.dimensions[CSS_HEIGHT] = width * 2;
} else if (heightMode != CSS_MEASURE_MODE_UNDEFINED) {
dim.dimensions[CSS_WIDTH] = height * 2;
dim.dimensions[CSS_HEIGHT] = height;
} else {
dim.dimensions[CSS_WIDTH] = 99999;
dim.dimensions[CSS_HEIGHT] = 99999;
}
return dim;
}
if (strcmp(text, MEASURE_WITH_MATCH_PARENT) == 0) {
if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
width = 99999;
}
if (heightMode == CSS_MEASURE_MODE_UNDEFINED) {
height = 99999;
}
dim.dimensions[CSS_WIDTH] = width;
dim.dimensions[CSS_HEIGHT] = height;
return dim;
}
// Should not go here
dim.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
dim.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
return dim;
}
static int test_ran_count = 0;
void test(const char *name, css_node_t *style, css_node_t *expected_layout) {
++test_ran_count;
layoutNode(style, CSS_UNDEFINED, CSS_UNDEFINED, (css_direction_t)-1);
if (!are_layout_equal(style, expected_layout)) {
printf("%sF%s", "\x1B[31m", "\x1B[0m");
add_failed_test(name, style, expected_layout);
} else {
printf("%s.%s", "\x1B[32m", "\x1B[0m");
free_css_node(style);
free_css_node(expected_layout);
}
}
int tests_finished() {
failed_test_t *failed_test = failed_test_head;
printf("\n");
int tests_failed = 0;
while (failed_test) {
printf("%sFAIL%s %s\n", "\x1B[31m", "\x1B[0m", failed_test->name);
printf("Input: ");
print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_STYLE | CSS_PRINT_CHILDREN));
printf("Output: ");
print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN));
printf("Expected: ");
print_css_node(failed_test->expected, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN));
free_css_node(failed_test->style);
free_css_node(failed_test->expected);
failed_test_t *next_failed_test = failed_test->next;
free(failed_test);
failed_test = next_failed_test;
tests_failed++;
}
printf("\n\n");
if (tests_failed > 0) {
printf("TESTS FAILED: %d\n", tests_failed);
return 1;
} else {
printf("ALL TESTS PASSED: %d tests ran.\n", test_ran_count);
return 0;
}
}
static css_node_t* get_child(void *context, int i) {
css_node_t* children = (css_node_t*)context;
return &children[i];
}
static bool is_dirty(void *context) {
(void)context; // remove unused warning
return true;
}
static void init_test_css_node(css_node_t *node) {
node->get_child = get_child;
node->is_dirty = is_dirty;
}
css_node_t *new_test_css_node(void) {
css_node_t *node = new_css_node();
init_test_css_node(node);
return node;
}
void init_css_node_children(css_node_t *node, int children_count) {
node->context = calloc((size_t)children_count, sizeof(css_node_t));
for (int i = 0; i < children_count; ++i) {
init_css_node(node->get_child(node->context, i));
init_test_css_node(node->get_child(node->context, i));
}
node->children_count = children_count;
}

View File

@@ -1,18 +0,0 @@
/**
* 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.
*/
#include "Layout.h"
#include <stdio.h>
#include <string.h>
void test(const char *name, css_node_t *style, css_node_t *expected_layout);
int tests_finished(void);
css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode);
void init_css_node_children(css_node_t *node, int children_count);
css_node_t *new_test_css_node(void);

View File

@@ -1,604 +0,0 @@
/**
* 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.
*/
/* globals document, computeLayout, navigator */
var layoutTestUtils = (function() {
//
// Sets the test cases precision, by default set to 1.0, aka pixel precision
// (assuming the browser does pixel snapping - and that we're ok with being
// 'only' pixel perfect).
//
// Set it to '10' for .1 precision, etc... in theory the browser is doing
// 'pixel' snapping so 1.0 should do, the code is left for clarity...
//
// Set it to undefined to disable and use full precision.
//
var testMeasurePrecision = 1.0;
if (typeof jasmine !== 'undefined') {
jasmine.matchersUtil.buildFailureMessage = function() {
var args = Array.prototype.slice.call(arguments, 0);
var matcherName = args[0];
var isNot = args[1];
var actual = args[2];
var expected = args.slice(3);
var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
var pp = function(node) {
return jasmine.pp(node)
.replace(/([\{\[]) /g, '$1')
.replace(/ ([\}\]:])/g, '$1');
};
var message = 'Expected ' +
pp(actual) +
(isNot ? ' not ' : ' ') +
'\n' +
englishyPredicate;
if (expected.length > 0) {
for (var i = 0; i < expected.length; i++) {
if (i > 0) {
message += ',';
}
message += ' ' + pp(expected[i]);
}
}
return message + '.';
};
}
var _cachedIframe;
function renderIframe() {
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
return iframe;
}
function getIframe(iframe) {
if (_cachedIframe) {
return _cachedIframe;
}
var doc = iframe.contentDocument;
if (doc.readyState === 'complete') {
var style = document.createElement('style');
style.textContent = (function() {/*
body, div {
box-sizing: border-box;
border: 0 solid black;
position: relative;
display: flex;
display: -webkit-flex;
flex-direction: column;
-webkit-flex-direction: column;
align-items: stretch;
-webkit-align-items: stretch;
justify-content: flex-start;
-webkit-justify-content: flex-start;
flex-shrink: 0;
-webkit-flex-shrink: 0;
margin: 0;
padding: 0;
min-width: 0;
}
hack to ignore three hundred px width of the body {}
body > div {
align-self: flex-start;
}
*/} + '').slice(15, -4);
doc.head.appendChild(style);
_cachedIframe = iframe;
return iframe;
} else {
setTimeout(getIframe.bind(null, iframe), 0);
}
}
if (typeof window !== 'undefined') {
var iframe = renderIframe();
getIframe(iframe);
}
if (typeof computeLayout === 'object') {
var fillNodes = computeLayout.fillNodes;
var realComputeLayout = computeLayout.computeLayout;
var canUseCachedMeasurement = computeLayout.canUseCachedMeasurement;
}
function extractNodes(node) {
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 node.layout;
return layout;
}
function roundLayout(layout) {
// Chrome rounds all the numbers with a precision of 1/64
// Reproduce the same behavior
function round(number) {
var floored = Math.floor(number);
var decimal = number - floored;
if (decimal === 0) {
return number;
}
var minDifference = Infinity;
var minDecimal = Infinity;
for (var i = 1; i < 64; ++i) {
var roundedDecimal = i / 64;
var difference = Math.abs(roundedDecimal - decimal);
if (difference < minDifference) {
minDifference = difference;
minDecimal = roundedDecimal;
}
}
return floored + minDecimal;
}
function rec(layout) {
layout.top = round(layout.top);
layout.left = round(layout.left);
layout.width = round(layout.width);
layout.height = round(layout.height);
if (layout.children) {
for (var i = 0; i < layout.children.length; ++i) {
rec(layout.children[i]);
}
}
}
rec(layout);
return layout;
}
function capitalizeFirst(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function computeCSSLayout(rootNode) {
fillNodes(rootNode);
realComputeLayout(rootNode);
return roundLayout(extractNodes(rootNode));
}
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 || '');
setStyle(div, name, value);
}
}
function transferSpacing(div, node, type, suffix) {
transfer(div, node, type + suffix, 'px');
transfer(div, node, type + 'Left' + suffix, 'px');
transfer(div, node, type + 'Top' + suffix, 'px');
transfer(div, node, type + 'Bottom' + suffix, 'px');
transfer(div, node, type + 'Right' + suffix, 'px');
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');
transfer(div, node, 'height', 'px');
transfer(div, node, 'minWidth', 'px');
transfer(div, node, 'minHeight', 'px');
transfer(div, node, 'maxWidth', 'px');
transfer(div, node, 'maxHeight', 'px');
transfer(div, node, 'top', 'px');
transfer(div, node, 'left', 'px');
transfer(div, node, 'right', 'px');
transfer(div, node, 'bottom', 'px');
transferSpacing(div, node, 'margin', '');
transferSpacing(div, node, 'padding', '');
transferSpacing(div, node, 'border', 'Width');
transfer(div, node, 'flexDirection');
transfer(div, node, 'direction');
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);
});
if (node.style.measure) {
div.innerText = node.style.measure.toString();
}
return div;
}
var div = renderNode(body, node);
function buildLayout(absoluteRect, div) {
var rect = div.getBoundingClientRect();
var result = {
width: rect.width,
height: rect.height,
top: rect.top - absoluteRect.top,
left: rect.left - absoluteRect.left
};
var children = [];
for (var child = div.firstChild; child; child = child.nextSibling) {
if (child.nodeType !== 3 /* textNode */) {
children.push(buildLayout(rect, child));
}
}
if (children.length) {
result.children = children;
}
return result;
}
var layout = buildLayout({left: 0, top: 0}, div);
body.removeChild(div);
return layout;
}
function inplaceRoundNumbersInObject(obj) {
if (!testMeasurePrecision) {
// undefined/0, disables rounding
return;
}
for (var key in obj) {
if (!obj.hasOwnProperty(key)) {
continue;
}
var val = obj[key];
if (typeof val === 'number') {
obj[key] = Math.floor((val * testMeasurePrecision) + 0.5) / testMeasurePrecision;
} else if (typeof val === 'object') {
inplaceRoundNumbersInObject(val);
}
}
}
function nameLayout(name, layout) {
var namedLayout = {name: name};
for (var key in layout) {
namedLayout[key] = layout[key];
}
return namedLayout;
}
function testFillNodes(node, filledNode) {
expect(fillNodes(node)).toEqual(filledNode);
}
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))
.toEqual(nameLayout(name, layoutB));
}
function isEqual(a, b) {
// computeCSSLayout and computeDOMLayout output a tree with same ordered elements
return JSON.stringify(a) === JSON.stringify(b);
}
function reduceTest(node) {
function isWorking() {
return isEqual(
computeDOMLayout(node),
computeCSSLayout(node)
);
}
if (isWorking()) {
return node;
}
var isModified = true;
function rec(node) {
var key;
var value;
// Style
for (key in node.style) {
value = node.style[key];
delete node.style[key];
if (isWorking()) {
node.style[key] = value;
} else {
isModified = true;
}
}
// Round values
for (key in node.style) {
value = node.style[key];
if (value > 100) {
node.style[key] = Math.round(value / 100) * 100;
} else if (value > 10) {
node.style[key] = Math.round(value / 10) * 10;
} else if (value > 1) {
node.style[key] = 5;
}
if (node.style[key] !== value) {
if (isWorking()) {
node.style[key] = value;
} else {
isModified = true;
}
}
}
// Children
for (var i = 0; node.children && i < node.children.length; ++i) {
value = node.children[i];
node.children.splice(i, 1);
if (isWorking()) {
if (!node.children) {
node.children = [];
}
node.children.splice(i, 0, value);
rec(node.children[i]);
} else {
i--;
isModified = true;
}
}
}
while (isModified) {
isModified = false;
rec(node);
}
return node;
}
var iframeText;
function measureTextSizes(text, width) {
iframeText = iframeText || document.createElement('iframe');
document.body.appendChild(iframeText);
var body = iframeText.contentDocument.body;
if (width === undefined || isNaN(width)) {
width = Infinity;
}
var div = document.createElement('div');
div.style.width = (width === Infinity ? 10000000 : width) + 'px';
div.style.display = 'flex';
div.style.flexDirection = 'column';
div.style.alignItems = 'flex-start';
div.style.alignContent = 'flex-start';
var span = document.createElement('span');
span.style.display = 'flex';
span.style.flexDirection = 'column';
span.style.alignItems = 'flex-start';
span.style.alignContent = 'flex-start';
span.innerText = text;
div.appendChild(span);
body.appendChild(div);
var rect = span.getBoundingClientRect();
body.removeChild(div);
return {
width: rect.width,
height: rect.height
};
}
var texts = {
small: 'small',
big: 'loooooooooong with space'
};
var preDefinedTextSizes = {
smallWidth: 34.671875,
smallHeight: 18,
bigWidth: 172.421875,
bigHeight: 36,
bigMinWidth: 100.4375
};
// Note(prenaux): Clearly not what I would like, but it seems to be the only
// way :( My guess is that since the font on Windows is
// different than on OSX it has a different size.
if (typeof navigator !== 'undefined' && navigator.userAgent.indexOf('Windows NT') > -1) {
preDefinedTextSizes.bigHeight = 36;
}
var textSizes;
if (typeof require === 'function') {
textSizes = preDefinedTextSizes;
} else {
textSizes = {
smallWidth: measureTextSizes(texts.small, 0).width,
smallHeight: measureTextSizes(texts.small, 0).height,
bigWidth: measureTextSizes(texts.big).width,
bigHeight: measureTextSizes(texts.big, 0).height,
bigMinWidth: measureTextSizes(texts.big, 0).width
};
}
// round the text sizes so that we dont have to update it for every browser
// update, assumes we're ok with pixel precision
inplaceRoundNumbersInObject(preDefinedTextSizes);
inplaceRoundNumbersInObject(textSizes);
return {
texts: texts,
textSizes: textSizes,
preDefinedTextSizes: preDefinedTextSizes,
testLayout: function(node, expectedLayout) {
var layout = computeCSSLayout(node);
var domLayout = computeDOMLayout(node);
inplaceRoundNumbersInObject(layout);
inplaceRoundNumbersInObject(domLayout);
inplaceRoundNumbersInObject(expectedLayout);
testNamedLayout('expected-dom', expectedLayout, domLayout);
testNamedLayout('layout-dom', layout, domLayout);
},
testLayoutAgainstDomOnly: function(node) {
var layout = computeCSSLayout(node);
var domLayout = computeDOMLayout(node);
inplaceRoundNumbersInObject(layout);
inplaceRoundNumbersInObject(domLayout);
testNamedLayout('layout-dom', layout, domLayout);
},
testLayoutAgainstExpectedOnly: function(node, expectedLayout) {
var layout = computeCSSLayout(node);
inplaceRoundNumbersInObject(layout);
inplaceRoundNumbersInObject(expectedLayout);
testNamedLayout('expected-dom', expectedLayout, layout);
},
testFillNodes: testFillNodes,
testExtractNodes: testExtractNodes,
testCanUseCachedMeasurement: testCanUseCachedMeasurement,
testRandomLayout: function(node) {
var layout = computeCSSLayout(node);
var domLayout = computeDOMLayout(node);
inplaceRoundNumbersInObject(layout);
inplaceRoundNumbersInObject(domLayout);
expect({node: node, layout: layout})
.toEqual({node: node, layout: domLayout});
},
testsFinished: function() {
console.log('tests finished!');
},
computeLayout: computeCSSLayout,
computeDOMLayout: computeDOMLayout,
reduceTest: reduceTest,
text: function(text) {
var fn = function(width, widthMode, height, heightMode) {
if (widthMode === 'undefined') {
width = Infinity;
}
// Constants for testing purposes between C/JS and other platforms
// Comment this block of code if you want to use the browser to
// generate proper sizes
if (text === texts.small) {
return {
width: Math.min(textSizes.smallWidth, width),
height: textSizes.smallHeight
};
}
if (text === texts.big) {
var res = {
width: width >= textSizes.bigWidth ? textSizes.bigWidth : Math.max(textSizes.bigMinWidth, width),
height: width >= textSizes.bigWidth ? textSizes.smallHeight : textSizes.bigHeight
};
return res;
}
};
// Name of the function is used in DOM tests as a text in the measured node
// and as a way to tell different measure functions apart in transpiled tests
fn.toString = function() { return text; };
return fn;
},
measureWithRatio2: function() {
var fn = function(width, widthMode, height, heightMode) {
if (widthMode !== 'undefined') {
height = width * 2;
} else if (heightMode !== 'undefined') {
width = height * 2;
} else {
// This should be Infinity, but it would be pain to transpile,
// so let's just go with big numbers.
height = 99999;
width = 99999;
}
return {width: width, height: height};
};
// This is necessary for transpiled tests, see previous comment
fn.toString = function() { return 'measureWithRatio2'; };
return fn;
},
measureWithMatchParent: function() {
var fn = function(width, widthMode, height, heightMode) {
if (widthMode === 'undefined') {
width = 99999;
}
if (heightMode === 'undefined') {
height = 99999;
}
return {width: width, height: height};
};
// This is necessary for transpiled tests, see previous comment
fn.toString = function() { return 'measureWithMatchParent'; };
return fn;
}
};
})();
if (typeof module !== 'undefined') {
module.exports = layoutTestUtils;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,200 +0,0 @@
/**
* 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.
*/
#ifndef __LAYOUT_H
#define __LAYOUT_H
#include <math.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
// Not defined in MSVC++
#ifndef NAN
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define NAN (*(const float *)__nan)
#endif
#define CSS_UNDEFINED NAN
typedef enum {
CSS_DIRECTION_INHERIT = 0,
CSS_DIRECTION_LTR,
CSS_DIRECTION_RTL
} css_direction_t;
typedef enum {
CSS_FLEX_DIRECTION_COLUMN = 0,
CSS_FLEX_DIRECTION_COLUMN_REVERSE,
CSS_FLEX_DIRECTION_ROW,
CSS_FLEX_DIRECTION_ROW_REVERSE
} css_flex_direction_t;
typedef enum {
CSS_JUSTIFY_FLEX_START = 0,
CSS_JUSTIFY_CENTER,
CSS_JUSTIFY_FLEX_END,
CSS_JUSTIFY_SPACE_BETWEEN,
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 {
CSS_ALIGN_AUTO = 0,
CSS_ALIGN_FLEX_START,
CSS_ALIGN_CENTER,
CSS_ALIGN_FLEX_END,
CSS_ALIGN_STRETCH
} css_align_t;
typedef enum {
CSS_POSITION_RELATIVE = 0,
CSS_POSITION_ABSOLUTE
} css_position_type_t;
typedef enum {
CSS_NOWRAP = 0,
CSS_WRAP
} css_wrap_type_t;
// Note: left and top are shared between position[2] and position[4], so
// they have to be before right and bottom.
typedef enum {
CSS_LEFT = 0,
CSS_TOP,
CSS_RIGHT,
CSS_BOTTOM,
CSS_START,
CSS_END,
CSS_POSITION_COUNT
} css_position_t;
typedef enum {
CSS_MEASURE_MODE_UNDEFINED = 0,
CSS_MEASURE_MODE_EXACTLY,
CSS_MEASURE_MODE_AT_MOST,
CSS_MEASURE_MODE_COUNT
} css_measure_mode_t;
typedef enum {
CSS_WIDTH = 0,
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;
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 {
float dimensions[2];
} css_dim_t;
typedef struct {
css_direction_t direction;
css_flex_direction_t flex_direction;
css_justify_t justify_content;
css_align_t align_content;
css_align_t align_items;
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];
/**
* You should skip all the rules that contain negative values for the
* following attributes. For example:
* {padding: 10, paddingLeft: -5}
* should output:
* {left: 10 ...}
* the following two are incorrect:
* {left: -5 ...}
* {left: 0 ...}
*/
float padding[6];
float border[6];
float dimensions[2];
float minDimensions[2];
float maxDimensions[2];
} css_style_t;
typedef struct css_node css_node_t;
struct css_node {
css_style_t style;
css_layout_t layout;
int children_count;
int line_index;
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);
struct css_node* (*get_child)(void *context, int i);
bool (*is_dirty)(void *context);
bool (*is_text_node)(void *context);
void *context;
};
// Lifecycle of nodes and children
css_node_t *new_css_node(void);
void init_css_node(css_node_t *node);
void free_css_node(css_node_t *node);
// Print utilities
typedef enum {
CSS_PRINT_LAYOUT = 1,
CSS_PRINT_STYLE = 2,
CSS_PRINT_CHILDREN = 4,
} 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);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSAlign {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSConstants {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSDirection {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSFlexDirection {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSJustify {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
import java.util.Arrays;

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
/**

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSMeasureMode {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
import javax.annotation.Nullable;

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSPositionType {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
import java.util.Arrays;

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 CSSWrap {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
/**

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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 FloatUtil {

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
import com.facebook.infer.annotation.Assertions;
@@ -551,47 +552,46 @@ public class LayoutEngine {
CSSMeasureMode widthMeasureMode,
CSSMeasureMode heightMeasureMode,
boolean performLayout) {
/** START_GENERATED **/
Assertions.assertCondition(Float.isNaN(availableWidth) ? widthMeasureMode == CSSMeasureMode.UNDEFINED : true, "availableWidth is indefinite so widthMeasureMode must be CSSMeasureMode.UNDEFINED");
Assertions.assertCondition(Float.isNaN(availableHeight) ? heightMeasureMode == CSSMeasureMode.UNDEFINED : true, "availableHeight is indefinite so heightMeasureMode must be CSSMeasureMode.UNDEFINED");
float paddingAndBorderAxisRow = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW])));
float paddingAndBorderAxisColumn = ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
float marginAxisRow = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
float marginAxisColumn = (node.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
// Set the resolved resolution in the node's layout.
CSSDirection direction = resolveDirection(node, parentDirection);
node.layout.direction = direction;
// For content (text) nodes, determine the dimensions based on the text contents.
if (isMeasureDefined(node)) {
float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
if (widthMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY) {
// Don't bother sizing the text if both dimensions are already defined.
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, availableHeight - marginAxisColumn);
} else if (innerWidth <= 0 || innerHeight <= 0) {
// Don't bother sizing the text if there's no horizontal or vertical space.
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
} else {
// Measure the text under the current constraints.
MeasureOutput measureDim = node.measure(
layoutContext.measureOutput,
innerWidth,
widthMeasureMode,
innerHeight,
heightMeasureMode
);
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW,
(widthMeasureMode == CSSMeasureMode.UNDEFINED || widthMeasureMode == CSSMeasureMode.AT_MOST) ?
measureDim.width + paddingAndBorderAxisRow :
@@ -601,10 +601,10 @@ public class LayoutEngine {
measureDim.height + paddingAndBorderAxisColumn :
availableHeight - marginAxisColumn);
}
return;
}
// For nodes with no children, use the available values if they were provided, or
// the minimum size as indicated by the padding and border sizes.
int childCount = node.getChildCount();
@@ -619,7 +619,7 @@ public class LayoutEngine {
availableHeight - marginAxisColumn);
return;
}
// If we're not being asked to perform a full layout, we can handle a number of common
// cases here without incurring the cost of the remaining function.
if (!performLayout) {
@@ -631,19 +631,19 @@ public class LayoutEngine {
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
return;
}
if (widthMeasureMode == CSSMeasureMode.AT_MOST && availableWidth <= 0) {
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, 0);
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, Float.isNaN(availableHeight) ? 0 : (availableHeight - marginAxisColumn));
return;
}
if (heightMeasureMode == CSSMeasureMode.AT_MOST && availableHeight <= 0) {
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, Float.isNaN(availableWidth) ? 0 : (availableWidth - marginAxisRow));
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, 0);
return;
}
// If we're being asked to use an exact width/height, there's no need to measure the children.
if (widthMeasureMode == CSSMeasureMode.EXACTLY && heightMeasureMode == CSSMeasureMode.EXACTLY) {
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
@@ -651,32 +651,32 @@ public class LayoutEngine {
return;
}
}
// STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
int mainAxis = resolveAxis(getFlexDirection(node), direction);
int crossAxis = getCrossFlexDirection(mainAxis, direction);
boolean isMainAxisRow = (mainAxis == CSS_FLEX_DIRECTION_ROW || mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE);
CSSJustify justifyContent = node.style.justifyContent;
boolean isNodeFlexWrap = (node.style.flexWrap == CSSWrap.WRAP);
CSSNode firstAbsoluteChild = null;
CSSNode currentAbsoluteChild = null;
float leadingPaddingAndBorderMain = (node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]));
float trailingPaddingAndBorderMain = (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
float leadingPaddingAndBorderCross = (node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]));
float paddingAndBorderAxisMain = ((node.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + node.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (node.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + node.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis])));
float paddingAndBorderAxisCross = ((node.style.padding.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + node.style.border.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis])) + (node.style.padding.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]) + node.style.border.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
CSSMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode;
CSSMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode;
// STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
float availableInnerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow;
float availableInnerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn;
float availableInnerMainDim = isMainAxisRow ? availableInnerWidth : availableInnerHeight;
float availableInnerCrossDim = isMainAxisRow ? availableInnerHeight : availableInnerWidth;
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
CSSNode child;
int i;
@@ -686,17 +686,17 @@ public class LayoutEngine {
CSSMeasureMode childHeightMeasureMode;
for (i = 0; i < childCount; i++) {
child = node.getChildAt(i);
if (performLayout) {
// Set the initial position (relative to the parent).
CSSDirection childDirection = resolveDirection(child, direction);
setPosition(child, childDirection);
}
// Absolute-positioned children don't participate in flex layout. Add them
// to a list that we can process later.
if (child.style.positionType == CSSPositionType.ABSOLUTE) {
// Store a private linked list of absolutely positioned children
// so that we can efficiently traverse them later.
if (firstAbsoluteChild == null) {
@@ -708,27 +708,27 @@ public class LayoutEngine {
currentAbsoluteChild = child;
child.nextChild = null;
} else {
if (isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
// The width is definite, so use that as the flex basis.
child.layout.flexBasis = Math.max(child.style.dimensions[DIMENSION_WIDTH], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]))));
} else if (!isMainAxisRow && (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
// The height is definite, so use that as the flex basis.
child.layout.flexBasis = Math.max(child.style.dimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (child.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + child.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]))));
} else if (!isFlexBasisAuto(child) && !Float.isNaN(availableInnerMainDim)) {
// If the basis isn't 'auto', it is assumed to be zero.
child.layout.flexBasis = Math.max(0, ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
} else {
// Compute the flex basis and hypothetical main size (i.e. the clamped flex basis).
childWidth = CSSConstants.UNDEFINED;
childHeight = CSSConstants.UNDEFINED;
childWidthMeasureMode = CSSMeasureMode.UNDEFINED;
childHeightMeasureMode = CSSMeasureMode.UNDEFINED;
if ((child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
childWidth = child.style.dimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
@@ -737,7 +737,7 @@ public class LayoutEngine {
childHeight = child.style.dimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
childHeightMeasureMode = CSSMeasureMode.EXACTLY;
}
// According to the spec, if the main size is not definite and the
// child's inline axis is parallel to the main axis (i.e. it's
// horizontal), the child should be sized using "UNDEFINED" in
@@ -746,7 +746,7 @@ public class LayoutEngine {
childWidth = availableInnerWidth;
childWidthMeasureMode = CSSMeasureMode.AT_MOST;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (node.style.overflow == CSSOverflow.HIDDEN) {
@@ -755,7 +755,7 @@ public class LayoutEngine {
childHeightMeasureMode = CSSMeasureMode.AT_MOST;
}
}
// If child has no defined size in the cross axis and is set to stretch, set the cross
// axis to be measured exactly with the available inner width
if (!isMainAxisRow &&
@@ -774,76 +774,76 @@ public class LayoutEngine {
childHeight = availableInnerHeight;
childHeightMeasureMode = CSSMeasureMode.EXACTLY;
}
// Measure the child
layoutNodeInternal(layoutContext, child, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "measure");
child.layout.flexBasis = Math.max(isMainAxisRow ? child.layout.measuredDimensions[DIMENSION_WIDTH] : child.layout.measuredDimensions[DIMENSION_HEIGHT], ((child.style.padding.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.border.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis])) + (child.style.padding.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]) + child.style.border.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]))));
}
}
}
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
// Indexes of children that represent the first and last items in the line.
int startOfLineIndex = 0;
int endOfLineIndex = 0;
// Number of lines.
int lineCount = 0;
// Accumulated cross dimensions of all lines so far.
float totalLineCrossDim = 0;
// Max main dimension of all the lines.
float maxLineMainDim = 0;
while (endOfLineIndex < childCount) {
// Number of items on the currently line. May be different than the difference
// between start and end indicates because we skip over absolute-positioned items.
int itemsOnLine = 0;
// sizeConsumedOnCurrentLine is accumulation of the dimensions and margin
// of all the children on the current line. This will be used in order to
// either set the dimensions of the node if none already exist or to compute
// the remaining space left for the flexible children.
float sizeConsumedOnCurrentLine = 0;
float totalFlexGrowFactors = 0;
float totalFlexShrinkScaledFactors = 0;
i = startOfLineIndex;
// Maintain a linked list of the child nodes that can shrink and/or grow.
CSSNode firstRelativeChild = null;
CSSNode currentRelativeChild = null;
// Add items to the current line until it's full or we run out of items.
while (i < childCount) {
child = node.getChildAt(i);
child.lineIndex = lineCount;
if (child.style.positionType != CSSPositionType.ABSOLUTE) {
float outerFlexBasis = child.layout.flexBasis + (child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
// If this is a multi-line flow and this item pushes us over the available size, we've
// hit the end of the current line. Break out of the loop and lay out the current line.
if (sizeConsumedOnCurrentLine + outerFlexBasis > availableInnerMainDim && isNodeFlexWrap && itemsOnLine > 0) {
break;
}
sizeConsumedOnCurrentLine += outerFlexBasis;
itemsOnLine++;
if ((child.style.positionType == CSSPositionType.RELATIVE && child.style.flex != 0)) {
totalFlexGrowFactors += getFlexGrowFactor(child);
// Unlike the grow factor, the shrink factor is scaled relative to the child
// dimension.
totalFlexShrinkScaledFactors += getFlexShrinkFactor(child) * child.layout.flexBasis;
}
// Store a private linked list of children that need to be layed out.
if (firstRelativeChild == null) {
firstRelativeChild = child;
@@ -854,20 +854,20 @@ public class LayoutEngine {
currentRelativeChild = child;
child.nextChild = null;
}
i++;
endOfLineIndex++;
}
// If we don't need to measure the cross axis, we can skip the entire flex step.
boolean canSkipFlex = !performLayout && measureModeCrossDim == CSSMeasureMode.EXACTLY;
// In order to position the elements in the main axis, we have two
// controls. The space between the beginning and the first element
// and the space between each two elements.
float leadingMainDim = 0;
float betweenMainDim = 0;
// STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
// Calculate the remaining available space that needs to be allocated.
// If the main dimension size isn't known, it is computed based on
@@ -881,17 +881,17 @@ public class LayoutEngine {
// its content. Consequently, remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
remainingFreeSpace = -sizeConsumedOnCurrentLine;
}
float originalRemainingFreeSpace = remainingFreeSpace;
float deltaFreeSpace = 0;
if (!canSkipFlex) {
float childFlexBasis;
float flexShrinkScaledFactor;
float flexGrowFactor;
float baseMainSize;
float boundMainSize;
// Do two passes over the flex items to figure out how to distribute the remaining space.
// The first pass finds the items whose min/max constraints trigger, freezes them at those
// sizes, and excludes those sizes from the remaining space. The second pass sets the size
@@ -904,17 +904,17 @@ public class LayoutEngine {
// that needs to be repeated a variable number of times. The algorithm implemented here
// won't handle all cases but it was simpler to implement and it mitigates performance
// concerns because we know exactly how many passes it'll do.
// First pass: detect the flex items whose min/max constraints trigger
float deltaFlexShrinkScaledFactors = 0;
float deltaFlexGrowFactors = 0;
currentRelativeChild = firstRelativeChild;
while (currentRelativeChild != null) {
childFlexBasis = currentRelativeChild.layout.flexBasis;
if (remainingFreeSpace < 0) {
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
// Is this child able to shrink?
if (flexShrinkScaledFactor != 0) {
baseMainSize = childFlexBasis +
@@ -930,7 +930,7 @@ public class LayoutEngine {
}
} else if (remainingFreeSpace > 0) {
flexGrowFactor = getFlexGrowFactor(currentRelativeChild);
// Is this child able to grow?
if (flexGrowFactor != 0) {
baseMainSize = childFlexBasis +
@@ -945,24 +945,24 @@ public class LayoutEngine {
}
}
}
currentRelativeChild = currentRelativeChild.nextChild;
}
totalFlexShrinkScaledFactors += deltaFlexShrinkScaledFactors;
totalFlexGrowFactors += deltaFlexGrowFactors;
remainingFreeSpace += deltaFreeSpace;
// Second pass: resolve the sizes of the flexible items
deltaFreeSpace = 0;
currentRelativeChild = firstRelativeChild;
while (currentRelativeChild != null) {
childFlexBasis = currentRelativeChild.layout.flexBasis;
float updatedMainSize = childFlexBasis;
if (remainingFreeSpace < 0) {
flexShrinkScaledFactor = getFlexShrinkFactor(currentRelativeChild) * childFlexBasis;
// Is this child able to shrink?
if (flexShrinkScaledFactor != 0) {
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
@@ -970,20 +970,20 @@ public class LayoutEngine {
}
} else if (remainingFreeSpace > 0) {
flexGrowFactor = getFlexGrowFactor(currentRelativeChild);
// Is this child able to grow?
if (flexGrowFactor != 0) {
updatedMainSize = boundAxis(currentRelativeChild, mainAxis, childFlexBasis +
remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor);
}
}
deltaFreeSpace -= updatedMainSize - childFlexBasis;
if (isMainAxisRow) {
childWidth = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
if (!Float.isNaN(availableInnerCrossDim) &&
!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0) &&
heightMeasureMode == CSSMeasureMode.EXACTLY &&
@@ -1000,7 +1000,7 @@ public class LayoutEngine {
} else {
childHeight = updatedMainSize + (currentRelativeChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentRelativeChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
childHeightMeasureMode = CSSMeasureMode.EXACTLY;
if (!Float.isNaN(availableInnerCrossDim) &&
!(currentRelativeChild.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0) &&
widthMeasureMode == CSSMeasureMode.EXACTLY &&
@@ -1015,32 +1015,32 @@ public class LayoutEngine {
childWidthMeasureMode = CSSMeasureMode.EXACTLY;
}
}
boolean requiresStretchLayout = !(currentRelativeChild.style.dimensions[dim[crossAxis]] >= 0.0) &&
getAlignItem(node, currentRelativeChild) == CSSAlign.STRETCH;
// Recursively call the layout algorithm for this child with the updated main size.
layoutNodeInternal(layoutContext, currentRelativeChild, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, performLayout && !requiresStretchLayout, "flex");
currentRelativeChild = currentRelativeChild.nextChild;
}
}
remainingFreeSpace = originalRemainingFreeSpace + deltaFreeSpace;
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
// At this point, all the children have their dimensions set in the main axis.
// Their dimensions are also set in the cross axis with the exception of items
// that are aligned "stretch". We need to compute these stretch values and
// set the final positions.
// If we are using "at most" rules in the main axis, we won't distribute
// any remaining space at this point.
if (measureModeMainDim == CSSMeasureMode.AT_MOST) {
remainingFreeSpace = 0;
}
// Use justifyContent to figure out how to allocate the remaining space
// available in the main axis.
if (justifyContent != CSSJustify.FLEX_START) {
@@ -1061,13 +1061,13 @@ public class LayoutEngine {
leadingMainDim = betweenMainDim / 2;
}
}
float mainDim = leadingPaddingAndBorderMain + leadingMainDim;
float crossDim = 0;
for (i = startOfLineIndex; i < endOfLineIndex; ++i) {
child = node.getChildAt(i);
if (child.style.positionType == CSSPositionType.ABSOLUTE &&
!Float.isNaN(child.style.position[leading[mainAxis]])) {
if (performLayout) {
@@ -1084,7 +1084,7 @@ public class LayoutEngine {
// we put it at the current accumulated offset.
child.layout.position[pos[mainAxis]] += mainDim;
}
// Now that we placed the element, we need to update the variables.
// We need to do that only for relative elements. Absolute elements
// do not take part in that phase.
@@ -1098,7 +1098,7 @@ public class LayoutEngine {
// The main dimension is the sum of all the elements dimension plus
// the spacing.
mainDim += betweenMainDim + (child.layout.measuredDimensions[dim[mainAxis]] + child.style.margin.getWithFallback(leadingSpacing[mainAxis], leading[mainAxis]) + child.style.margin.getWithFallback(trailingSpacing[mainAxis], trailing[mainAxis]));
// The cross dimension is the max of the elements dimension since there
// can only be one element in that cross dimension.
crossDim = Math.max(crossDim, (child.layout.measuredDimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis])));
@@ -1106,33 +1106,33 @@ public class LayoutEngine {
}
}
}
mainDim += trailingPaddingAndBorderMain;
float containerCrossAxis = availableInnerCrossDim;
if (measureModeCrossDim == CSSMeasureMode.UNDEFINED || measureModeCrossDim == CSSMeasureMode.AT_MOST) {
// Compute the cross axis from the max cross dimension of the children.
containerCrossAxis = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
if (measureModeCrossDim == CSSMeasureMode.AT_MOST) {
containerCrossAxis = Math.min(containerCrossAxis, availableInnerCrossDim);
}
}
// If there's no flex wrap, the cross dimension is defined by the container.
if (!isNodeFlexWrap && measureModeCrossDim == CSSMeasureMode.EXACTLY) {
crossDim = availableInnerCrossDim;
}
// Clamp to the min/max size specified on the container.
crossDim = boundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - paddingAndBorderAxisCross;
// STEP 7: CROSS-AXIS ALIGNMENT
// We can skip child alignment if we're just measuring the container.
if (performLayout) {
for (i = startOfLineIndex; i < endOfLineIndex; ++i) {
child = node.getChildAt(i);
if (child.style.positionType == CSSPositionType.ABSOLUTE) {
// If the child is absolutely positioned and has a top/left/bottom/right
// set, override all the previously computed positions to set it correctly.
@@ -1146,18 +1146,18 @@ public class LayoutEngine {
}
} else {
float leadingCrossDim = leadingPaddingAndBorderCross;
// For a relative children, we're either using alignItems (parent) or
// alignSelf (child) in order to determine the position in the cross axis
CSSAlign alignItem = getAlignItem(node, child);
// If the child uses align stretch, we need to lay it out one more time, this time
// forcing the cross-axis size to be the computed cross size for the current line.
if (alignItem == CSSAlign.STRETCH) {
childWidth = child.layout.measuredDimensions[DIMENSION_WIDTH] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
childHeight = child.layout.measuredDimensions[DIMENSION_HEIGHT] + (child.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + child.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
boolean isCrossSizeDefinite = false;
if (isMainAxisRow) {
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0);
childHeight = crossDim;
@@ -1165,7 +1165,7 @@ public class LayoutEngine {
isCrossSizeDefinite = (child.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0);
childWidth = crossDim;
}
// If the child defines a definite size for its cross axis, there's no need to stretch.
if (!isCrossSizeDefinite) {
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
@@ -1174,36 +1174,36 @@ public class LayoutEngine {
}
} else if (alignItem != CSSAlign.FLEX_START) {
float remainingCrossDim = containerCrossAxis - (child.layout.measuredDimensions[dim[crossAxis]] + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]) + child.style.margin.getWithFallback(trailingSpacing[crossAxis], trailing[crossAxis]));
if (alignItem == CSSAlign.CENTER) {
leadingCrossDim += remainingCrossDim / 2;
} else { // CSSAlign.FLEX_END
leadingCrossDim += remainingCrossDim;
}
}
// And we apply the position
child.layout.position[pos[crossAxis]] += totalLineCrossDim + leadingCrossDim;
}
}
}
totalLineCrossDim += crossDim;
maxLineMainDim = Math.max(maxLineMainDim, mainDim);
// Reset variables for new line.
lineCount++;
startOfLineIndex = endOfLineIndex;
endOfLineIndex = startOfLineIndex;
}
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
if (lineCount > 1 && performLayout && !Float.isNaN(availableInnerCrossDim)) {
float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
float crossDimLead = 0;
float currentLead = leadingPaddingAndBorderCross;
CSSAlign alignContent = node.style.alignContent;
if (alignContent == CSSAlign.FLEX_END) {
currentLead += remainingAlignContentDim;
@@ -1214,12 +1214,12 @@ public class LayoutEngine {
crossDimLead = (remainingAlignContentDim / lineCount);
}
}
int endIndex = 0;
for (i = 0; i < lineCount; ++i) {
int startIndex = endIndex;
int j;
// compute the line's height and find the endIndex
float lineHeight = 0;
for (j = startIndex; j < childCount; ++j) {
@@ -1237,14 +1237,14 @@ public class LayoutEngine {
}
endIndex = j;
lineHeight += crossDimLead;
if (performLayout) {
for (j = startIndex; j < endIndex; ++j) {
child = node.getChildAt(j);
if (child.style.positionType != CSSPositionType.RELATIVE) {
continue;
}
CSSAlign alignContentAlignItem = getAlignItem(node, child);
if (alignContentAlignItem == CSSAlign.FLEX_START) {
child.layout.position[pos[crossAxis]] = currentLead + child.style.margin.getWithFallback(leadingSpacing[crossAxis], leading[crossAxis]);
@@ -1260,15 +1260,15 @@ public class LayoutEngine {
}
}
}
currentLead += lineHeight;
}
}
// STEP 9: COMPUTING FINAL DIMENSIONS
node.layout.measuredDimensions[DIMENSION_WIDTH] = boundAxis(node, CSS_FLEX_DIRECTION_ROW, availableWidth - marginAxisRow);
node.layout.measuredDimensions[DIMENSION_HEIGHT] = boundAxis(node, CSS_FLEX_DIRECTION_COLUMN, availableHeight - marginAxisColumn);
// If the user didn't specify a width or height for the node, set the
// dimensions based on the children.
if (measureModeMainDim == CSSMeasureMode.UNDEFINED) {
@@ -1281,7 +1281,7 @@ public class LayoutEngine {
boundAxisWithinMinAndMax(node, mainAxis, maxLineMainDim)),
paddingAndBorderAxisMain);
}
if (measureModeCrossDim == CSSMeasureMode.UNDEFINED) {
// Clamp the size to the min/max size, if specified, and make sure it
// doesn't go below the padding and border amount.
@@ -1292,48 +1292,48 @@ public class LayoutEngine {
boundAxisWithinMinAndMax(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross)),
paddingAndBorderAxisCross);
}
// STEP 10: SETTING TRAILING POSITIONS FOR CHILDREN
if (performLayout) {
boolean needsMainTrailingPos = false;
boolean needsCrossTrailingPos = false;
if (mainAxis == CSS_FLEX_DIRECTION_ROW_REVERSE ||
mainAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) {
needsMainTrailingPos = true;
}
if (crossAxis == CSS_FLEX_DIRECTION_ROW_REVERSE ||
crossAxis == CSS_FLEX_DIRECTION_COLUMN_REVERSE) {
needsCrossTrailingPos = true;
}
// Set trailing position if necessary.
if (needsMainTrailingPos || needsCrossTrailingPos) {
for (i = 0; i < childCount; ++i) {
child = node.getChildAt(i);
if (needsMainTrailingPos) {
child.layout.position[trailing[mainAxis]] = node.layout.measuredDimensions[dim[mainAxis]] - (child.style.positionType == CSSPositionType.ABSOLUTE ? 0 : child.layout.measuredDimensions[dim[mainAxis]]) - child.layout.position[pos[mainAxis]];
}
if (needsCrossTrailingPos) {
child.layout.position[trailing[crossAxis]] = node.layout.measuredDimensions[dim[crossAxis]] - (child.style.positionType == CSSPositionType.ABSOLUTE ? 0 : child.layout.measuredDimensions[dim[crossAxis]]) - child.layout.position[pos[crossAxis]];
}
}
}
}
// STEP 11: SIZING AND POSITIONING ABSOLUTE CHILDREN
currentAbsoluteChild = firstAbsoluteChild;
while (currentAbsoluteChild != null) {
// Now that we know the bounds of the container, perform layout again on the
// absolutely-positioned children.
if (performLayout) {
childWidth = CSSConstants.UNDEFINED;
childHeight = CSSConstants.UNDEFINED;
if ((currentAbsoluteChild.style.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] >= 0.0)) {
childWidth = currentAbsoluteChild.style.dimensions[DIMENSION_WIDTH] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
} else {
@@ -1345,7 +1345,7 @@ public class LayoutEngine {
childWidth = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_ROW, childWidth);
}
}
if ((currentAbsoluteChild.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
childHeight = currentAbsoluteChild.style.dimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
} else {
@@ -1357,12 +1357,12 @@ public class LayoutEngine {
childHeight = boundAxis(currentAbsoluteChild, CSS_FLEX_DIRECTION_COLUMN, childHeight);
}
}
// If we're still missing one or the other dimension, measure the content.
if (Float.isNaN(childWidth) || Float.isNaN(childHeight)) {
childWidthMeasureMode = Float.isNaN(childWidth) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
childHeightMeasureMode = Float.isNaN(childHeight) ? CSSMeasureMode.UNDEFINED : CSSMeasureMode.EXACTLY;
// According to the spec, if the main size is not definite and the
// child's inline axis is parallel to the main axis (i.e. it's
// horizontal), the child should be sized using "UNDEFINED" in
@@ -1371,7 +1371,7 @@ public class LayoutEngine {
childWidth = availableInnerWidth;
childWidthMeasureMode = CSSMeasureMode.AT_MOST;
}
// The W3C spec doesn't say anything about the 'overflow' property,
// but all major browsers appear to implement the following logic.
if (node.style.overflow == CSSOverflow.HIDDEN) {
@@ -1380,14 +1380,14 @@ public class LayoutEngine {
childHeightMeasureMode = CSSMeasureMode.AT_MOST;
}
}
layoutNodeInternal(layoutContext, currentAbsoluteChild, childWidth, childHeight, direction, childWidthMeasureMode, childHeightMeasureMode, false, "abs-measure");
childWidth = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_WIDTH] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_ROW], leading[CSS_FLEX_DIRECTION_ROW]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_ROW], trailing[CSS_FLEX_DIRECTION_ROW]));
childHeight = currentAbsoluteChild.layout.measuredDimensions[DIMENSION_HEIGHT] + (currentAbsoluteChild.style.margin.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + currentAbsoluteChild.style.margin.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]));
}
layoutNodeInternal(layoutContext, currentAbsoluteChild, childWidth, childHeight, direction, CSSMeasureMode.EXACTLY, CSSMeasureMode.EXACTLY, true, "abs-layout");
if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) &&
!!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_ROW]])) {
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_ROW]] =
@@ -1395,7 +1395,7 @@ public class LayoutEngine {
currentAbsoluteChild.layout.measuredDimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
(Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_ROW]]);
}
if (!Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) &&
!!Float.isNaN(currentAbsoluteChild.style.position[leading[CSS_FLEX_DIRECTION_COLUMN]])) {
currentAbsoluteChild.layout.position[leading[CSS_FLEX_DIRECTION_COLUMN]] =
@@ -1404,9 +1404,8 @@ public class LayoutEngine {
(Float.isNaN(currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]) ? 0 : currentAbsoluteChild.style.position[trailing[CSS_FLEX_DIRECTION_COLUMN]]);
}
}
currentAbsoluteChild = currentAbsoluteChild.nextChild;
}
/** END_GENERATED **/
}
}

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
/**

View File

@@ -1,11 +1,12 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* Copyright (c) 2014-present, 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;
import javax.annotation.Nullable;

View File

@@ -1,13 +0,0 @@
root = true
[*]
end_of_line=LF
[*.cs]
indent_style=space
indent_size=4
[*.js]
indent_style=space
indent_size=2

View File

@@ -1,6 +0,0 @@
bin/
obj/
/packages/
/.vs/
*.user
*.nupkg

View File

@@ -1,53 +0,0 @@
/**
* 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.
*/
using System;
using NUnit.Framework;
namespace Facebook.CSSLayout.Tests
{
/**
* Tests for {@link CSSNode}.
*/
public class CSSNodeTest
{
[Test]
public void testAddChildGetParent()
{
CSSNode parent = new CSSNode();
CSSNode child = new CSSNode();
Assert.IsNull(child.getParent());
Assert.AreEqual(0, parent.getChildCount());
parent.addChildAt(child, 0);
Assert.AreEqual(1, parent.getChildCount());
Assert.AreEqual(child, parent.getChildAt(0));
Assert.AreEqual(parent, child.getParent());
parent.removeChildAt(0);
Assert.IsNull(child.getParent());
Assert.AreEqual(0, parent.getChildCount());
}
[Test, ExpectedException(typeof(InvalidOperationException))]
public void testCannotAddChildToMultipleParents()
{
CSSNode parent1 = new CSSNode();
CSSNode parent2 = new CSSNode();
CSSNode child = new CSSNode();
parent1.addChildAt(child, 0);
parent2.addChildAt(child, 0);
}
}
}

View File

@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E687C8FD-0A0D-450F-853D-EC301BE1C038}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Facebook.CSSLayout.Tests</RootNamespace>
<AssemblyName>Facebook.CSSLayout.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CSSNodeTest.cs" />
<Compile Include="LayoutCachingTest.cs" />
<Compile Include="LayoutEngineTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestConstants.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Facebook.CSSLayout\Facebook.CSSLayout.csproj">
<Project>{d534fb4b-a7d4-4a29-96d3-f39a91a259bd}</Project>
<Name>Facebook.CSSLayout</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -1,240 +0,0 @@
/**
* 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.
*/
using NUnit.Framework;
namespace Facebook.CSSLayout.Tests
{
/**
* Tests for {@link LayoutEngine} and {@link CSSNode} to make sure layouts are only generated when
* needed.
*/
public class LayoutCachingTest
{
private void assertTreeHasNewLayout(bool expectedHasNewLayout, CSSNode root)
{
Assert.AreEqual(expectedHasNewLayout, root.HasNewLayout);
for (int i = 0; i < root.getChildCount(); i++)
{
assertTreeHasNewLayout(expectedHasNewLayout, root.getChildAt(i));
}
}
private void markLayoutAppliedForTree(CSSNode root)
{
root.MarkLayoutSeen();
for (int i = 0; i < root.getChildCount(); i++)
{
markLayoutAppliedForTree(root.getChildAt(i));
}
}
[Test]
public void testCachesFullTree()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout();
assertTreeHasNewLayout(true, root);
markLayoutAppliedForTree(root);
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
assertTreeHasNewLayout(false, c0);
assertTreeHasNewLayout(false, c1);
}
[Test]
public void testInvalidatesCacheWhenChildAdded()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
CSSNode c0c1 = new CSSNode();
CSSNode c1c0 = new CSSNode();
c0c1.Width = 200;
c0c1.Height = 200;
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
c0c0.addChildAt(c1c0, 0);
root.calculateLayout();
markLayoutAppliedForTree(root);
c0.addChildAt(c0c1, 1);
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
Assert.IsTrue(c0.HasNewLayout);
Assert.IsTrue(c0c1.HasNewLayout);
Assert.IsTrue(c0c0.HasNewLayout);
Assert.IsTrue(c1.HasNewLayout);
Assert.IsTrue(c1c0.HasNewLayout);
}
[Test]
public void testInvalidatesCacheWhenEnumPropertyChanges()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout();
markLayoutAppliedForTree(root);
c1.AlignSelf = CSSAlign.Center;
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
Assert.IsTrue(c1.HasNewLayout);
Assert.IsTrue(c0.HasNewLayout);
Assert.IsFalse(c0c0.HasNewLayout);
}
[Test]
public void testInvalidatesCacheWhenFloatPropertyChanges()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout();
markLayoutAppliedForTree(root);
c1.SetMargin(CSSSpacingType.Left, 10);
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
Assert.IsTrue(c1.HasNewLayout);
Assert.IsTrue(c0.HasNewLayout);
Assert.IsTrue(c0c0.HasNewLayout);
}
[Test]
public void testInvalidatesFullTreeWhenParentWidthChanges()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
CSSNode c1c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
c1.addChildAt(c1c0, 0);
root.calculateLayout();
markLayoutAppliedForTree(root);
c0.Width = 200;
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
Assert.IsTrue(c0.HasNewLayout);
Assert.IsTrue(c0c0.HasNewLayout);
Assert.IsTrue(c1.HasNewLayout);
Assert.IsTrue(c1c0.HasNewLayout);
}
[Test]
public void testDoesNotInvalidateCacheWhenPropertyIsTheSame()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.Width = 200;
root.calculateLayout();
markLayoutAppliedForTree(root);
root.Width = 200;
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
assertTreeHasNewLayout(false, c0);
assertTreeHasNewLayout(false, c1);
}
[Test]
public void testInvalidateCacheWhenHeightChangesPosition()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c1c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c1.addChildAt(c1c0, 0);
root.calculateLayout();
markLayoutAppliedForTree(root);
c0.Height = 100;
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
Assert.IsTrue(c0.HasNewLayout);
Assert.IsTrue(c1.HasNewLayout);
Assert.IsFalse(c1c0.HasNewLayout);
}
[Test]
public void testInvalidatesOnNewMeasureFunction()
{
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout();
markLayoutAppliedForTree(root);
c1.setMeasureFunction((node, width, widthMode, height, heightMode) => new MeasureOutput(100, 20));
root.calculateLayout();
Assert.IsTrue(root.HasNewLayout);
Assert.IsTrue(c1.HasNewLayout);
Assert.IsTrue(c0.HasNewLayout);
Assert.IsTrue(c0c0.HasNewLayout);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +0,0 @@
/**
* 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.
*/
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Facebook.CSSLayout.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Facebook.CSSLayout.Tests")]
[assembly: AssemblyCopyright("Copyright © Facebook 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("c186053a-741f-477d-b031-4d343fb20d1d")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,30 +0,0 @@
/**
* 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.Tests
{
/**
* Generated constants used in {@link LayoutEngineTest}.
*/
public class TestConstants
{
/** START_GENERATED **/
public static readonly float SMALL_WIDTH = 35f;
public static readonly float SMALL_HEIGHT = 18f;
public static readonly float BIG_WIDTH = 172f;
public static readonly float BIG_HEIGHT = 36f;
public static readonly float BIG_MIN_WIDTH = 100f;
public static readonly string SMALL_TEXT = "small";
public static readonly string LONG_TEXT = "loooooooooong with space";
public static readonly string MEASURE_WITH_RATIO_2 = "measureWithRatio2";
public static readonly string MEASURE_WITH_MATCH_PARENT = "measureWithMatchParent";
/** END_GENERATED **/
}
}

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.6.4" targetFramework="net45" />
</packages>

View File

@@ -1,34 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.CSSLayout", "Facebook.CSSLayout\Facebook.CSSLayout.csproj", "{D534FB4B-A7D4-4A29-96D3-F39A91A259BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.CSSLayout.Tests", "Facebook.CSSLayout.Tests\Facebook.CSSLayout.Tests.csproj", "{E687C8FD-0A0D-450F-853D-EC301BE1C038}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{29A6932B-FDDC-4E8A-8895-7FD64CC47B7F}"
ProjectSection(SolutionItems) = preProject
..\CSharpTranspiler.js = ..\CSharpTranspiler.js
..\JavaTranspiler.js = ..\JavaTranspiler.js
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D534FB4B-A7D4-4A29-96D3-F39A91A259BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D534FB4B-A7D4-4A29-96D3-F39A91A259BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D534FB4B-A7D4-4A29-96D3-F39A91A259BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D534FB4B-A7D4-4A29-96D3-F39A91A259BD}.Release|Any CPU.Build.0 = Release|Any CPU
{E687C8FD-0A0D-450F-853D-EC301BE1C038}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E687C8FD-0A0D-450F-853D-EC301BE1C038}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E687C8FD-0A0D-450F-853D-EC301BE1C038}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E687C8FD-0A0D-450F-853D-EC301BE1C038}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,27 +0,0 @@
/**
* 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.
*/
using System.Diagnostics;
namespace Facebook.CSSLayout
{
static class Assertions
{
public static T assertNotNull<T>(T v) where T : class
{
Debug.Assert(v != null);
return v;
}
public static void assertCondition(bool condition, string explanation)
{
Debug.Assert(condition, explanation);
}
}
}

View File

@@ -1,20 +0,0 @@
/**
* 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 CSSAlign
{
Auto,
FlexStart,
Center,
FlexEnd,
Stretch,
}
}

View File

@@ -1,22 +0,0 @@
/**
* 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

@@ -1,21 +0,0 @@
/**
* 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 static class CSSConstants
{
public const float Undefined = float.NaN;
public static bool IsUndefined(float value)
{
return float.IsNaN(value);
}
}
}

View File

@@ -1,18 +0,0 @@
/**
* 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 CSSDirection
{
Inherit,
LTR,
RTL
}
}

View File

@@ -1,19 +0,0 @@
/**
* 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 CSSFlexDirection
{
Column,
ColumnReverse,
Row,
RowReverse
}
}

View File

@@ -1,20 +0,0 @@
/**
* 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 CSSJustify
{
FlexStart,
Center,
FlexEnd,
SpaceBetween,
SpaceAround
}
}

View File

@@ -1,89 +0,0 @@
/**
* 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
{
/**
* Where the output of {@link LayoutEngine#layoutNode(CSSNode, float)} will go in the CSSNode.
*/
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;
public const int POSITION_BOTTOM = 3;
public const int DIMENSION_WIDTH = 0;
public const int DIMENSION_HEIGHT = 1;
public float[] position = new float[4];
public float[] dimensions = {
CSSConstants.Undefined,
CSSConstants.Undefined
};
public CSSDirection direction = CSSDirection.LTR;
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()
{
FillArray(position, 0);
FillArray(dimensions, CSSConstants.Undefined);
direction = CSSDirection.LTR;
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()
{
return "layout: {" +
"left: " + position[POSITION_LEFT] + ", " +
"top: " + position[POSITION_TOP] + ", " +
"width: " + dimensions[DIMENSION_WIDTH] + ", " +
"height: " + dimensions[DIMENSION_HEIGHT] + ", " +
"direction: " + direction +
"}";
}
static void FillArray<T>(T[] array, T value)
{
for (var i = 0; i != array.Length; ++i)
array[i] = value;
}
}
}

View File

@@ -1,27 +0,0 @@
/**
* 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
{
/**
* A context for holding values local to a given instance of layout computation.
*
* This is necessary for making layout thread-safe. A separate instance should
* be used when {@link CSSNode#calculateLayout} is called concurrently on
* different node hierarchies.
*/
sealed class CSSLayoutContext
{
/*package*/
public MeasureOutput measureOutput = new MeasureOutput();
public int currentGenerationCount;
}
}

View File

@@ -1,18 +0,0 @@
/**
* 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 CSSMeasureMode
{
Undefined,
Exactly,
AtMost,
}
}

View File

@@ -1,558 +0,0 @@
/**
* 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.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Facebook.CSSLayout
{
/**
* Should measure the given node and put the result in the given MeasureOutput.
*/
public delegate MeasureOutput MeasureFunction(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode);
/**
* A CSS Node. It has a style object you can manipulate at {@link #style}. After calling
* {@link #calculateLayout()}, {@link #layout} will be filled with the results of the layout.
*/
public class CSSNode
{
const int POSITION_LEFT = CSSLayout.POSITION_LEFT;
const int POSITION_TOP = CSSLayout.POSITION_TOP;
const int POSITION_RIGHT = CSSLayout.POSITION_RIGHT;
const int POSITION_BOTTOM = CSSLayout.POSITION_BOTTOM;
const int DIMENSION_WIDTH = CSSLayout.DIMENSION_WIDTH;
const int DIMENSION_HEIGHT = CSSLayout.DIMENSION_HEIGHT;
enum LayoutState
{
/**
* Some property of this node or its children has changes and the current values in
* {@link #layout} are not valid.
*/
DIRTY,
/**
* This node has a new layout relative to the last time {@link #MarkLayoutSeen()} was called.
*/
HAS_NEW_LAYOUT,
/**
* {@link #layout} is valid for the node's properties and this layout has been marked as
* having been seen.
*/
UP_TO_DATE,
}
internal readonly CSSStyle style = new CSSStyle();
internal readonly CSSLayout layout = new CSSLayout();
internal readonly CachedCSSLayout lastLayout = new CachedCSSLayout();
internal int lineIndex = 0;
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);
[Nullable] CSSNode mParent;
[Nullable] MeasureFunction mMeasureFunction = null;
LayoutState mLayoutState = LayoutState.DIRTY;
bool mIsTextNode = false;
public int ChildCount
{
get { return mChildren.Count; }
}
public CSSNode this[int i]
{
get { return mChildren[i]; }
}
public IEnumerable<CSSNode> Children
{
get { return mChildren; }
}
public void AddChild(CSSNode child)
{
InsertChild(ChildCount, child);
}
public void InsertChild(int i, CSSNode child)
{
if (child.mParent != null)
{
throw new InvalidOperationException("Child already has a parent, it must be removed first.");
}
mChildren.Insert(i, child);
child.mParent = this;
dirty();
}
public void RemoveChildAt(int i)
{
mChildren[i].mParent = null;
mChildren.RemoveAt(i);
dirty();
}
public CSSNode Parent
{
[return: Nullable]
get
{ return mParent; }
}
/**
* @return the index of the given child, or -1 if the child doesn't exist in this node.
*/
public int IndexOf(CSSNode child)
{
return mChildren.IndexOf(child);
}
public MeasureFunction MeasureFunction
{
get { return mMeasureFunction; }
set
{
if (!valuesEqual(mMeasureFunction, value))
{
mMeasureFunction = value;
dirty();
}
}
}
public bool IsTextNode
{
get { return mIsTextNode; }
set { mIsTextNode = value; }
}
public bool IsMeasureDefined
{
get { return mMeasureFunction != null; }
}
internal MeasureOutput measure(MeasureOutput measureOutput, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode)
{
if (!IsMeasureDefined)
{
throw new Exception("Measure function isn't defined!");
}
return Assertions.assertNotNull(mMeasureFunction)(this, width, widthMode, height, heightMode);
}
/**
* Performs the actual layout and saves the results in {@link #layout}
*/
public void CalculateLayout()
{
LayoutEngine.layoutNode(DummyLayoutContext, this, CSSConstants.Undefined, CSSConstants.Undefined, null);
}
static readonly CSSLayoutContext DummyLayoutContext = new CSSLayoutContext();
/**
* See {@link LayoutState#DIRTY}.
*/
public bool IsDirty
{
get { return mLayoutState == LayoutState.DIRTY; }
}
/**
* See {@link LayoutState#HAS_NEW_LAYOUT}.
*/
public bool HasNewLayout
{
get { return mLayoutState == LayoutState.HAS_NEW_LAYOUT; }
}
internal protected virtual void dirty()
{
if (mLayoutState == LayoutState.DIRTY)
{
return;
}
else if (mLayoutState == LayoutState.HAS_NEW_LAYOUT)
{
throw new InvalidOperationException("Previous layout was ignored! MarkLayoutSeen() never called");
}
mLayoutState = LayoutState.DIRTY;
if (mParent != null)
{
mParent.dirty();
}
}
internal void markHasNewLayout()
{
mLayoutState = LayoutState.HAS_NEW_LAYOUT;
}
/**
* Tells the node that the current values in {@link #layout} have been seen. Subsequent calls
* to {@link #hasNewLayout()} will return false until this node is laid out with new parameters.
* You must call this each time the layout is generated if the node has a new layout.
*/
public void MarkLayoutSeen()
{
if (!HasNewLayout)
{
throw new InvalidOperationException("Expected node to have a new layout to be seen!");
}
mLayoutState = LayoutState.UP_TO_DATE;
}
void toStringWithIndentation(StringBuilder result, int level)
{
// Spaces and tabs are dropped by IntelliJ logcat integration, so rely on __ instead.
StringBuilder indentation = new StringBuilder();
for (int i = 0; i < level; ++i)
{
indentation.Append("__");
}
result.Append(indentation.ToString());
result.Append(layout.ToString());
if (ChildCount == 0)
{
return;
}
result.Append(", children: [\n");
for (var i = 0; i < ChildCount; i++)
{
this[i].toStringWithIndentation(result, level + 1);
result.Append("\n");
}
result.Append(indentation + "]");
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
this.toStringWithIndentation(sb, 0);
return sb.ToString();
}
protected bool valuesEqual(float f1, float f2)
{
return FloatUtil.floatsEqual(f1, f2);
}
protected bool valuesEqual<T>([Nullable] T o1, [Nullable] T o2)
{
if (o1 == null)
{
return o2 == null;
}
return o1.Equals(o2);
}
public CSSDirection Direction
{
get { return style.direction; }
set { updateDiscreteValue(ref style.direction, value); }
}
public CSSFlexDirection FlexDirection
{
get { return style.flexDirection; }
set { updateDiscreteValue(ref style.flexDirection, value); }
}
public CSSJustify JustifyContent
{
get { return style.justifyContent; }
set { updateDiscreteValue(ref style.justifyContent, value); }
}
public CSSAlign AlignContent
{
get { return style.alignContent; }
set { updateDiscreteValue(ref style.alignContent, value); }
}
public CSSAlign AlignItems
{
get { return style.alignItems; }
set { updateDiscreteValue(ref style.alignItems, value); }
}
public CSSAlign AlignSelf
{
get { return style.alignSelf; }
set { updateDiscreteValue(ref style.alignSelf, value); }
}
public CSSPositionType PositionType
{
get { return style.positionType; }
set { updateDiscreteValue(ref style.positionType, value); }
}
public CSSWrap Wrap
{
get { return style.flexWrap; }
set { updateDiscreteValue(ref style.flexWrap, value); }
}
public float Flex
{
get { return style.flex; }
set { updateFloatValue(ref style.flex, value); }
}
public CSSOverflow Overflow
{
get { return style.overflow; }
set { updateDiscreteValue(ref style.overflow, value); }
}
public void SetMargin(CSSSpacingType spacingType, float margin)
{
if (style.margin.set((int)spacingType, margin))
dirty();
}
public float GetMargin(CSSSpacingType spacingType)
{
return style.margin.getRaw((int)spacingType);
}
public void SetPadding(CSSSpacingType spacingType, float padding)
{
if (style.padding.set((int)spacingType, padding))
dirty();
}
public float GetPadding(CSSSpacingType spacingType)
{
return style.padding.getRaw((int)spacingType);
}
public void SetBorder(CSSSpacingType spacingType, float border)
{
if (style.border.set((int)spacingType, border))
dirty();
}
public float GetBorder(CSSSpacingType spacingType)
{
return style.border.getRaw((int)spacingType);
}
public float PositionTop
{
get { return style.position[POSITION_TOP]; }
set { updateFloatValue(ref style.position[POSITION_TOP], value); }
}
public float PositionBottom
{
get { return style.position[POSITION_BOTTOM]; }
set { updateFloatValue(ref style.position[POSITION_BOTTOM], value); }
}
public float PositionLeft
{
get { return style.position[POSITION_LEFT]; }
set { updateFloatValue(ref style.position[POSITION_LEFT], value); }
}
public float PositionRight
{
get { return style.position[POSITION_RIGHT]; }
set { updateFloatValue(ref style.position[POSITION_RIGHT], value); }
}
public float Width
{
get { return style.dimensions[DIMENSION_WIDTH]; }
set { updateFloatValue(ref style.dimensions[DIMENSION_WIDTH], value); }
}
public float Height
{
get { return style.dimensions[DIMENSION_HEIGHT]; }
set { updateFloatValue(ref style.dimensions[DIMENSION_HEIGHT], value); }
}
public float MinWidth
{
get { return style.minWidth; }
set { updateFloatValue(ref style.minWidth, value); }
}
public float MinHeight
{
get { return style.minHeight; }
set { updateFloatValue(ref style.minHeight, value); }
}
public float MaxWidth
{
get { return style.maxWidth; }
set { updateFloatValue(ref style.maxWidth, value); }
}
public float MaxHeight
{
get { return style.maxHeight; }
set { updateFloatValue(ref style.maxHeight, value); }
}
public float LayoutX
{
get { return layout.position[POSITION_LEFT]; }
}
public float LayoutY
{
get { return layout.position[POSITION_TOP]; }
}
public float LayoutWidth
{
get { return layout.dimensions[DIMENSION_WIDTH]; }
}
public float LayoutHeight
{
get { return layout.dimensions[DIMENSION_HEIGHT]; }
}
public CSSDirection LayoutDirection
{
get { return layout.direction; }
}
/**
* Set a default padding (left/top/right/bottom) for this node.
*/
public void SetDefaultPadding(CSSSpacingType spacingType, float padding)
{
if (style.padding.setDefault((int)spacingType, padding))
dirty();
}
void updateDiscreteValue<ValueT>(ref ValueT valueRef, ValueT newValue)
{
if (valuesEqual(valueRef, newValue))
return;
valueRef = newValue;
dirty();
}
void updateFloatValue(ref float valueRef, float newValue)
{
if (valuesEqual(valueRef, newValue))
return;
valueRef = newValue;
dirty();
}
}
public static class CSSNodeExtensions
{
/*
Explicitly mark this node as dirty.
Calling this function is required when the measure function points to the same instance,
but changes its behavior.
For all other property changes, the node is automatically marked dirty.
*/
public static void MarkDirty(this CSSNode node)
{
node.dirty();
}
}
internal static class CSSNodeExtensionsInternal
{
public static CSSNode getParent(this CSSNode node)
{
return node.Parent;
}
public static int getChildCount(this CSSNode node)
{
return node.ChildCount;
}
public static CSSNode getChildAt(this CSSNode node, int i)
{
return node[i];
}
public static void addChildAt(this CSSNode node, CSSNode child, int i)
{
node.InsertChild(i, child);
}
public static void removeChildAt(this CSSNode node, int i)
{
node.RemoveChildAt(i);
}
public static void setMeasureFunction(this CSSNode node, MeasureFunction measureFunction)
{
node.MeasureFunction = measureFunction;
}
public static void setIsTextNode(this CSSNode node, bool isTextNode)
{
node.IsTextNode = isTextNode;
}
public static void calculateLayout(this CSSNode node)
{
node.CalculateLayout();
}
public static bool isDirty(this CSSNode node)
{
return node.IsDirty;
}
public static void setMargin(this CSSNode node, int spacingType, float margin)
{
node.SetMargin((CSSSpacingType)spacingType, margin);
}
public static void setPadding(this CSSNode node, int spacingType, float padding)
{
node.SetPadding((CSSSpacingType)spacingType, padding);
}
public static void setBorder(this CSSNode node, int spacingType, float border)
{
node.SetBorder((CSSSpacingType)spacingType, border);
}
}
}

View File

@@ -1,17 +0,0 @@
/**
* 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

@@ -1,17 +0,0 @@
/**
* 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 CSSPositionType
{
Relative,
Absolute
}
}

View File

@@ -1,24 +0,0 @@
/**
* 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 CSSSpacingType
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3,
Vertical = 4,
Horizontal = 5,
Start = 6,
End = 7,
All = 8
}
}

View File

@@ -1,50 +0,0 @@
/**
* 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
{
/**
* The CSS style definition for a {@link CSSNode}.
*/
sealed class CSSStyle
{
public CSSDirection direction = CSSDirection.Inherit;
public CSSFlexDirection flexDirection = CSSFlexDirection.Column;
public CSSJustify justifyContent = CSSJustify.FlexStart;
public CSSAlign alignContent = CSSAlign.FlexStart;
public CSSAlign alignItems = CSSAlign.Stretch;
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();
public Spacing padding = new Spacing();
public Spacing border = new Spacing();
public float[] position = {
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined
};
public float[] dimensions = {
CSSConstants.Undefined,
CSSConstants.Undefined
};
public float minWidth = CSSConstants.Undefined;
public float minHeight = CSSConstants.Undefined;
public float maxWidth = CSSConstants.Undefined;
public float maxHeight = CSSConstants.Undefined;
}
}

View File

@@ -1,16 +0,0 @@
/**
* 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 CSSWrap
{
NoWrap,
Wrap
}
}

View File

@@ -1,25 +0,0 @@
/**
* 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
{
/**
* CSSLayout with additional information about the conditions under which it was generated.
* {@link #RequestedWidth} and {@link #RequestedHeight} are the width and height the parent set on
* this node before calling layout visited us.
*/
class CachedCSSLayout : CSSLayout
{
public float requestedWidth = CSSConstants.Undefined;
public float requestedHeight = CSSConstants.Undefined;
public float parentMaxWidth = CSSConstants.Undefined;
public float parentMaxHeight = CSSConstants.Undefined;
}
}

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D534FB4B-A7D4-4A29-96D3-F39A91A259BD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Facebook.CSSLayout</RootNamespace>
<AssemblyName>Facebook.CSSLayout</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile259</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>5</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<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="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" />
<Compile Include="FloatUtil.cs" />
<Compile Include="LayoutEngine.cs" />
<Compile Include="MeasureOutput.cs" />
<Compile Include="NullableAttribute.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Spacing.cs" />
<Compile Include="CSSSpacingType.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<title>$title$</title>
<authors>$author$</authors>
<owners>$author$</owners>
<licenseUrl>https://github.com/facebook/css-layout/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/facebook/css-layout</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<releaseNotes></releaseNotes>
<copyright>Copyright 2015 Facebook</copyright>
<tags>flexbox flex-box css layout css-layout facebook</tags>
</metadata>
</package>

View File

@@ -1,27 +0,0 @@
/**
* 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.
*/
using System;
namespace Facebook.CSSLayout
{
static class FloatUtil
{
const float Epsilon = .00001f;
public static bool floatsEqual(float f1, float f2)
{
if (float.IsNaN(f1) || float.IsNaN(f2))
{
return float.IsNaN(f1) && float.IsNaN(f2);
}
return Math.Abs(f2 - f1) < Epsilon;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +0,0 @@
/**
* 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
{
/**
* POJO to hold the output of the measure function.
*/
public struct MeasureOutput
{
public MeasureOutput(float width, float height)
{
Width = width;
Height = height;
}
public readonly float Width;
public readonly float Height;
internal float width
{
get { return Width; }
}
internal float height
{
get { return Height; }
}
}
}

View File

@@ -1,22 +0,0 @@
/**
* 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.
*/
using System;
namespace Facebook.CSSLayout
{
/**
* This is here to preserve the @nullable attribute of the original Java API.
*/
[AttributeUsage(AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.Parameter)]
sealed class NullableAttribute : Attribute
{
}
}

View File

@@ -1,27 +0,0 @@
/**
* 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.
*/
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("Facebook.CSSLayout")]
[assembly: AssemblyDescription("A subset of CSS's flexbox layout algorithm and box model.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Facebook")]
[assembly: AssemblyProduct("Facebook.CSSLayout")]
[assembly: AssemblyCopyright("Copyright © 2015 Facebook")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("Facebook.CSSLayout.Tests")]

View File

@@ -1,234 +0,0 @@
/**
* 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
{
/**
* Class representing CSS spacing (padding, margin, and borders). This is mostly necessary to
* properly implement interactions and updates for properties like margin, marginLeft, and
* marginHorizontal.
*/
sealed class Spacing
{
/**
* Spacing type that represents the left direction. E.g. {@code marginLeft}.
*/
internal const int LEFT = (int)CSSSpacingType.Left;
/**
* Spacing type that represents the top direction. E.g. {@code marginTop}.
*/
internal const int TOP = (int)CSSSpacingType.Top;
/**
* Spacing type that represents the right direction. E.g. {@code marginRight}.
*/
internal const int RIGHT = (int)CSSSpacingType.Right;
/**
* Spacing type that represents the bottom direction. E.g. {@code marginBottom}.
*/
internal const int BOTTOM = (int)CSSSpacingType.Bottom;
/**
* Spacing type that represents vertical direction (top and bottom). E.g. {@code marginVertical}.
*/
internal const int VERTICAL = (int)CSSSpacingType.Vertical;
/**
* Spacing type that represents horizontal direction (left and right). E.g.
* {@code marginHorizontal}.
*/
internal const int HORIZONTAL = (int)CSSSpacingType.Horizontal;
/**
* Spacing type that represents start direction e.g. left in left-to-right, right in right-to-left.
*/
internal const int START = (int)CSSSpacingType.Start;
/**
* Spacing type that represents end direction e.g. right in left-to-right, left in right-to-left.
*/
internal const int END = (int)CSSSpacingType.End;
/**
* Spacing type that represents all directions (left, top, right, bottom). E.g. {@code margin}.
*/
internal const int ALL = (int)CSSSpacingType.All;
static readonly int[] sFlagsMap = {
1, /*LEFT*/
2, /*TOP*/
4, /*RIGHT*/
8, /*BOTTOM*/
16, /*VERTICAL*/
32, /*HORIZONTAL*/
64, /*START*/
128, /*END*/
256 /*ALL*/
};
float[] mSpacing = newFullSpacingArray();
[Nullable] float[] mDefaultSpacing = null;
int mValueFlags = 0;
bool mHasAliasesSet;
/**
* Set a spacing value.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM},
* {@link #VERTICAL}, {@link #HORIZONTAL}, {@link #ALL}
* @param value the value for this direction
* @return {@code true} if the spacing has changed, or {@code false} if the same value was already
* set
*/
internal bool set(int spacingType, float value)
{
if (!FloatUtil.floatsEqual(mSpacing[spacingType], value))
{
mSpacing[spacingType] = value;
if (CSSConstants.IsUndefined(value))
{
mValueFlags &= ~sFlagsMap[spacingType];
}
else
{
mValueFlags |= sFlagsMap[spacingType];
}
mHasAliasesSet =
(mValueFlags & sFlagsMap[ALL]) != 0 ||
(mValueFlags & sFlagsMap[VERTICAL]) != 0 ||
(mValueFlags & sFlagsMap[HORIZONTAL]) != 0;
return true;
}
return false;
}
/**
* Set a default spacing value. This is used as a fallback when no spacing has been set for a
* particular direction.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM}
* @param value the default value for this direction
* @return
*/
internal bool setDefault(int spacingType, float value)
{
if (mDefaultSpacing == null)
mDefaultSpacing = newSpacingResultArray();
if (!FloatUtil.floatsEqual(mDefaultSpacing[spacingType], value))
{
mDefaultSpacing[spacingType] = value;
return true;
}
return false;
}
/**
* Get the spacing for a direction. This takes into account any default values that have been set.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM}
*/
internal float get(int spacingType)
{
float defaultValue =
(mDefaultSpacing != null)
? mDefaultSpacing[spacingType]
: (spacingType == START || spacingType == END ? CSSConstants.Undefined : 0);
if (mValueFlags == 0)
{
return defaultValue;
}
if ((mValueFlags & sFlagsMap[spacingType]) != 0)
{
return mSpacing[spacingType];
}
if (mHasAliasesSet)
{
int secondType = spacingType == TOP || spacingType == BOTTOM ? VERTICAL : HORIZONTAL;
if ((mValueFlags & sFlagsMap[secondType]) != 0)
{
return mSpacing[secondType];
}
else if ((mValueFlags & sFlagsMap[ALL]) != 0)
{
return mSpacing[ALL];
}
}
return defaultValue;
}
/**
* Get the raw value (that was set using {@link #set(int, float)}), without taking into account
* any default values.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM},
* {@link #VERTICAL}, {@link #HORIZONTAL}, {@link #ALL}
*/
internal float getRaw(int spacingType)
{
return mSpacing[spacingType];
}
/**
* Try to get start value and fallback to given type if not defined. This is used privately
* by the layout engine as a more efficient way to fetch direction-aware values by
* avoid extra method invocations.
*/
internal float getWithFallback(int spacingType, int fallbackType)
{
return
(mValueFlags & sFlagsMap[spacingType]) != 0
? mSpacing[spacingType]
: get(fallbackType);
}
static float[] newFullSpacingArray()
{
return new[]
{
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined,
CSSConstants.Undefined
};
}
static float[] newSpacingResultArray()
{
return newSpacingResultArray(0);
}
static float[] newSpacingResultArray(float defaultValue)
{
return new[]
{
defaultValue,
defaultValue,
defaultValue,
defaultValue,
defaultValue,
defaultValue,
CSSConstants.Undefined,
CSSConstants.Undefined,
defaultValue
};
}
}
}

View File

@@ -1,37 +0,0 @@
MSB=msbuild.exe /m /verbosity:m /nologo
NUGET=nuget.exe
NUNITC=nunit-console.exe
VER=1.0.0
NAME=Facebook.CSSLayout
.PHONY: all
all: test
.PHONY: distribute
distribute: package release-package
.PHONY: package
package: conf=Release
package: build
cd ${NAME} && ${NUGET} pack ${NAME}.csproj -Version ${VER} -Prop Configuration=${conf}
.PHONY: release-package
release-package:
cd ${NAME} && nuget push ${NAME}.${VER}.nupkg
.PHONY: test
test: build-debug
cd ${NAME}.Tests/bin/Debug && ${NUNITC} Facebook.CSSLayout.Tests.dll
.PHONY: build-debug
build-debug: conf=Debug
build-debug: build
.PHONY: build-release
build-release: conf=Release
build-release: build
.PHONY: build
build:
${MSB} ${NAME}.sln /p:Configuration=${conf} /t:"Facebook_CSSLayout:Rebuild;Facebook_CSSLayout_Tests:Rebuild"

View File

@@ -1,29 +0,0 @@
// UMD (Universal Module Definition)
// See https://github.com/umdjs/umd for reference
//
// This file uses the following specific UMD implementation:
// https://github.com/umdjs/umd/blob/master/templates/returnExports.js
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory);
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
} else {
// Browser globals (root is window)
root.computeLayout = factory();
}
}(this, function() {
// @@include('./Layout.js')
return function(node) {
/*eslint-disable */
// disabling ESLint because this code relies on the above include
computeLayout.fillNodes(node);
computeLayout.computeLayout(node);
/*eslint-enable */
};
}));

1
java/java/.idea/.name generated
View File

@@ -1 +0,0 @@
css-layout

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<option name="DEFAULT_COMPILER" value="Javac" />
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>

View File

@@ -1,5 +0,0 @@
<component name="CopyrightManager">
<settings default="">
<module2copyright />
</settings>
</component>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/java.iml" filepath="$PROJECT_DIR$/java.iml" />
</modules>
</component>
</project>

View File

@@ -1,5 +0,0 @@
<component name="DependencyValidationManager">
<state>
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</state>
</component>

View File

@@ -1,125 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="" />
</component>
</project>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$APPLICATION_HOME_DIR$/lib/junit-4.10.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>

Binary file not shown.

Binary file not shown.

View File

@@ -1,50 +0,0 @@
/**
* 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;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Tests for {@link CSSNode}.
*/
public class CSSNodeTest {
@Test
public void testAddChildGetParent() {
CSSNode parent = new CSSNode();
CSSNode child = new CSSNode();
assertNull(child.getParent());
assertEquals(0, parent.getChildCount());
parent.addChildAt(child, 0);
assertEquals(1, parent.getChildCount());
assertEquals(child, parent.getChildAt(0));
assertEquals(parent, child.getParent());
parent.removeChildAt(0);
assertNull(child.getParent());
assertEquals(0, parent.getChildCount());
}
@Test(expected = IllegalStateException.class)
public void testCannotAddChildToMultipleParents() {
CSSNode parent1 = new CSSNode();
CSSNode parent2 = new CSSNode();
CSSNode child = new CSSNode();
parent1.addChildAt(child, 0);
parent2.addChildAt(child, 0);
}
}

View File

@@ -1,240 +0,0 @@
/**
* 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;
import org.junit.Test;
import static junit.framework.Assert.*;
/**
* Tests for {@link LayoutEngine} and {@link CSSNode} to make sure layouts are only generated when
* needed.
*/
public class LayoutCachingTest {
private void assertTreeHasNewLayout(boolean expectedHasNewLayout, CSSNode root) {
assertEquals(expectedHasNewLayout, root.hasNewLayout());
for (int i = 0; i < root.getChildCount(); i++) {
assertTreeHasNewLayout(expectedHasNewLayout, root.getChildAt(i));
}
}
private void markLayoutAppliedForTree(CSSNode root) {
root.markLayoutSeen();
for (int i = 0; i < root.getChildCount(); i++) {
markLayoutAppliedForTree(root.getChildAt(i));
}
}
@Test
public void testCachesFullTree() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout(layoutContext);
assertTreeHasNewLayout(true, root);
markLayoutAppliedForTree(root);
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTreeHasNewLayout(false, c0);
assertTreeHasNewLayout(false, c1);
}
@Test
public void testInvalidatesCacheWhenChildAdded() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
CSSNode c0c1 = new CSSNode();
CSSNode c1c0 = new CSSNode();
c0c1.setStyleWidth(200);
c0c1.setStyleHeight(200);
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
c0c0.addChildAt(c1c0, 0);
root.calculateLayout(layoutContext);
markLayoutAppliedForTree(root);
c0.addChildAt(c0c1, 1);
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTrue(c0.hasNewLayout());
assertTrue(c0c1.hasNewLayout());
assertTrue(c0c0.hasNewLayout());
assertTrue(c1.hasNewLayout());
assertTrue(c1c0.hasNewLayout());
}
@Test
public void testInvalidatesCacheWhenEnumPropertyChanges() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout(layoutContext);
markLayoutAppliedForTree(root);
c1.setAlignSelf(CSSAlign.CENTER);
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTrue(c1.hasNewLayout());
assertTrue(c0.hasNewLayout());
assertFalse(c0c0.hasNewLayout());
}
@Test
public void testInvalidatesCacheWhenFloatPropertyChanges() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout(layoutContext);
markLayoutAppliedForTree(root);
c1.setMargin(Spacing.LEFT, 10);
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTrue(c1.hasNewLayout());
assertTrue(c0.hasNewLayout());
assertTrue(c0c0.hasNewLayout());
}
@Test
public void testInvalidatesFullTreeWhenParentWidthChanges() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
CSSNode c1c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
c1.addChildAt(c1c0, 0);
root.calculateLayout(layoutContext);
markLayoutAppliedForTree(root);
c0.setStyleWidth(200);
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTrue(c0.hasNewLayout());
assertTrue(c0c0.hasNewLayout());
assertTrue(c1.hasNewLayout());
assertTrue(c1c0.hasNewLayout());
}
@Test
public void testDoesNotInvalidateCacheWhenPropertyIsTheSame() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.setStyleWidth(200);
root.calculateLayout(layoutContext);
markLayoutAppliedForTree(root);
root.setStyleWidth(200);
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTreeHasNewLayout(false, c0);
assertTreeHasNewLayout(false, c1);
}
@Test
public void testInvalidateCacheWhenHeightChangesPosition() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c1c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c1.addChildAt(c1c0, 0);
root.calculateLayout(layoutContext);
markLayoutAppliedForTree(root);
c0.setStyleHeight(100);
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTrue(c0.hasNewLayout());
assertTrue(c1.hasNewLayout());
assertFalse(c1c0.hasNewLayout());
}
@Test
public void testInvalidatesOnNewMeasureFunction() {
CSSLayoutContext layoutContext = new CSSLayoutContext();
CSSNode root = new CSSNode();
CSSNode c0 = new CSSNode();
CSSNode c1 = new CSSNode();
CSSNode c0c0 = new CSSNode();
root.addChildAt(c0, 0);
root.addChildAt(c1, 1);
c0.addChildAt(c0c0, 0);
root.calculateLayout(layoutContext);
markLayoutAppliedForTree(root);
c1.setMeasureFunction(new CSSNode.MeasureFunction() {
@Override
public void measure(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode, MeasureOutput measureOutput) {
measureOutput.width = 100;
measureOutput.height = 20;
}
});
root.calculateLayout(layoutContext);
assertTrue(root.hasNewLayout());
assertTrue(c1.hasNewLayout());
assertTrue(c0.hasNewLayout());
assertTrue(c0c0.hasNewLayout());
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +0,0 @@
/**
* 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;
/**
* Generated constants used in {@link LayoutEngineTest}.
*/
public class TestConstants {
/** START_GENERATED **/
public static final float SMALL_WIDTH = 35f;
public static final float SMALL_HEIGHT = 18f;
public static final float BIG_WIDTH = 172f;
public static final float BIG_HEIGHT = 36f;
public static final float BIG_MIN_WIDTH = 100f;
public static final String SMALL_TEXT = "small";
public static final String LONG_TEXT = "loooooooooong with space";
public static final String MEASURE_WITH_RATIO_2 = "measureWithRatio2";
public static final String MEASURE_WITH_MATCH_PARENT = "measureWithMatchParent";
/** END_GENERATED **/
}

View File

@@ -1,349 +0,0 @@
/**
* 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.
*/
var layoutTestUtils = require('./Layout-test-utils.js');
var computeLayout = require('./Layout.js').layoutNodeImpl;
var fs = require('fs');
var JavaTranspiler = require('./JavaTranspiler.js');
var CSharpTranspiler = require('./CSharpTranspiler.js');
var currentTest = '';
var allTests = [];
var computeDOMLayout = layoutTestUtils.computeDOMLayout;
var reduceTest = layoutTestUtils.reduceTest;
global.layoutTestUtils = {
testLayout: function(node, expectedLayout) {
allTests.push({name: currentTest, node: node, expectedLayout: expectedLayout});
},
testLayoutAgainstDomOnly: function() {
},
testRandomLayout: function(node, i) {
allTests.push({name: 'Random #' + i, node: node, expectedLayout: computeDOMLayout(node)});
},
testLayoutAgainstExpectedOnly: function(node, expectedLayout) {
allTests.push({name: currentTest, node: node, expectedLayout: expectedLayout});
},
computeLayout: layoutTestUtils.computeLayout,
reduceTest: reduceTest,
text: layoutTestUtils.text,
texts: layoutTestUtils.texts,
textSizes: layoutTestUtils.textSizes,
measureWithRatio2: layoutTestUtils.measureWithRatio2,
measureWithMatchParent: layoutTestUtils.measureWithMatchParent
};
global.describe = function(name, cb) {
if (name.toLowerCase().indexOf('javascript only') === -1) {
cb();
}
};
global.it = function(name, cb) { currentTest = name; cb(); };
global.xit = function() { /* ignore skipped tests */ };
require('./__tests__/Layout-test.js');
function printLayout(test) {
var level = 1;
var res = [];
function indent(level) {
var result = '';
for (var i = 0; i < level; ++i) {
result += ' ';
}
return result;
}
function add(str) {
if (str.length > 0) {
str = indent(level) + str;
}
res.push(str);
}
function isEmpty(obj) {
return !Object.keys(obj).length;
}
add('{');
level++;
// Output the style node
add('css_node_t *root_node = new_test_css_node();');
add('{');
level++;
if (!isEmpty(test.node.style) || test.node.children && test.node.children.length) {
add('css_node_t *node_0 = root_node;');
}
function recStyle(node) {
function addStyle(str) {
add('node_' + (level - 3) + '->style.' + str);
}
function addEnum(node, jsKey, cKey, dict) {
if (jsKey in node.style) {
addStyle(cKey + ' = ' + dict[node.style[jsKey]] + ';');
}
}
function addFloat(node, jsKey, cKey) {
if (jsKey in node.style) {
addStyle(cKey + ' = ' + node.style[jsKey] + ';');
}
}
function addSpacing(node, spacing, suffix) {
addFloat(node, spacing + suffix, spacing + '[CSS_LEFT]');
addFloat(node, spacing + suffix, spacing + '[CSS_TOP]');
addFloat(node, spacing + suffix, spacing + '[CSS_RIGHT]');
addFloat(node, spacing + suffix, spacing + '[CSS_BOTTOM]');
addFloat(node, spacing + suffix, spacing + '[CSS_START]');
addFloat(node, spacing + suffix, spacing + '[CSS_END]');
addFloat(node, spacing + 'Left' + suffix, spacing + '[CSS_LEFT]');
addFloat(node, spacing + 'Top' + suffix, spacing + '[CSS_TOP]');
addFloat(node, spacing + 'Right' + suffix, spacing + '[CSS_RIGHT]');
addFloat(node, spacing + 'Bottom' + suffix, spacing + '[CSS_BOTTOM]');
addFloat(node, spacing + 'Start' + suffix, spacing + '[CSS_START]');
addFloat(node, spacing + 'End' + suffix, spacing + '[CSS_END]');
}
function addMeasure(node) {
if ('measure' in node.style) {
if (node.children && node.children.length) {
throw new Error('Using custom measure function is supported only for leaf nodes.');
}
add('node_' + (level - 3) + '->measure = measure;');
add('node_' + (level - 3) + '->context = "' + node.style.measure.toString() + '";');
}
}
addEnum(node, 'direction', 'direction', {
'ltr': 'CSS_DIRECTION_LTR',
'rtl': 'CSS_DIRECTION_RTL'
});
addEnum(node, 'flexDirection', 'flex_direction', {
'row': 'CSS_FLEX_DIRECTION_ROW',
'row-reverse': 'CSS_FLEX_DIRECTION_ROW_REVERSE',
'column': 'CSS_FLEX_DIRECTION_COLUMN',
'column-reverse': 'CSS_FLEX_DIRECTION_COLUMN_REVERSE'
});
addEnum(node, 'justifyContent', 'justify_content', {
'flex-start': 'CSS_JUSTIFY_FLEX_START',
'center': 'CSS_JUSTIFY_CENTER',
'flex-end': 'CSS_JUSTIFY_FLEX_END',
'space-between': 'CSS_JUSTIFY_SPACE_BETWEEN',
'space-around': 'CSS_JUSTIFY_SPACE_AROUND'
});
addEnum(node, 'alignContent', 'align_content', {
'flex-start': 'CSS_ALIGN_FLEX_START',
'center': 'CSS_ALIGN_CENTER',
'flex-end': 'CSS_ALIGN_FLEX_END',
'stretch': 'CSS_ALIGN_STRETCH'
});
addEnum(node, 'alignItems', 'align_items', {
'flex-start': 'CSS_ALIGN_FLEX_START',
'center': 'CSS_ALIGN_CENTER',
'flex-end': 'CSS_ALIGN_FLEX_END',
'stretch': 'CSS_ALIGN_STRETCH'
});
addEnum(node, 'alignSelf', 'align_self', {
'flex-start': 'CSS_ALIGN_FLEX_START',
'center': 'CSS_ALIGN_CENTER',
'flex-end': 'CSS_ALIGN_FLEX_END',
'stretch': 'CSS_ALIGN_STRETCH'
});
addEnum(node, 'position', 'position_type', {
'relative': 'CSS_POSITION_RELATIVE',
'absolute': 'CSS_POSITION_ABSOLUTE'
});
addEnum(node, 'flexWrap', 'flex_wrap', {
'nowrap': 'CSS_NOWRAP',
'wrap': 'CSS_WRAP'
});
addEnum(node, 'measureMode', 'measure_mode', {
'undefined': 'CSS_MEASURE_MODE_UNDEFINED',
'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]');
addFloat(node, 'maxWidth', 'maxDimensions[CSS_WIDTH]');
addFloat(node, 'maxHeight', 'maxDimensions[CSS_HEIGHT]');
addFloat(node, 'minWidth', 'minDimensions[CSS_WIDTH]');
addFloat(node, 'minHeight', 'minDimensions[CSS_HEIGHT]');
addSpacing(node, 'margin', '');
addSpacing(node, 'padding', '');
addSpacing(node, 'border', 'Width');
addFloat(node, 'left', 'position[CSS_LEFT]');
addFloat(node, 'top', 'position[CSS_TOP]');
addFloat(node, 'right', 'position[CSS_RIGHT]');
addFloat(node, 'bottom', 'position[CSS_BOTTOM]');
addMeasure(node);
if (node.children) {
add('init_css_node_children(node_' + (level - 3) + ', ' + node.children.length + ');');
add('{');
level++;
add('css_node_t *node_' + (level - 3) + ';');
for (var i = 0; i < node.children.length; ++i) {
add('node_' + (level - 3) + ' = node_' + (level - 4) + '->get_child(node_' + (level - 4) + '->context, ' + i + ');');
recStyle(node.children[i]);
}
level--;
add('}');
}
}
recStyle(test.node);
level--;
add('}');
add('');
// Output the expected layout node
add('css_node_t *root_layout = new_test_css_node();');
add('{');
level++;
add('css_node_t *node_0 = root_layout;');
function recLayout(node) {
function addLayout(str) {
add('node_' + (level - 3) + '->layout.' + str);
}
addLayout('position[CSS_TOP] = ' + node.top + ';');
addLayout('position[CSS_LEFT] = ' + node.left + ';');
addLayout('dimensions[CSS_WIDTH] = ' + node.width + ';');
addLayout('dimensions[CSS_HEIGHT] = ' + node.height + ';');
if (node.children) {
add('init_css_node_children(node_' + (level - 3) + ', ' + node.children.length + ');');
add('{');
level++;
add('css_node_t *node_' + (level - 3) + ';');
for (var i = 0; i < node.children.length; ++i) {
add('node_' + (level - 3) + ' = node_' + (level - 4) + '->get_child(node_' + (level - 4) + '->context, ' + i + ');');
recLayout(node.children[i]);
}
level--;
add('}');
}
}
recLayout(test.expectedLayout);
level--;
add('}');
add('');
// Do the test
add('test("' + test.name.replace(/"/g, '\\"') + '", root_node, root_layout);');
level--;
add('}');
return res.join('\n');
}
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(/undefined/g, 'NULL')
.replace(/\.children\.length/g, '.children_count')
.replace(/\.width/g, '.dimensions[CSS_WIDTH]')
.replace(/\.height/g, '.dimensions[CSS_HEIGHT]')
.replace(/\.maxWidth/g, '.maxDimensions[CSS_WIDTH]')
.replace(/\.maxHeight/g, '.maxDimensions[CSS_HEIGHT]')
.replace(/\.minWidth/g, '.minDimensions[CSS_WIDTH]')
.replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]')
.replace(/\.lineIndex/g, '.line_index')
.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\[j\]/g, 'node->get_child(node->context, j)')
.replace(/node\./g, 'node->')
.replace(/child\./g, 'child->')
.replace(/currentAbsoluteChild\./g, 'currentAbsoluteChild->')
.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, ' == ')
.replace(/ !== /g, ' != ')
.replace(/\n {2}/g, '\n')
.replace(/\/\*\(c\)!([^*]+)\*\//g, '$1')
.replace(/\/[*]!([^*]+)[*]\//g, '$1')
.replace(/\/\*\(java\)!([^*]+)\*\//g, '');
}
function makeConstDefs() {
var lines = [
'#define SMALL_WIDTH ' + layoutTestUtils.textSizes.smallWidth,
'#define SMALL_HEIGHT ' + layoutTestUtils.textSizes.smallHeight,
'#define BIG_WIDTH ' + layoutTestUtils.textSizes.bigWidth,
'#define BIG_HEIGHT ' + layoutTestUtils.textSizes.bigHeight,
'#define BIG_MIN_WIDTH ' + layoutTestUtils.textSizes.bigMinWidth,
'#define SMALL_TEXT "' + layoutTestUtils.texts.small + '"',
'#define LONG_TEXT "' + layoutTestUtils.texts.big + '"',
'#define MEASURE_WITH_RATIO_2 "' + layoutTestUtils.measureWithRatio2() + '"',
'#define MEASURE_WITH_MATCH_PARENT "' + layoutTestUtils.measureWithMatchParent() + '"'
];
return lines.join('\n');
}
function generateFile(fileName, generatedContent) {
var content = fs.readFileSync(fileName, 'utf8').toString();
content = content.replace(new RegExp(
/\/\*\* START_GENERATED \*\*\/[\s\S]*\/\*\* END_GENERATED \*\*\//
), '/** START_GENERATED **/\n' + generatedContent + '\n /** END_GENERATED **/');
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(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(computeLayoutCode));
generateFile(__dirname + '/csharp/Facebook.CSSLayout.Tests/TestConstants.cs', CSharpTranspiler.transpileCConstDefs(makeConstDefs()));
generateFile(__dirname + '/csharp/Facebook.CSSLayout.Tests/LayoutEngineTest.cs', CSharpTranspiler.transpileCTestsArray(allTestsInC));