diff --git a/.gitignore b/.gitignore index cba7efc8..678859b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ a.out +*.class +/**/java/out/* +/**/.idea/workspace.xml diff --git a/Makefile b/Makefile index f0711fe6..046f6597 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,26 @@ FILES=src/__tests__/Layout-test.c src/Layout.c src/Layout-test-utils.c -all: c test +all: c c_test java java_test -c: - @node ./src/transpile.js +c: transpile_all -test: +c_test: c @gcc -std=c99 -Werror -Wno-padded $(FILES) -lm && ./a.out @rm a.out +java: transpile_all src/java + @javac -cp ./lib/junit4.jar -sourcepath ./src/java/src:./src/java/tests src/java/tests/com/facebook/csslayout/*.java + +java_test: java + @java -cp ./src/java/src:./src/java/tests:./lib/junit4.jar org.junit.runner.JUnitCore \ + com.facebook.csslayout.LayoutEngineTest \ + com.facebook.csslayout.LayoutCachingTest \ + com.facebook.csslayout.CSSNodeTest + +transpile_all: ./src/transpile.js + @node ./src/transpile.js + debug: @gcc -ggdb $(FILES) -lm && lldb ./a.out @rm a.out diff --git a/lib/junit4.jar b/lib/junit4.jar new file mode 100644 index 00000000..954851e6 Binary files /dev/null and b/lib/junit4.jar differ diff --git a/src/JavaTranspiler.js b/src/JavaTranspiler.js new file mode 100644 index 00000000..9d35526f --- /dev/null +++ b/src/JavaTranspiler.js @@ -0,0 +1,110 @@ +function __transpileToJavaCommon(code) { + return code + .replace(/CSS_UNDEFINED/g, 'CSSConstants.UNDEFINED') + .replace(/css_flex_direction_t/g, 'CSSFlexDirection') + .replace(/CSS_FLEX_DIRECTION_/g, 'CSSFlexDirection.') + .replace(/css_align_t/g, 'CSSAlign') + .replace(/CSS_ALIGN_/g, 'CSSAlign.') + .replace(/CSS_POSITION_/g, 'CSSPositionType.') + .replace(/css_justify_t/g, 'CSSJustify') + .replace(/CSS_JUSTIFY_/g, 'CSSJustify.') + .replace(/css_dim_t/g, 'MeasureOutput') + .replace(/bool/g, 'boolean') + .replace(/^(\s+)([^\s]+)\s+\+=/gm, '$1$2 = $2 +') // Expand += + .replace(/leading\[([^\]]+)\]/g, 'getLeading($1)') + .replace(/trailing\[([^\]]+)\]/g, 'getTrailing($1)') + .replace(/pos\[([^\]]+)\]/g, 'getPos($1)') + .replace(/dim\[([^\]]+)\]/g, 'getDim($1)') + .replace(/isUndefined/g, 'FloatUtil.isUndefined') + + // Since Java doesn't store its attributes in arrays, we need to use setters/getters to access + // the appropriate layout/style fields + .replace( + /(\w+)\.layout\[((?:getLeading|getPos)\([^\)]+\))\]\s+=\s+([^;]+);/gm, + 'setLayoutPosition($1, $2, $3);') + .replace(/(\w+)\.layout\[((?:getLeading|getPos)\([^\]]+\))\]/g, 'getLayoutPosition($1, $2)') + .replace( + /(\w+)\.layout\[(getDim\([^\)]+\))\]\s+=\s+([^;]+);/gm, + 'setLayoutDimension($1, $2, $3);') + .replace(/(\w+)\.layout\[(getDim\([^\]]+\))\]/g, 'getLayoutDimension($1, $2)') + .replace(/(\w+)\.style\[((?:getLeading|getPos)\([^\]]+\))\]/g, 'getStylePosition($1, $2)') + .replace(/(\w+)\.style\[(getDim\([^\]]+\))\]/g, 'getStyleDimension($1, $2)'); +} + +function __transpileSingleTestToJava(code) { + return __transpileToJavaCommon(code) + .replace(/new_test_css_node/g, 'new TestCSSNode') + .replace( // style.dimensions[CSS_WIDTH] => style.width + /(style|layout)\.dimensions\[CSS_(WIDTH|HEIGHT)\]/g, + function (str, match1, match2) { + return match1 + '.' + match2.toLowerCase(); + }) + .replace( // layout.position[CSS_TOP] => layout.y + /layout\.position\[CSS_(TOP|LEFT)\]/g, + function (str, match1) { + return 'layout.' + (match1 == 'TOP' ? 'y' : 'x'); + }) + .replace( // style.position[CSS_TOP] => style.positionTop + /style\.(position|margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT)\]/g, + function (str, match1, match2) { + return 'style.' + match1 + match2[0] + match2.substring(1).toLowerCase(); + }) + .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+.+/, '$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(/function\s+layoutNode.*/, '') + .replace('node.style.measure', 'node.measure') + .replace(/\.children\.length/g, '.getChildCount()') + .replace(/node.children\[i\]/g, 'node.getChildAt(i)') + .replace(/fmaxf/g, 'Math.max') + .replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages + .replace(/var\/\*([^\/]+)\*\//g, '$1') + .replace(/ === /g, ' == ') + .replace(/\n /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; +} diff --git a/src/Layout.c b/src/Layout.c index 6118b2e6..0e3c9fea 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -398,7 +398,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both // left and right or top and bottom). for (int ii = 0; ii < 2; ii++) { - css_flex_direction_t axis = ii ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; if (!isUndefined(node->layout.dimensions[dim[axis]]) && !isDimDefined(child, axis) && isPosDefined(child, leading[axis]) && @@ -491,7 +491,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // If there are flexible children in the mix, they are going to fill the // remaining space - if (flexibleChildrenCount) { + if (flexibleChildrenCount != 0) { float flexibleMainDim = remainingMainDim / totalFlexible; // The non flexible children can overflow the container, in this case @@ -675,7 +675,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both // left and right or top and bottom). for (int ii = 0; ii < 2; ii++) { - css_flex_direction_t axis = ii ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; if (!isUndefined(node->layout.dimensions[dim[axis]]) && !isDimDefined(child, axis) && isPosDefined(child, leading[axis]) && @@ -692,7 +692,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { } } for (int ii = 0; ii < 2; ii++) { - css_flex_direction_t axis = ii ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + css_flex_direction_t axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; if (isPosDefined(child, trailing[axis]) && !isPosDefined(child, leading[axis])) { child->layout.position[leading[axis]] = diff --git a/src/Layout.js b/src/Layout.js index cf229c72..01858307 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -237,7 +237,7 @@ var computeLayout = (function() { // Let's not measure the text if we already know both dimensions if (isRowUndefined || isColumnUndefined) { var/*css_dim_t*/ measure_dim = node.style.measure( - /*!node->context,*/ + /*(c)!node->context,*/ width ); if (isRowUndefined) { @@ -273,7 +273,7 @@ var computeLayout = (function() { // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both // left and right or top and bottom). for (var/*int*/ ii = 0; ii < 2; ii++) { - var/*css_flex_direction_t*/ axis = ii ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + var/*css_flex_direction_t*/ axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; if (!isUndefined(node.layout[dim[axis]]) && !isDimDefined(child, axis) && isPosDefined(child, leading[axis]) && @@ -366,7 +366,7 @@ var computeLayout = (function() { // If there are flexible children in the mix, they are going to fill the // remaining space - if (flexibleChildrenCount) { + if (flexibleChildrenCount != 0) { var/*float*/ flexibleMainDim = remainingMainDim / totalFlexible; // The non flexible children can overflow the container, in this case @@ -550,7 +550,7 @@ var computeLayout = (function() { // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both // left and right or top and bottom). for (var/*int*/ ii = 0; ii < 2; ii++) { - var/*css_flex_direction_t*/ axis = ii ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + var/*css_flex_direction_t*/ axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; if (!isUndefined(node.layout[dim[axis]]) && !isDimDefined(child, axis) && isPosDefined(child, leading[axis]) && @@ -567,7 +567,7 @@ var computeLayout = (function() { } } for (var/*int*/ ii = 0; ii < 2; ii++) { - var/*css_flex_direction_t*/ axis = ii ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; + var/*css_flex_direction_t*/ axis = (ii != 0) ? CSS_FLEX_DIRECTION_ROW : CSS_FLEX_DIRECTION_COLUMN; if (isPosDefined(child, trailing[axis]) && !isPosDefined(child, leading[axis])) { child.layout[leading[axis]] = diff --git a/src/java/.idea/.name b/src/java/.idea/.name new file mode 100644 index 00000000..4cc7a509 --- /dev/null +++ b/src/java/.idea/.name @@ -0,0 +1 @@ +css-layout \ No newline at end of file diff --git a/src/java/.idea/compiler.xml b/src/java/.idea/compiler.xml new file mode 100644 index 00000000..217af471 --- /dev/null +++ b/src/java/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/src/java/.idea/copyright/profiles_settings.xml b/src/java/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..3572571a --- /dev/null +++ b/src/java/.idea/copyright/profiles_settings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/java/.idea/encodings.xml b/src/java/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/src/java/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/java/.idea/misc.xml b/src/java/.idea/misc.xml new file mode 100644 index 00000000..97320410 --- /dev/null +++ b/src/java/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/java/.idea/modules.xml b/src/java/.idea/modules.xml new file mode 100644 index 00000000..8123b62d --- /dev/null +++ b/src/java/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/java/.idea/scopes/scope_settings.xml b/src/java/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/src/java/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/java/.idea/uiDesigner.xml b/src/java/.idea/uiDesigner.xml new file mode 100644 index 00000000..3b000203 --- /dev/null +++ b/src/java/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/.idea/vcs.xml b/src/java/.idea/vcs.xml new file mode 100644 index 00000000..def6a6a1 --- /dev/null +++ b/src/java/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/java/java.iml b/src/java/java.iml new file mode 100644 index 00000000..22ef4acb --- /dev/null +++ b/src/java/java.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/src/com/facebook/csslayout/CSSAlign.java b/src/java/src/com/facebook/csslayout/CSSAlign.java new file mode 100644 index 00000000..dbdfc420 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSAlign.java @@ -0,0 +1,9 @@ +package com.facebook.csslayout; + +public enum CSSAlign { + AUTO, + FLEX_START, + CENTER, + FLEX_END, + STRETCH, +} diff --git a/src/java/src/com/facebook/csslayout/CSSConstants.java b/src/java/src/com/facebook/csslayout/CSSConstants.java new file mode 100644 index 00000000..26c31d15 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSConstants.java @@ -0,0 +1,6 @@ +package com.facebook.csslayout; + +public class CSSConstants { + + public static final float UNDEFINED = Float.NaN; +} diff --git a/src/java/src/com/facebook/csslayout/CSSFlexDirection.java b/src/java/src/com/facebook/csslayout/CSSFlexDirection.java new file mode 100644 index 00000000..ed8a8f83 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSFlexDirection.java @@ -0,0 +1,6 @@ +package com.facebook.csslayout; + +public enum CSSFlexDirection { + COLUMN, + ROW, +} diff --git a/src/java/src/com/facebook/csslayout/CSSJustify.java b/src/java/src/com/facebook/csslayout/CSSJustify.java new file mode 100644 index 00000000..5a4ca9a4 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSJustify.java @@ -0,0 +1,9 @@ +package com.facebook.csslayout; + +public enum CSSJustify { + FLEX_START, + CENTER, + FLEX_END, + SPACE_BETWEEN, + SPACE_AROUND, +} diff --git a/src/java/src/com/facebook/csslayout/CSSLayout.java b/src/java/src/com/facebook/csslayout/CSSLayout.java new file mode 100644 index 00000000..be3f30ac --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSLayout.java @@ -0,0 +1,39 @@ +package com.facebook.csslayout; + +/** + * Where the output of {@link LayoutEngine#layoutNode(CSSNode, float)} will go in the CSSNode. + */ +public class CSSLayout { + + public float x; + public float y; + public float width = CSSConstants.UNDEFINED; + public float height = CSSConstants.UNDEFINED; + + /** + * This should always get called before calling {@link LayoutEngine#layoutNode(CSSNode, float)} + */ + public void resetResult() { + x = 0; + y = 0; + width = CSSConstants.UNDEFINED; + height = CSSConstants.UNDEFINED; + } + + public void copy(CSSLayout layout) { + x = layout.x; + y = layout.y; + width = layout.width; + height = layout.height; + } + + @Override + public String toString() { + return "layout: {" + + "x: " + x + ", " + + "y: " + y + ", " + + "width: " + width + ", " + + "height: " + height + + "}"; + } +} diff --git a/src/java/src/com/facebook/csslayout/CSSNode.java b/src/java/src/com/facebook/csslayout/CSSNode.java new file mode 100644 index 00000000..da6d8714 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSNode.java @@ -0,0 +1,338 @@ +package com.facebook.csslayout; + +import java.util.ArrayList; + +/** + * 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 { + + private static 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 #markLayoutApplied()} was called. + */ + HAS_NEW_LAYOUT, + + /** + * {@link #layout} is valid for the node's properties and this layout has been marked as + * having been applied. + */ + UP_TO_DATE, + } + + // Only one copy kept around to keep from allocating a bunch of MeasureOutput objects + // NOT THREAD SAFE! NOT RE-ENTRANT SAFE! + private static final MeasureOutput MEASURE_OUTPUT = new MeasureOutput(); + + public static interface MeasureFunction { + + /** + * Should measure the given node and put the result in the given MeasureOutput. + * + * NB: measure is NOT guaranteed to be threadsafe/re-entrant safe! + */ + public void measure(CSSNode node, float width, MeasureOutput measureOutput); + } + + // VisibleForTesting + /*package*/ final CSSStyle style = new CSSStyle(); + /*package*/ final CSSLayout layout = new CSSLayout(); + /*package*/ final CachedCSSLayout lastLayout = new CachedCSSLayout(); + + // 4 is kinda arbitrary, but the default of 10 seems really high for an average View. + private final ArrayList mChildren = new ArrayList(4); + + private CSSNode mParent; + private MeasureFunction mMeasureFunction = null; + private LayoutState mLayoutState = LayoutState.DIRTY; + + public int getChildCount() { + return mChildren.size(); + } + + public CSSNode getChildAt(int i) { + return mChildren.get(i); + } + + public void addChildAt(CSSNode child, int i) { + if (child.mParent != null) { + throw new IllegalStateException("Child already has a parent, it must be removed first."); + } + + mChildren.add(i, child); + child.mParent = this; + dirty(); + } + + public void removeChildAt(int i) { + mChildren.remove(i).mParent = null; + dirty(); + } + + public CSSNode getParent() { + return mParent; + } + + public void setMeasureFunction(MeasureFunction measureFunction) { + dirtyIfDifferent(mMeasureFunction, measureFunction); + mMeasureFunction = measureFunction; + } + + public boolean isMeasureDefined() { + return mMeasureFunction != null; + } + + /*package*/ MeasureOutput measure(float width) { + if (!isMeasureDefined()) { + throw new RuntimeException("Measure function isn't defined!"); + } + MEASURE_OUTPUT.height = CSSConstants.UNDEFINED; + MEASURE_OUTPUT.width = CSSConstants.UNDEFINED; + mMeasureFunction.measure(this, width, MEASURE_OUTPUT); + return MEASURE_OUTPUT; + } + + /** + * Performs the actual layout and saves the results in {@link #layout} + */ + public void calculateLayout() { + resetLayoutResultRecursive(); + LayoutEngine.layoutNode(this, CSSConstants.UNDEFINED); + } + + /** + * See {@link LayoutState#DIRTY}. + */ + /*package*/ boolean isDirty() { + return mLayoutState == LayoutState.DIRTY; + } + + /** + * See {@link LayoutState#HAS_NEW_LAYOUT}. + */ + public boolean hasNewLayout() { + return mLayoutState == LayoutState.HAS_NEW_LAYOUT; + } + + protected void dirty() { + if (mLayoutState == LayoutState.DIRTY) { + return; + } else if (mLayoutState == LayoutState.HAS_NEW_LAYOUT) { + throw new IllegalStateException( + "Previous layout was ignored! markLayoutApplied() never called"); + } + + mLayoutState = LayoutState.DIRTY; + + if (mParent != null) { + mParent.dirty(); + } + } + + /*package*/ void markHasNewLayout() { + mLayoutState = LayoutState.HAS_NEW_LAYOUT; + } + + /** + * Tells the node that the current values in {@link #layout} have been applied. 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 markLayoutApplied() { + if (!hasNewLayout()) { + throw new IllegalStateException("Expected node to have a new layout to apply!"); + } + + mLayoutState = LayoutState.UP_TO_DATE; + } + + @Override + public String toString() { + String layoutString = layout.toString(); + + if (getChildCount() == 0) { + return layoutString; + } + + layoutString += ", children: [\n"; + + for (int i = 0; i < getChildCount(); i++) { + String childString = getChildAt(i).toString(); + childString = childString.replaceAll("\n", "\n\t"); + layoutString += "\t" + childString + "\n"; + } + + layoutString += "]"; + + return layoutString; + } + + private void resetLayoutResultRecursive() { + layout.resetResult(); + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).resetLayoutResultRecursive(); + } + } + + protected void dirtyIfDifferent(float f1, float f2) { + if (!FloatUtil.floatsEqual(f1, f2)) { + dirty(); + } + } + + private static boolean objectsEqual(T o1, T o2) { + if (o1 == null) { + return o2 == null; + } + return o1.equals(o2); + } + + protected void dirtyIfDifferent(T o1, T o2) { + if (!objectsEqual(o1, o2)) { + dirty(); + } + } + + public void setFlexDirection(CSSFlexDirection flexDirection) { + dirtyIfDifferent(style.flexDirection, flexDirection); + style.flexDirection = flexDirection; + } + + public void setJustifyContent(CSSJustify justifyContent) { + dirtyIfDifferent(style.justifyContent, justifyContent); + style.justifyContent = justifyContent; + } + + public void setAlignItems(CSSAlign alignItems) { + dirtyIfDifferent(style.alignItems, alignItems); + style.alignItems = alignItems; + } + + public void setAlignSelf(CSSAlign alignSelf) { + dirtyIfDifferent(style.alignSelf, alignSelf); + style.alignSelf = alignSelf; + } + + public void setPositionType(CSSPositionType positionType) { + dirtyIfDifferent(style.positionType, positionType); + style.positionType = positionType; + } + + public void setFlex(float flex) { + dirtyIfDifferent(style.flex, flex); + style.flex = flex; + } + + public void setMarginTop(float marginTop) { + dirtyIfDifferent(style.marginTop, marginTop); + style.marginTop = marginTop; + } + + public void setMarginBottom(float marginBottom) { + dirtyIfDifferent(style.marginBottom, marginBottom); + style.marginBottom = marginBottom; + } + + public void setMarginLeft(float marginLeft) { + dirtyIfDifferent(style.marginLeft, marginLeft); + style.marginLeft = marginLeft; + } + + public void setMarginRight(float marginRight) { + dirtyIfDifferent(style.marginRight, marginRight); + style.marginRight = marginRight; + } + + public void setPaddingTop(float paddingTop) { + dirtyIfDifferent(style.paddingTop, paddingTop); + style.paddingTop = paddingTop; + } + + public void setPaddingBottom(float paddingBottom) { + dirtyIfDifferent(style.paddingBottom, paddingBottom); + style.paddingBottom = paddingBottom; + } + + public void setPaddingLeft(float paddingLeft) { + dirtyIfDifferent(style.paddingLeft, paddingLeft); + style.paddingLeft = paddingLeft; + } + + public void setPaddingRight(float paddingRight) { + dirtyIfDifferent(style.paddingRight, paddingRight); + style.paddingRight = paddingRight; + } + + public void setPositionTop(float positionTop) { + dirtyIfDifferent(style.positionTop, positionTop); + style.positionTop = positionTop; + } + + public void setPositionBottom(float positionBottom) { + dirtyIfDifferent(style.positionBottom, positionBottom); + style.positionBottom = positionBottom; + } + + public void setPositionLeft(float positionLeft) { + dirtyIfDifferent(style.positionLeft, positionLeft); + style.positionLeft = positionLeft; + } + + public void setPositionRight(float positionRight) { + dirtyIfDifferent(style.positionRight, positionRight); + style.positionRight = positionRight; + } + + public void setBorderTop(float borderTop) { + dirtyIfDifferent(style.borderTop, borderTop); + style.borderTop = borderTop; + } + + public void setBorderBottom(float borderBottom) { + dirtyIfDifferent(style.borderBottom, borderBottom); + style.borderBottom = borderBottom; + } + + public void setBorderLeft(float borderLeft) { + dirtyIfDifferent(style.borderLeft, borderLeft); + style.borderLeft = borderLeft; + } + + public void setBorderRight(float borderRight) { + dirtyIfDifferent(style.borderRight, borderRight); + style.borderRight = borderRight; + } + + public void setStyleWidth(float width) { + dirtyIfDifferent(style.width, width); + style.width = width; + } + + public void setStyleHeight(float height) { + dirtyIfDifferent(style.height, height); + style.height = height; + } + + public float getLayoutX() { + return layout.x; + } + + public float getLayoutY() { + return layout.y; + } + + public float getLayoutWidth() { + return layout.width; + } + + public float getLayoutHeight() { + return layout.height; + } +} diff --git a/src/java/src/com/facebook/csslayout/CSSPositionType.java b/src/java/src/com/facebook/csslayout/CSSPositionType.java new file mode 100644 index 00000000..fa2e1e42 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSPositionType.java @@ -0,0 +1,6 @@ +package com.facebook.csslayout; + +public enum CSSPositionType { + RELATIVE, + ABSOLUTE, +} diff --git a/src/java/src/com/facebook/csslayout/CSSStyle.java b/src/java/src/com/facebook/csslayout/CSSStyle.java new file mode 100644 index 00000000..3d9e7278 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSStyle.java @@ -0,0 +1,37 @@ +package com.facebook.csslayout; + +/** + * The CSS style definition for a {@link CSSNode}. + */ +public class CSSStyle { + + public CSSFlexDirection flexDirection = CSSFlexDirection.COLUMN; + public CSSJustify justifyContent = CSSJustify.FLEX_START; + public CSSAlign alignItems = CSSAlign.FLEX_START; + public CSSAlign alignSelf = CSSAlign.AUTO; + public CSSPositionType positionType = CSSPositionType.RELATIVE; + public float flex; + + public float marginTop; + public float marginBottom; + public float marginLeft; + public float marginRight; + + public float paddingTop; + public float paddingBottom; + public float paddingLeft; + public float paddingRight; + + public float positionTop = CSSConstants.UNDEFINED; + public float positionBottom = CSSConstants.UNDEFINED; + public float positionLeft = CSSConstants.UNDEFINED; + public float positionRight = CSSConstants.UNDEFINED; + + public float borderTop; + public float borderBottom; + public float borderLeft; + public float borderRight; + + public float width = CSSConstants.UNDEFINED; + public float height = CSSConstants.UNDEFINED; +} diff --git a/src/java/src/com/facebook/csslayout/CachedCSSLayout.java b/src/java/src/com/facebook/csslayout/CachedCSSLayout.java new file mode 100644 index 00000000..2f81884d --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CachedCSSLayout.java @@ -0,0 +1,13 @@ +package com.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. + */ +public class CachedCSSLayout extends CSSLayout { + + public float requestedWidth = CSSConstants.UNDEFINED; + public float requestedHeight = CSSConstants.UNDEFINED; + public float parentMaxWidth = CSSConstants.UNDEFINED; +} diff --git a/src/java/src/com/facebook/csslayout/FloatUtil.java b/src/java/src/com/facebook/csslayout/FloatUtil.java new file mode 100644 index 00000000..a3390f4e --- /dev/null +++ b/src/java/src/com/facebook/csslayout/FloatUtil.java @@ -0,0 +1,17 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +package com.facebook.csslayout; + +public class FloatUtil { + + public static boolean isUndefined(float f) { + return Float.compare(f, CSSConstants.UNDEFINED) == 0; + } + + public static boolean floatsEqual(float f1, float f2) { + if (isUndefined(f1)) { + return isUndefined(f2); + } + return Math.abs(f2 - f1) < .00001; + } +} diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java new file mode 100644 index 00000000..68b6f9d6 --- /dev/null +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -0,0 +1,650 @@ +package com.facebook.csslayout; + +/** + * Calculates layouts based on CSS style. See {@link #layoutNode(CSSNode, float)}. + */ +public class LayoutEngine { + + private static enum PositionIndex { + TOP, + LEFT, + BOTTOM, + RIGHT, + } + + private static enum DimensionIndex { + WIDTH, + HEIGHT, + } + + private static void setLayoutPosition(CSSNode node, PositionIndex position, float value) { + switch (position) { + case TOP: + node.layout.y = value; + break; + case LEFT: + node.layout.x = value; + break; + default: + throw new RuntimeException("Didn't get TOP or LEFT!"); + } + } + + private static float getLayoutPosition(CSSNode node, PositionIndex position) { + switch (position) { + case TOP: + return node.layout.y; + case LEFT: + return node.layout.x; + default: + throw new RuntimeException("Didn't get TOP or LEFT!"); + } + } + + private static void setLayoutDimension(CSSNode node, DimensionIndex dimension, float value) { + switch (dimension) { + case WIDTH: + node.layout.width = value; + break; + case HEIGHT: + node.layout.height = value; + break; + default: + throw new RuntimeException("Someone added a third dimension..."); + } + } + + private static float getLayoutDimension(CSSNode node, DimensionIndex dimension) { + switch (dimension) { + case WIDTH: + return node.layout.width; + case HEIGHT: + return node.layout.height; + default: + throw new RuntimeException("Someone added a third dimension..."); + } + } + + private static float getStylePosition(CSSNode node, PositionIndex position) { + switch (position) { + case TOP: + return node.style.positionTop; + case BOTTOM: + return node.style.positionBottom; + case LEFT: + return node.style.positionLeft; + case RIGHT: + return node.style.positionRight; + default: + throw new RuntimeException("Someone added a new cardinal direction..."); + } + } + + private static float getStyleDimension(CSSNode node, DimensionIndex dimension) { + switch (dimension) { + case WIDTH: + return node.style.width; + case HEIGHT: + return node.style.height; + default: + throw new RuntimeException("Someone added a third dimension..."); + } + } + + private static PositionIndex getLeading(CSSFlexDirection axis) { + return axis == CSSFlexDirection.COLUMN ? PositionIndex.TOP : PositionIndex.LEFT; + } + + private static PositionIndex getTrailing(CSSFlexDirection axis) { + return axis == CSSFlexDirection.COLUMN ? PositionIndex.BOTTOM : PositionIndex.RIGHT; + } + + private static PositionIndex getPos(CSSFlexDirection axis) { + return axis == CSSFlexDirection.COLUMN ? PositionIndex.TOP : PositionIndex.LEFT; + } + + private static DimensionIndex getDim(CSSFlexDirection axis) { + return axis == CSSFlexDirection.COLUMN ? DimensionIndex.HEIGHT : DimensionIndex.WIDTH; + } + + private static boolean isDimDefined(CSSNode node, CSSFlexDirection axis) { + return !FloatUtil.isUndefined(getStyleDimension(node, getDim(axis))); + } + + private static boolean isPosDefined(CSSNode node, PositionIndex position) { + return !FloatUtil.isUndefined(getStylePosition(node, position)); + } + + private static float getPosition(CSSNode node, PositionIndex position) { + float result = getStylePosition(node, position); + return FloatUtil.isUndefined(result) ? 0 : result; + } + + private static float getMargin(CSSNode node, PositionIndex position) { + switch (position) { + case TOP: + return node.style.marginTop; + case BOTTOM: + return node.style.marginBottom; + case LEFT: + return node.style.marginLeft; + case RIGHT: + return node.style.marginRight; + default: + throw new RuntimeException("Someone added a new cardinal direction..."); + } + } + + private static float getPadding(CSSNode node, PositionIndex position) { + switch (position) { + case TOP: + return node.style.paddingTop; + case BOTTOM: + return node.style.paddingBottom; + case LEFT: + return node.style.paddingLeft; + case RIGHT: + return node.style.paddingRight; + default: + throw new RuntimeException("Someone added a new cardinal direction..."); + } + } + + private static float getBorder(CSSNode node, PositionIndex position) { + switch (position) { + case TOP: + return node.style.borderTop; + case BOTTOM: + return node.style.borderBottom; + case LEFT: + return node.style.borderLeft; + case RIGHT: + return node.style.borderRight; + default: + throw new RuntimeException("Someone added a new cardinal direction..."); + } + } + + private static float getPaddingAndBorder(CSSNode node, PositionIndex position) { + return getPadding(node, position) + getBorder(node, position); + } + + private static float getMarginAxis(CSSNode node, CSSFlexDirection axis) { + return getMargin(node, getLeading(axis)) + getMargin(node, getTrailing(axis)); + } + + private static float getPaddingAndBorderAxis(CSSNode node, CSSFlexDirection axis) { + return getPaddingAndBorder( + node, + getLeading(axis)) + getPaddingAndBorder(node, getTrailing(axis)); + } + + private static void setDimensionFromStyle(CSSNode node, CSSFlexDirection axis) { + // The parent already computed us a width or height. We just skip it + if (!FloatUtil.isUndefined(getLayoutDimension(node, getDim(axis)))) { + return; + } + // We only run if there's a width or height defined + if (!isDimDefined(node, axis)) { + return; + } + + // The dimensions can never be smaller than the padding and border + float maxLayoutDimension = Math.max( + getStyleDimension(node, getDim(axis)), + getPaddingAndBorderAxis(node, axis)); + setLayoutDimension(node, getDim(axis), maxLayoutDimension); + } + + private static float getRelativePosition(CSSNode node, CSSFlexDirection axis) { + float lead = getStylePosition(node, getLeading(axis)); + if (!FloatUtil.isUndefined(lead)) { + return lead; + } + return -getPosition(node, getTrailing(axis)); + } + + private static float getFlex(CSSNode node) { + return node.style.flex; + } + + private static CSSFlexDirection getFlexDirection(CSSNode node) { + return node.style.flexDirection; + } + + private static CSSPositionType getPositionType(CSSNode node) { + return node.style.positionType; + } + + private static CSSAlign getAlignItem(CSSNode node, CSSNode child) { + if (child.style.alignSelf != CSSAlign.AUTO) { + return child.style.alignSelf; + } + return node.style.alignItems; + } + + private static CSSJustify getJustifyContent(CSSNode node) { + return node.style.justifyContent; + } + + private static boolean isFlex(CSSNode node) { + return getPositionType(node) == CSSPositionType.RELATIVE && getFlex(node) > 0; + } + + private static boolean isMeasureDefined(CSSNode node) { + return node.isMeasureDefined(); + } + + private static float getDimWithMargin(CSSNode node, CSSFlexDirection axis) { + return getLayoutDimension(node, getDim(axis)) + + getMargin(node, getLeading(axis)) + + getMargin(node, getTrailing(axis)); + } + + private static boolean needsRelayout(CSSNode node, float parentMaxWidth) { + return node.isDirty() || + !FloatUtil.floatsEqual(node.lastLayout.requestedHeight, node.layout.height) || + !FloatUtil.floatsEqual(node.lastLayout.requestedWidth, node.layout.width) || + !FloatUtil.floatsEqual(node.lastLayout.parentMaxWidth, parentMaxWidth); + } + + /*package*/ static void layoutNode(CSSNode node, float parentMaxWidth) { + if (needsRelayout(node, parentMaxWidth)) { + node.lastLayout.requestedWidth = node.layout.width; + node.lastLayout.requestedHeight = node.layout.height; + node.lastLayout.parentMaxWidth = parentMaxWidth; + + layoutNodeImpl(node, parentMaxWidth); + node.markHasNewLayout(); + + node.lastLayout.copy(node.layout); + } else { + node.layout.copy(node.lastLayout); + } + } + + private static void layoutNodeImpl(CSSNode node, float parentMaxWidth) { + + /** START_GENERATED **/ + + CSSFlexDirection mainAxis = getFlexDirection(node); + CSSFlexDirection crossAxis = mainAxis == CSSFlexDirection.ROW ? + CSSFlexDirection.COLUMN : + CSSFlexDirection.ROW; + + // Handle width and height style attributes + setDimensionFromStyle(node, mainAxis); + setDimensionFromStyle(node, crossAxis); + + // The position is set by the parent, but we need to complete it with a + // delta composed of the margin and left/top/right/bottom + setLayoutPosition(node, getLeading(mainAxis), getLayoutPosition(node, getLeading(mainAxis)) + getMargin(node, getLeading(mainAxis)) + + getRelativePosition(node, mainAxis)); + setLayoutPosition(node, getLeading(crossAxis), getLayoutPosition(node, getLeading(crossAxis)) + getMargin(node, getLeading(crossAxis)) + + getRelativePosition(node, crossAxis)); + + if (isMeasureDefined(node)) { + float width = CSSConstants.UNDEFINED; + if (isDimDefined(node, CSSFlexDirection.ROW)) { + width = node.style.width; + } else if (!FloatUtil.isUndefined(getLayoutDimension(node, getDim(CSSFlexDirection.ROW)))) { + width = getLayoutDimension(node, getDim(CSSFlexDirection.ROW)); + } else { + width = parentMaxWidth - + getMarginAxis(node, CSSFlexDirection.ROW); + } + width -= getPaddingAndBorderAxis(node, CSSFlexDirection.ROW); + + // We only need to give a dimension for the text if we haven't got any + // for it computed yet. It can either be from the style attribute or because + // the element is flexible. + boolean isRowUndefined = !isDimDefined(node, CSSFlexDirection.ROW) && + FloatUtil.isUndefined(getLayoutDimension(node, getDim(CSSFlexDirection.ROW))); + boolean isColumnUndefined = !isDimDefined(node, CSSFlexDirection.COLUMN) && + FloatUtil.isUndefined(getLayoutDimension(node, getDim(CSSFlexDirection.COLUMN))); + + // Let's not measure the text if we already know both dimensions + if (isRowUndefined || isColumnUndefined) { + MeasureOutput measure_dim = node.measure( + width + ); + if (isRowUndefined) { + node.layout.width = measure_dim.width + + getPaddingAndBorderAxis(node, CSSFlexDirection.ROW); + } + if (isColumnUndefined) { + node.layout.height = measure_dim.height + + getPaddingAndBorderAxis(node, CSSFlexDirection.COLUMN); + } + } + return; + } + + // Pre-fill some dimensions straight from the parent + for (int i = 0; i < node.getChildCount(); ++i) { + CSSNode child = node.getChildAt(i); + // Pre-fill cross axis dimensions when the child is using stretch before + // we call the recursive layout pass + if (getAlignItem(node, child) == CSSAlign.STRETCH && + getPositionType(child) == CSSPositionType.RELATIVE && + !FloatUtil.isUndefined(getLayoutDimension(node, getDim(crossAxis))) && + !isDimDefined(child, crossAxis) && + !isPosDefined(child, getLeading(crossAxis))) { + setLayoutDimension(child, getDim(crossAxis), Math.max( + getLayoutDimension(node, getDim(crossAxis)) - + getPaddingAndBorderAxis(node, crossAxis) - + getMarginAxis(child, crossAxis), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, crossAxis) + )); + } else if (getPositionType(child) == CSSPositionType.ABSOLUTE) { + // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both + // left and right or top and bottom). + for (int ii = 0; ii < 2; ii++) { + CSSFlexDirection axis = (ii != 0) ? CSSFlexDirection.ROW : CSSFlexDirection.COLUMN; + if (!FloatUtil.isUndefined(getLayoutDimension(node, getDim(axis))) && + !isDimDefined(child, axis) && + isPosDefined(child, getLeading(axis)) && + isPosDefined(child, getTrailing(axis))) { + setLayoutDimension(child, getDim(axis), Math.max( + getLayoutDimension(node, getDim(axis)) - + getPaddingAndBorderAxis(node, axis) - + getMarginAxis(child, axis) - + getPosition(child, getLeading(axis)) - + getPosition(child, getTrailing(axis)), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, axis) + )); + } + } + } + } + + // Layout non flexible children and count children by type + + // mainContentDim is accumulation of the dimensions and margin of all the + // non flexible children. 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 mainContentDim = 0; + + // There are three kind of children, non flexible, flexible and absolute. + // We need to know how many there are in order to distribute the space. + int flexibleChildrenCount = 0; + float totalFlexible = 0; + int nonFlexibleChildrenCount = 0; + for (int i = 0; i < node.getChildCount(); ++i) { + CSSNode child = node.getChildAt(i); + + // It only makes sense to consider a child flexible if we have a computed + // dimension for the node. + if (!FloatUtil.isUndefined(getLayoutDimension(node, getDim(mainAxis))) && isFlex(child)) { + flexibleChildrenCount++; + totalFlexible = totalFlexible + getFlex(child); + + // Even if we don't know its exact size yet, we already know the padding, + // border and margin. We'll use this partial information to compute the + // remaining space. + mainContentDim = mainContentDim + getPaddingAndBorderAxis(child, mainAxis) + + getMarginAxis(child, mainAxis); + + } else { + float maxWidth = CSSConstants.UNDEFINED; + if (mainAxis == CSSFlexDirection.ROW) { + // do nothing + } else if (isDimDefined(node, CSSFlexDirection.ROW)) { + maxWidth = getLayoutDimension(node, getDim(CSSFlexDirection.ROW)) - + getPaddingAndBorderAxis(node, CSSFlexDirection.ROW); + } else { + maxWidth = parentMaxWidth - + getMarginAxis(node, CSSFlexDirection.ROW) - + getPaddingAndBorderAxis(node, CSSFlexDirection.ROW); + } + + // This is the main recursive call. We layout non flexible children. + layoutNode(child, maxWidth); + + // Absolute positioned elements do not take part of the layout, so we + // don't use them to compute mainContentDim + if (getPositionType(child) == CSSPositionType.RELATIVE) { + nonFlexibleChildrenCount++; + // At this point we know the final size and margin of the element. + mainContentDim = mainContentDim + getDimWithMargin(child, mainAxis); + } + } + } + + + // Layout flexible children and allocate empty space + + // 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; + + // If the dimensions of the current node is defined by its children, they + // are all going to be packed together and we don't need to compute + // anything. + if (!FloatUtil.isUndefined(getLayoutDimension(node, getDim(mainAxis)))) { + // The remaining available space that needs to be allocated + float remainingMainDim = getLayoutDimension(node, getDim(mainAxis)) - + getPaddingAndBorderAxis(node, mainAxis) - + mainContentDim; + + // If there are flexible children in the mix, they are going to fill the + // remaining space + if (flexibleChildrenCount != 0) { + float flexibleMainDim = remainingMainDim / totalFlexible; + + // The non flexible children can overflow the container, in this case + // we should just assume that there is no space available. + if (flexibleMainDim < 0) { + flexibleMainDim = 0; + } + // We iterate over the full array and only apply the action on flexible + // children. This is faster than actually allocating a new array that + // contains only flexible children. + for (int i = 0; i < node.getChildCount(); ++i) { + CSSNode child = node.getChildAt(i); + if (isFlex(child)) { + // At this point we know the final size of the element in the main + // dimension + setLayoutDimension(child, getDim(mainAxis), flexibleMainDim * getFlex(child) + + getPaddingAndBorderAxis(child, mainAxis)); + + float maxWidth = CSSConstants.UNDEFINED; + if (mainAxis == CSSFlexDirection.ROW) { + // do nothing + } else if (isDimDefined(node, CSSFlexDirection.ROW)) { + maxWidth = getLayoutDimension(node, getDim(CSSFlexDirection.ROW)) - + getPaddingAndBorderAxis(node, CSSFlexDirection.ROW); + } else { + maxWidth = parentMaxWidth - + getMarginAxis(node, CSSFlexDirection.ROW) - + getPaddingAndBorderAxis(node, CSSFlexDirection.ROW); + } + + // And we recursively call the layout algorithm for this child + layoutNode(child, maxWidth); + } + } + + // We use justifyContent to figure out how to allocate the remaining + // space available + } else { + CSSJustify justifyContent = getJustifyContent(node); + if (justifyContent == CSSJustify.FLEX_START) { + // Do nothing + } else if (justifyContent == CSSJustify.CENTER) { + leadingMainDim = remainingMainDim / 2; + } else if (justifyContent == CSSJustify.FLEX_END) { + leadingMainDim = remainingMainDim; + } else if (justifyContent == CSSJustify.SPACE_BETWEEN) { + remainingMainDim = Math.max(remainingMainDim, 0); + betweenMainDim = remainingMainDim / + (flexibleChildrenCount + nonFlexibleChildrenCount - 1); + } else if (justifyContent == CSSJustify.SPACE_AROUND) { + // Space on the edges is half of the space between elements + betweenMainDim = remainingMainDim / + (flexibleChildrenCount + nonFlexibleChildrenCount); + leadingMainDim = betweenMainDim / 2; + } + } + } + + // Position elements in the main axis and compute dimensions + + // At this point, all the children have their dimensions set. We need to + // find their position. In order to do that, we accumulate data in + // variables that are also useful to compute the total dimensions of the + // container! + float crossDim = 0; + float mainDim = leadingMainDim + + getPaddingAndBorder(node, getLeading(mainAxis)); + for (int i = 0; i < node.getChildCount(); ++i) { + CSSNode child = node.getChildAt(i); + + if (getPositionType(child) == CSSPositionType.ABSOLUTE && + isPosDefined(child, getLeading(mainAxis))) { + // In case the child is position absolute and has left/top being + // defined, we override the position to whatever the user said + // (and margin/border). + setLayoutPosition(child, getPos(mainAxis), getPosition(child, getLeading(mainAxis)) + + getBorder(node, getLeading(mainAxis)) + + getMargin(child, getLeading(mainAxis))); + } else { + // If the child is position absolute (without top/left) or relative, + // we put it at the current accumulated offset. + setLayoutPosition(child, getPos(mainAxis), getLayoutPosition(child, getPos(mainAxis)) + mainDim); + } + + // Now that we placed the element, we need to update the variables + // We only need to do that for relative elements. Absolute elements + // do not take part in that phase. + if (getPositionType(child) == CSSPositionType.RELATIVE) { + // The main dimension is the sum of all the elements dimension plus + // the spacing. + mainDim = mainDim + betweenMainDim + getDimWithMargin(child, 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, getDimWithMargin(child, crossAxis)); + } + } + + // If the user didn't specify a width or height, and it has not been set + // by the container, then we set it via the children. + if (FloatUtil.isUndefined(getLayoutDimension(node, getDim(mainAxis)))) { + setLayoutDimension(node, getDim(mainAxis), Math.max( + // We're missing the last padding at this point to get the final + // dimension + mainDim + getPaddingAndBorder(node, getTrailing(mainAxis)), + // We can never assign a width smaller than the padding and borders + getPaddingAndBorderAxis(node, mainAxis) + )); + } + + if (FloatUtil.isUndefined(getLayoutDimension(node, getDim(crossAxis)))) { + setLayoutDimension(node, getDim(crossAxis), Math.max( + // For the cross dim, we add both sides at the end because the value + // is aggregate via a max function. Intermediate negative values + // can mess this computation otherwise + crossDim + getPaddingAndBorderAxis(node, crossAxis), + getPaddingAndBorderAxis(node, crossAxis) + )); + } + + + // Position elements in the cross axis + + for (int i = 0; i < node.getChildCount(); ++i) { + CSSNode child = node.getChildAt(i); + + if (getPositionType(child) == CSSPositionType.ABSOLUTE && + isPosDefined(child, getLeading(crossAxis))) { + // In case the child is absolutely positionned and has a + // top/left/bottom/right being set, we override all the previously + // computed positions to set it correctly. + setLayoutPosition(child, getPos(crossAxis), getPosition(child, getLeading(crossAxis)) + + getBorder(node, getLeading(crossAxis)) + + getMargin(child, getLeading(crossAxis))); + + } else { + float leadingCrossDim = getPaddingAndBorder(node, getLeading(crossAxis)); + + // For a relative children, we're either using alignItems (parent) or + // alignSelf (child) in order to determine the position in the cross axis + if (getPositionType(child) == CSSPositionType.RELATIVE) { + CSSAlign alignItem = getAlignItem(node, child); + if (alignItem == CSSAlign.FLEX_START) { + // Do nothing + } else if (alignItem == CSSAlign.STRETCH) { + // You can only stretch if the dimension has not already been set + // previously. + if (!isDimDefined(child, crossAxis)) { + setLayoutDimension(child, getDim(crossAxis), Math.max( + getLayoutDimension(node, getDim(crossAxis)) - + getPaddingAndBorderAxis(node, crossAxis) - + getMarginAxis(child, crossAxis), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, crossAxis) + )); + } + } else { + // The remaining space between the parent dimensions+padding and child + // dimensions+margin. + float remainingCrossDim = getLayoutDimension(node, getDim(crossAxis)) - + getPaddingAndBorderAxis(node, crossAxis) - + getDimWithMargin(child, crossAxis); + + if (alignItem == CSSAlign.CENTER) { + leadingCrossDim = leadingCrossDim + remainingCrossDim / 2; + } else { // CSSAlign.FLEX_END + leadingCrossDim = leadingCrossDim + remainingCrossDim; + } + } + } + + // And we apply the position + setLayoutPosition(child, getPos(crossAxis), getLayoutPosition(child, getPos(crossAxis)) + leadingCrossDim); + } + } + + // Calculate dimensions for absolutely positioned elements + + for (int i = 0; i < node.getChildCount(); ++i) { + CSSNode child = node.getChildAt(i); + if (getPositionType(child) == CSSPositionType.ABSOLUTE) { + // Pre-fill dimensions when using absolute position and both offsets for the axis are defined (either both + // left and right or top and bottom). + for (int ii = 0; ii < 2; ii++) { + CSSFlexDirection axis = (ii != 0) ? CSSFlexDirection.ROW : CSSFlexDirection.COLUMN; + if (!FloatUtil.isUndefined(getLayoutDimension(node, getDim(axis))) && + !isDimDefined(child, axis) && + isPosDefined(child, getLeading(axis)) && + isPosDefined(child, getTrailing(axis))) { + setLayoutDimension(child, getDim(axis), Math.max( + getLayoutDimension(node, getDim(axis)) - + getPaddingAndBorderAxis(node, axis) - + getMarginAxis(child, axis) - + getPosition(child, getLeading(axis)) - + getPosition(child, getTrailing(axis)), + // You never want to go smaller than padding + getPaddingAndBorderAxis(child, axis) + )); + } + } + for (int ii = 0; ii < 2; ii++) { + CSSFlexDirection axis = (ii != 0) ? CSSFlexDirection.ROW : CSSFlexDirection.COLUMN; + if (isPosDefined(child, getTrailing(axis)) && + !isPosDefined(child, getLeading(axis))) { + setLayoutPosition(child, getLeading(axis), getLayoutDimension(node, getDim(axis)) - + getLayoutDimension(child, getDim(axis)) - + getPosition(child, getTrailing(axis))); + } + } + } + } + } + /** END_GENERATED **/ +} diff --git a/src/java/src/com/facebook/csslayout/MeasureOutput.java b/src/java/src/com/facebook/csslayout/MeasureOutput.java new file mode 100644 index 00000000..52231dcc --- /dev/null +++ b/src/java/src/com/facebook/csslayout/MeasureOutput.java @@ -0,0 +1,10 @@ +package com.facebook.csslayout; + +/** + * POJO to hold the output of the measure function. + */ +public class MeasureOutput { + + public float width; + public float height; +} diff --git a/src/java/tests/com/facebook/csslayout/CSSNodeTest.java b/src/java/tests/com/facebook/csslayout/CSSNodeTest.java new file mode 100644 index 00000000..049a78e5 --- /dev/null +++ b/src/java/tests/com/facebook/csslayout/CSSNodeTest.java @@ -0,0 +1,42 @@ +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); + } +} diff --git a/src/java/tests/com/facebook/csslayout/LayoutCachingTest.java b/src/java/tests/com/facebook/csslayout/LayoutCachingTest.java new file mode 100644 index 00000000..2ba3be9d --- /dev/null +++ b/src/java/tests/com/facebook/csslayout/LayoutCachingTest.java @@ -0,0 +1,180 @@ +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.markLayoutApplied(); + 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(); + assertTreeHasNewLayout(false, root); + } + + @Test + public void testInvalidatesCacheWhenChildAdded() { + CSSNode root = new CSSNode(); + CSSNode c0 = new CSSNode(); + CSSNode c1 = new CSSNode(); + CSSNode c0c0 = new CSSNode(); + CSSNode c0c1 = new CSSNode(); + c0c1.setStyleWidth(200); + c0c1.setStyleHeight(200); + root.addChildAt(c0, 0); + root.addChildAt(c1, 1); + c0.addChildAt(c0c0, 0); + + root.calculateLayout(); + assertTreeHasNewLayout(true, root); + markLayoutAppliedForTree(root); + + root.calculateLayout(); + assertTreeHasNewLayout(false, root); + + c0.addChildAt(c0c1, 1); + + root.calculateLayout(); + assertTrue(root.hasNewLayout()); + assertTrue(c0.hasNewLayout()); + assertTrue(c0c1.hasNewLayout()); + + assertFalse(c0c0.hasNewLayout()); + assertFalse(c1.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(); + assertTreeHasNewLayout(true, root); + markLayoutAppliedForTree(root); + + root.calculateLayout(); + assertTreeHasNewLayout(false, root); + + c1.setAlignSelf(CSSAlign.CENTER); + root.calculateLayout(); + + assertTrue(root.hasNewLayout()); + assertTrue(c1.hasNewLayout()); + + assertFalse(c0.hasNewLayout()); + assertFalse(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(); + assertTreeHasNewLayout(true, root); + markLayoutAppliedForTree(root); + + root.calculateLayout(); + assertTreeHasNewLayout(false, root); + + c1.setMarginLeft(10); + root.calculateLayout(); + + assertTrue(root.hasNewLayout()); + assertTrue(c1.hasNewLayout()); + + assertFalse(c0.hasNewLayout()); + assertFalse(c0c0.hasNewLayout()); + } + + @Test + public void testInvalidatesFullTreeWhenParentWidthChanges() { + 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(); + assertTreeHasNewLayout(false, root); + + c0.setStyleWidth(200); + root.calculateLayout(); + + assertTrue(root.hasNewLayout()); + assertTrue(c0.hasNewLayout()); + assertTrue(c0c0.hasNewLayout()); + + assertFalse(c1.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.setStyleWidth(200); + + root.calculateLayout(); + assertTreeHasNewLayout(true, root); + markLayoutAppliedForTree(root); + + root.calculateLayout(); + assertTreeHasNewLayout(false, root); + + root.setStyleWidth(200); + root.calculateLayout(); + assertTreeHasNewLayout(false, root); + } +} diff --git a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java new file mode 100644 index 00000000..368ed3c1 --- /dev/null +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -0,0 +1,3722 @@ +package com.facebook.csslayout; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests for {@link LayoutEngine} + */ +public class LayoutEngineTest { + + private static CSSNode.MeasureFunction sTestMeasureFunction = new CSSNode.MeasureFunction() { + + @Override + public void measure(CSSNode node, float width, MeasureOutput measureOutput) { + if (FloatUtil.isUndefined(width)) { + width = 10000000; + } + + TestCSSNode testNode = (TestCSSNode) node; + if (testNode.context.equals(TestConstants.SMALL_TEXT)) { + measureOutput.width = Math.min(width, TestConstants.SMALL_WIDTH); + measureOutput.height = TestConstants.SMALL_HEIGHT; + } else if (testNode.context.equals(TestConstants.LONG_TEXT)) { + measureOutput.width = width >= TestConstants.BIG_WIDTH ? + TestConstants.BIG_WIDTH : Math.max(TestConstants.BIG_MIN_WIDTH, width); + measureOutput.height = width >= TestConstants.BIG_WIDTH ? + TestConstants.SMALL_HEIGHT : TestConstants.BIG_HEIGHT; + } else { + throw new RuntimeException("Got unknown test: " + testNode.context); + } + } + }; + + private static class TestCSSNode extends CSSNode { + + public String context = null; + + public TestCSSNode getChildAt(int i) { + return (TestCSSNode) super.getChildAt(i); + } + } + + private static void test(String message, CSSNode style, CSSNode expectedLayout) { + style.calculateLayout(); + assertLayoutsEqual(message, style, expectedLayout); + } + + private static void addChildren(TestCSSNode node, int numChildren) { + for (int i = 0; i < numChildren; i++) { + node.addChildAt(new TestCSSNode(), i); + } + } + + private static void assertLayoutsEqual(String message, CSSNode actual, CSSNode expected) { + Assert.assertTrue( + message + "\nActual:\n" + actual.toString() + "\nExpected:\n" + expected.toString(), + areLayoutsEqual(actual, expected)); + } + + private static boolean areLayoutsEqual(CSSNode a, CSSNode b) { + boolean doNodesHaveSameLayout = + areFloatsEqual(a.layout.x, b.layout.x) && + areFloatsEqual(a.layout.y, b.layout.y) && + areFloatsEqual(a.layout.width, b.layout.width) && + areFloatsEqual(a.layout.height, b.layout.height); + if (!doNodesHaveSameLayout) { + return false; + } + for (int i = 0; i < a.getChildCount(); i++) { + if (!areLayoutsEqual(a.getChildAt(i), b.getChildAt(i))) { + return false; + } + } + return true; + } + + private static boolean areFloatsEqual(float a, float b) { + return Math.abs(a - b) < .00001f; + } + + /** START_GENERATED **/ + @Test + public void testCase0() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 200; + } + + test("should layout a single node with width and height", root_node, root_layout); + } + + @Test + public void testCase1() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 500; + node_1.style.height = 500; + node_1 = node_0.getChildAt(1); + node_1.style.width = 250; + node_1.style.height = 250; + node_1 = node_0.getChildAt(2); + node_1.style.width = 125; + node_1.style.height = 125; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 500; + node_1.layout.height = 500; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 500; + node_1.layout.x = 0; + node_1.layout.width = 250; + node_1.layout.height = 250; + node_1 = node_0.getChildAt(2); + node_1.layout.y = 750; + node_1.layout.x = 0; + node_1.layout.width = 125; + node_1.layout.height = 125; + } + } + + test("should layout node with children", root_node, root_layout); + } + + @Test + public void testCase2() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 500; + node_1.style.height = 500; + node_1 = node_0.getChildAt(1); + node_1.style.width = 500; + node_1.style.height = 500; + addChildren(node_1, 2); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.width = 250; + node_2.style.height = 250; + node_2 = node_1.getChildAt(1); + node_2.style.width = 250; + node_2.style.height = 250; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 500; + node_1.layout.height = 500; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 500; + node_1.layout.x = 0; + node_1.layout.width = 500; + node_1.layout.height = 500; + addChildren(node_1, 2); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 250; + node_2.layout.height = 250; + node_2 = node_1.getChildAt(1); + node_2.layout.y = 250; + node_2.layout.x = 0; + node_2.layout.width = 250; + node_2.layout.height = 250; + } + } + } + + test("should layout node with nested children", root_node, root_layout); + } + + @Test + public void testCase3() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + node_0.style.marginLeft = 10; + node_0.style.marginTop = 10; + node_0.style.marginRight = 10; + node_0.style.marginBottom = 10; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 10; + node_0.layout.x = 10; + node_0.layout.width = 100; + node_0.layout.height = 200; + } + + test("should layout node with margin", root_node, root_layout); + } + + @Test + public void testCase4() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + node_0.style.marginLeft = 10; + node_0.style.marginTop = 10; + node_0.style.marginRight = 10; + node_0.style.marginBottom = 10; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 100; + node_1.style.marginLeft = 50; + node_1.style.marginTop = 50; + node_1.style.marginRight = 50; + node_1.style.marginBottom = 50; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + node_1.style.marginLeft = 25; + node_1.style.marginTop = 25; + node_1.style.marginRight = 25; + node_1.style.marginBottom = 25; + node_1 = node_0.getChildAt(2); + node_1.style.width = 100; + node_1.style.height = 100; + node_1.style.marginLeft = 10; + node_1.style.marginTop = 10; + node_1.style.marginRight = 10; + node_1.style.marginBottom = 10; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 10; + node_0.layout.x = 10; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 50; + node_1.layout.x = 50; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 225; + node_1.layout.x = 25; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(2); + node_1.layout.y = 360; + node_1.layout.x = 10; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with several children", root_node, root_layout); + } + + @Test + public void testCase5() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 200; + node_1 = node_0.getChildAt(1); + node_1.style.width = 300; + node_1.style.height = 150; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 100; + node_1.layout.width = 300; + node_1.layout.height = 150; + } + } + + test("should layout node with row flex direction", root_node, root_layout); + } + + @Test + public void testCase6() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 300; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 200; + node_1 = node_0.getChildAt(1); + node_1.style.width = 300; + node_1.style.height = 150; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 350; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 200; + node_1.layout.x = 0; + node_1.layout.width = 300; + node_1.layout.height = 150; + } + } + + test("should layout node based on children main dimensions", root_node, root_layout); + } + + @Test + public void testCase7() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 200; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + node_1.style.width = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 200; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 200; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 800; + } + } + + test("should layout node with flex", root_node, root_layout); + } + + @Test + public void testCase8() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.width = 1000; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.flex = 1; + node_2.style.width = 1000; + addChildren(node_2, 1); + { + TestCSSNode node_3; + node_3 = node_2.getChildAt(0); + node_3.style.flex = 1; + node_3.style.width = 1000; + } + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 1000; + node_1.layout.height = 1000; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 1000; + node_2.layout.height = 1000; + addChildren(node_2, 1); + { + TestCSSNode node_3; + node_3 = node_2.getChildAt(0); + node_3.layout.y = 0; + node_3.layout.x = 0; + node_3.layout.width = 1000; + node_3.layout.height = 1000; + } + } + } + } + + test("should layout node with flex recursively", root_node, root_layout); + } + + @Test + public void testCase9() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + node_0.style.marginLeft = 5; + node_0.style.marginTop = 10; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 100; + node_1.style.marginLeft = 15; + node_1.style.marginTop = 50; + node_1.style.marginBottom = 20; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + node_1.style.marginLeft = 30; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 10; + node_0.layout.x = 5; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 50; + node_1.layout.x = 15; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 170; + node_1.layout.x = 30; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with targeted margin", root_node, root_layout); + } + + @Test + public void testCase10() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.FLEX_START; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with justifyContent: flex-start", root_node, root_layout); + } + + @Test + public void testCase11() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.FLEX_END; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 800; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 900; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with justifyContent: flex-end", root_node, root_layout); + } + + @Test + public void testCase12() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.SPACE_BETWEEN; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 900; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with justifyContent: space-between", root_node, root_layout); + } + + @Test + public void testCase13() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.SPACE_AROUND; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 200; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 700; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with justifyContent: space-around", root_node, root_layout); + } + + @Test + public void testCase14() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.CENTER; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 100; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 400; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 500; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with justifyContent: center", root_node, root_layout); + } + + @Test + public void testCase15() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 1000; + } + } + + test("should layout node with flex override height", root_node, root_layout); + } + + @Test + public void testCase16() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.FLEX_START; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with alignItems: flex-start", root_node, root_layout); + } + + @Test + public void testCase17() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.CENTER; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 400; + node_1.layout.width = 200; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 450; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with alignItems: center", root_node, root_layout); + } + + @Test + public void testCase18() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.FLEX_END; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 800; + node_1.layout.width = 200; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 900; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with alignItems: flex-end", root_node, root_layout); + } + + @Test + public void testCase19() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.FLEX_END; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.alignSelf = CSSAlign.CENTER; + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 800; + node_1.layout.width = 200; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 450; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout node with alignSelf overrides alignItems", root_node, root_layout); + } + + @Test + public void testCase20() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.STRETCH; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1000; + node_0.layout.height = 1000; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 1000; + node_1.layout.height = 100; + } + } + + test("should layout node with alignItem: stretch", root_node, root_layout); + } + + @Test + public void testCase21() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout empty node", root_node, root_layout); + } + + @Test + public void testCase22() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginLeft = 5; + node_1.style.marginTop = 5; + node_1.style.marginRight = 5; + node_1.style.marginBottom = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 10; + node_0.layout.height = 10; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 5; + node_1.layout.x = 5; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout child with margin", root_node, root_layout); + } + + @Test + public void testCase23() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.height = 200; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 200; + } + } + + test("should not shrink children if not enough space", root_node, root_layout); + } + + @Test + public void testCase24() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.CENTER; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + } + + test("should layout for center", root_node, root_layout); + } + + @Test + public void testCase25() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.FLEX_END; + node_0.style.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginTop = 10; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout flex-end taking into account margin", root_node, root_layout); + } + + @Test + public void testCase26() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignItems = CSSAlign.FLEX_END; + addChildren(node_1, 2); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.marginLeft = 10; + node_2.style.marginTop = 10; + node_2.style.marginRight = 10; + node_2.style.marginBottom = 10; + node_2 = node_1.getChildAt(1); + node_2.style.height = 100; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 20; + node_0.layout.height = 120; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 20; + node_1.layout.height = 120; + addChildren(node_1, 2); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 10; + node_2.layout.x = 10; + node_2.layout.width = 0; + node_2.layout.height = 0; + node_2 = node_1.getChildAt(1); + node_2.layout.y = 20; + node_2.layout.x = 20; + node_2.layout.width = 0; + node_2.layout.height = 100; + } + } + } + + test("should layout alignItems with margin", root_node, root_layout); + } + + @Test + public void testCase27() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout flex inside of an empty element", root_node, root_layout); + } + + @Test + public void testCase28() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.STRETCH; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginLeft = 10; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 10; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 10; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout alignItems stretch and margin", root_node, root_layout); + } + + @Test + public void testCase29() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.paddingLeft = 5; + node_0.style.paddingTop = 5; + node_0.style.paddingRight = 5; + node_0.style.paddingBottom = 5; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 10; + node_0.layout.height = 10; + } + + test("should layout node with padding", root_node, root_layout); + } + + @Test + public void testCase30() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.paddingLeft = 5; + node_0.style.paddingTop = 5; + node_0.style.paddingRight = 5; + node_0.style.paddingBottom = 5; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 10; + node_0.layout.height = 10; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 5; + node_1.layout.x = 5; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with padding and a child", root_node, root_layout); + } + + @Test + public void testCase31() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.paddingLeft = 5; + node_0.style.paddingTop = 5; + node_0.style.paddingRight = 5; + node_0.style.paddingBottom = 5; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginLeft = 5; + node_1.style.marginTop = 5; + node_1.style.marginRight = 5; + node_1.style.marginBottom = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 20; + node_0.layout.height = 20; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 10; + node_1.layout.x = 10; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with padding and a child with margin", root_node, root_layout); + } + + @Test + public void testCase32() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignSelf = CSSAlign.STRETCH; + node_1.style.paddingLeft = 10; + node_1.style.paddingTop = 10; + node_1.style.paddingRight = 10; + node_1.style.paddingBottom = 10; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 20; + node_0.layout.height = 20; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 20; + node_1.layout.height = 20; + } + } + + test("should layout node with padding and stretch", root_node, root_layout); + } + + @Test + public void testCase33() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.paddingLeft = 50; + node_0.style.paddingTop = 50; + node_0.style.paddingRight = 50; + node_0.style.paddingBottom = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignSelf = CSSAlign.STRETCH; + node_1.style.paddingLeft = 10; + node_1.style.paddingTop = 10; + node_1.style.paddingRight = 10; + node_1.style.paddingBottom = 10; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 120; + node_0.layout.height = 120; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 50; + node_1.layout.x = 50; + node_1.layout.width = 20; + node_1.layout.height = 20; + } + } + + test("should layout node with inner & outer padding and stretch", root_node, root_layout); + } + + @Test + public void testCase34() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignSelf = CSSAlign.STRETCH; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.marginLeft = 16; + node_2.style.marginTop = 16; + node_2.style.marginRight = 16; + node_2.style.marginBottom = 16; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 32; + node_0.layout.height = 32; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 32; + node_1.layout.height = 32; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 16; + node_2.layout.x = 16; + node_2.layout.width = 0; + node_2.layout.height = 0; + } + } + } + + test("should layout node with stretch and child with margin", root_node, root_layout); + } + + @Test + public void testCase35() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.positionLeft = 5; + node_0.style.positionTop = 5; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 5; + node_0.layout.x = 5; + node_0.layout.width = 0; + node_0.layout.height = 0; + } + + test("should layout node with top and left", root_node, root_layout); + } + + @Test + public void testCase36() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.SPACE_AROUND; + node_0.style.height = 10; + node_0.style.paddingTop = 5; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 10; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 7.5f; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with height, padding and space-around", root_node, root_layout); + } + + @Test + public void testCase37() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.positionBottom = 5; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = -5; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + } + + test("should layout node with bottom", root_node, root_layout); + } + + @Test + public void testCase38() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.positionTop = 10; + node_0.style.positionBottom = 5; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 10; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + } + + test("should layout node with both top and bottom", root_node, root_layout); + } + + @Test + public void testCase39() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 500; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1 = node_0.getChildAt(1); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.width = 50; + node_1 = node_0.getChildAt(2); + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 500; + node_0.layout.height = 0; + addChildren(node_0, 3); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 250; + node_1.layout.height = 0; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 250; + node_1.layout.width = 50; + node_1.layout.height = 0; + node_1 = node_0.getChildAt(2); + node_1.layout.y = 0; + node_1.layout.x = 250; + node_1.layout.width = 250; + node_1.layout.height = 0; + } + } + + test("should layout node with position: absolute", root_node, root_layout); + } + + @Test + public void testCase40() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.marginRight = 15; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with child with position: absolute and margin", root_node, root_layout); + } + + @Test + public void testCase41() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignSelf = CSSAlign.CENTER; + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.paddingRight = 12; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 12; + node_1.layout.height = 0; + } + } + + test("should layout node with position: absolute, padding and alignSelf: center", root_node, root_layout); + } + + @Test + public void testCase42() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.height = 5; + node_0.style.paddingBottom = 20; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 20; + } + + test("should work with height smaller than paddingBottom", root_node, root_layout); + } + + @Test + public void testCase43() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 5; + node_0.style.paddingLeft = 20; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 20; + node_0.layout.height = 0; + } + + test("should work with width smaller than paddingLeft", root_node, root_layout); + } + + @Test + public void testCase44() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.width = 400; + } + node_1 = node_0.getChildAt(1); + node_1.style.alignSelf = CSSAlign.STRETCH; + node_1.style.width = 200; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 400; + node_0.layout.height = 0; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 400; + node_1.layout.height = 0; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 400; + node_2.layout.height = 0; + } + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 0; + } + } + + test("should layout node with specified width and stretch", root_node, root_layout); + } + + @Test + public void testCase45() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.paddingLeft = 5; + node_0.style.paddingTop = 5; + node_0.style.paddingRight = 5; + node_0.style.paddingBottom = 5; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 10; + node_0.layout.height = 10; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 5; + node_1.layout.x = 5; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with padding and child with position absolute", root_node, root_layout); + } + + @Test + public void testCase46() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 10; + node_1.style.positionTop = 10; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 10; + node_1.layout.x = 10; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with position absolute, top and left", root_node, root_layout); + } + + @Test + public void testCase47() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.paddingLeft = 20; + node_0.style.paddingTop = 20; + node_0.style.paddingRight = 20; + node_0.style.paddingBottom = 20; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 40; + node_0.layout.height = 40; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 20; + node_1.layout.x = 5; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with padding and child position absolute, left", root_node, root_layout); + } + + @Test + public void testCase48() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.marginTop = 5; + node_1.style.positionTop = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 10; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with position: absolute, top and marginTop", root_node, root_layout); + } + + @Test + public void testCase49() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.marginLeft = 5; + node_1.style.positionLeft = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 10; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with position: absolute, left and marginLeft", root_node, root_layout); + } + + @Test + public void testCase50() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.SPACE_AROUND; + node_0.style.height = 200; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1 = node_0.getChildAt(1); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 200; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with space-around and child position absolute", root_node, root_layout); + } + + @Test + public void testCase51() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 700; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.marginLeft = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 700; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 5; + node_1.layout.width = 695; + node_1.layout.height = 0; + } + } + + test("should layout node with flex and main margin", root_node, root_layout); + } + + @Test + public void testCase52() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 700; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + node_1.style.paddingRight = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 700; + node_0.layout.height = 0; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 347.5f; + node_1.layout.height = 0; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 347.5f; + node_1.layout.width = 352.5f; + node_1.layout.height = 0; + } + } + + test("should layout node with multiple flex and padding", root_node, root_layout); + } + + @Test + public void testCase53() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 700; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + node_1.style.marginLeft = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 700; + node_0.layout.height = 0; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 347.5f; + node_1.layout.height = 0; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 352.5f; + node_1.layout.width = 347.5f; + node_1.layout.height = 0; + } + } + + test("should layout node with multiple flex and margin", root_node, root_layout); + } + + @Test + public void testCase54() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.height = 300; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 600; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 300; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 600; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 600; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with flex and overflow", root_node, root_layout); + } + + @Test + public void testCase55() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 600; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 600; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with flex and position absolute", root_node, root_layout); + } + + @Test + public void testCase56() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.height = 500; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1 = node_0.getChildAt(1); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.flex = 1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 500; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 500; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 500; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with double flex and position absolute", root_node, root_layout); + } + + @Test + public void testCase57() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.borderLeft = 5; + node_0.style.borderTop = 5; + node_0.style.borderRight = 5; + node_0.style.borderBottom = 5; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 10; + node_0.layout.height = 10; + } + + test("should layout node with borderWidth", root_node, root_layout); + } + + @Test + public void testCase58() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.borderTop = 1; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionTop = -1; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 1; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with borderWidth and position: absolute, top", root_node, root_layout); + } + + @Test + public void testCase59() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.borderLeft = 1; + node_0.style.borderTop = 1; + node_0.style.borderRight = 1; + node_0.style.borderBottom = 1; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 2; + node_0.layout.height = 2; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 1; + node_1.layout.x = 6; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout node with borderWidth and position: absolute, top. cross axis", root_node, root_layout); + } + + @Test + public void testCase60() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignSelf = CSSAlign.STRETCH; + node_1.style.marginLeft = 20; + node_1.style.paddingLeft = 20; + node_1.style.paddingTop = 20; + node_1.style.paddingRight = 20; + node_1.style.paddingBottom = 20; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 50; + node_0.layout.height = 40; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 20; + node_1.layout.width = 40; + node_1.layout.height = 40; + } + } + + test("should correctly take into account min padding for stretch", root_node, root_layout); + } + + @Test + public void testCase61() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.borderRight = 5; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 5; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 5; + node_1.layout.height = 0; + } + } + + test("should layout node with negative width", root_node, root_layout); + } + + @Test + public void testCase62() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.borderRight = 1; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginRight = -8; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 1; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should handle negative margin and min padding correctly", root_node, root_layout); + } + + @Test + public void testCase63() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.setMeasureFunction(sTestMeasureFunction); + node_0.context = "small"; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 34.671875f; + node_0.layout.height = 18; + } + + test("should layout node with just text", root_node, root_layout); + } + + @Test + public void testCase64() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 10; + node_0.setMeasureFunction(sTestMeasureFunction); + node_0.context = "small"; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 10; + node_0.layout.height = 18; + } + + test("should layout node with text and width", root_node, root_layout); + } + + @Test + public void testCase65() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.setMeasureFunction(sTestMeasureFunction); + node_0.context = "loooooooooong with space"; + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 172.421875f; + node_0.layout.height = 18; + } + + test("should layout node with text, padding and margin", root_node, root_layout); + } + + @Test + public void testCase66() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 300; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignSelf = CSSAlign.STRETCH; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.alignSelf = CSSAlign.STRETCH; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 300; + node_1.layout.height = 0; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 300; + node_2.layout.height = 0; + } + } + } + + test("should layout node with nested alignSelf: stretch", root_node, root_layout); + } + + @Test + public void testCase67() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flexDirection = CSSFlexDirection.ROW; + node_1.style.width = 500; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.flex = 1; + node_2.setMeasureFunction(sTestMeasureFunction); + node_2.context = "loooooooooong with space"; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 500; + node_0.layout.height = 18; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 500; + node_1.layout.height = 18; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 500; + node_2.layout.height = 18; + } + } + } + + test("should layout node with text and flex", root_node, root_layout); + } + + @Test + public void testCase68() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 130; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignItems = CSSAlign.STRETCH; + node_1.style.alignSelf = CSSAlign.STRETCH; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.setMeasureFunction(sTestMeasureFunction); + node_2.context = "loooooooooong with space"; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 130; + node_0.layout.height = 36; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 130; + node_1.layout.height = 36; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 130; + node_2.layout.height = 36; + } + } + } + + test("should layout node with text and stretch", root_node, root_layout); + } + + @Test + public void testCase69() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignItems = CSSAlign.STRETCH; + node_1.style.alignSelf = CSSAlign.STRETCH; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.width = 130; + node_2.setMeasureFunction(sTestMeasureFunction); + node_2.context = "loooooooooong with space"; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 200; + node_0.layout.height = 36; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 36; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 130; + node_2.layout.height = 36; + } + } + } + + test("should layout node with text stretch and width", root_node, root_layout); + } + + @Test + public void testCase70() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.setMeasureFunction(sTestMeasureFunction); + node_1.context = "loooooooooong with space"; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 36; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100.453125f; + node_1.layout.height = 36; + } + } + + test("should layout node with text bounded by parent", root_node, root_layout); + } + + @Test + public void testCase71() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.paddingLeft = 10; + node_0.style.paddingTop = 10; + node_0.style.paddingRight = 10; + node_0.style.paddingBottom = 10; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginLeft = 10; + node_1.style.marginTop = 10; + node_1.style.marginRight = 10; + node_1.style.marginBottom = 10; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.setMeasureFunction(sTestMeasureFunction); + node_2.context = "loooooooooong with space"; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 76; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 20; + node_1.layout.x = 20; + node_1.layout.width = 100.453125f; + node_1.layout.height = 36; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 0; + node_2.layout.x = 0; + node_2.layout.width = 100.453125f; + node_2.layout.height = 36; + } + } + } + + test("should layout node with text bounded by grand-parent", root_node, root_layout); + } + + @Test + public void testCase72() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.SPACE_BETWEEN; + node_0.style.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 900; + node_1 = node_0.getChildAt(1); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 900; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 900; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout space-between when remaining space is negative", root_node, root_layout); + } + + @Test + public void testCase73() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.justifyContent = CSSJustify.FLEX_END; + node_0.style.width = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 900; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 200; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = -700; + node_1.layout.width = 900; + node_1.layout.height = 0; + } + } + + test("should layout flex-end when remaining space is negative", root_node, root_layout); + } + + @Test + public void testCase74() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flexDirection = CSSFlexDirection.ROW; + node_1.style.width = 200; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.marginLeft = 20; + node_2.style.marginTop = 20; + node_2.style.marginRight = 20; + node_2.style.marginBottom = 20; + node_2.setMeasureFunction(sTestMeasureFunction); + node_2.context = "loooooooooong with space"; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 200; + node_0.layout.height = 58; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 58; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 20; + node_2.layout.x = 20; + node_2.layout.width = 172.421875f; + node_2.layout.height = 18; + } + } + } + + test("should layout text with flexDirection row", root_node, root_layout); + } + + @Test + public void testCase75() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 200; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.marginLeft = 20; + node_2.style.marginTop = 20; + node_2.style.marginRight = 20; + node_2.style.marginBottom = 20; + node_2.setMeasureFunction(sTestMeasureFunction); + node_2.context = "loooooooooong with space"; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 200; + node_0.layout.height = 76; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 76; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 20; + node_2.layout.x = 20; + node_2.layout.width = 160; + node_2.layout.height = 36; + } + } + } + + test("should layout with text and margin", root_node, root_layout); + } + + @Test + public void testCase76() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 0; + node_1.style.positionTop = 0; + node_1.style.positionRight = 0; + node_1.style.positionBottom = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 100; + node_1.layout.height = 100; + } + } + + test("should layout with position absolute, top, left, bottom, right", root_node, root_layout); + } + + @Test + public void testCase77() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 2.5f; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 7.5f; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 25; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 25; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 75; + } + } + + test("should layout with arbitrary flex", root_node, root_layout); + } + + @Test + public void testCase78() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1 = node_0.getChildAt(1); + node_1.style.flex = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should layout with negative flex", root_node, root_layout); + } + + @Test + public void testCase79() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 50; + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 0; + node_1.style.positionRight = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 50; + node_0.layout.height = 100; + addChildren(node_0, 2); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 50; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 50; + node_1.layout.height = 0; + } + } + + test("should layout with position: absolute and another sibling", root_node, root_layout); + } + + @Test + public void testCase80() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionTop = 0; + node_1.style.positionBottom = 20; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 80; + } + } + + test("should calculate height properly with position: absolute top and bottom", root_node, root_layout); + } + + @Test + public void testCase81() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + node_0.style.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.justifyContent = CSSJustify.CENTER; + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 0; + node_1.style.positionTop = 0; + node_1.style.positionRight = 0; + node_1.style.positionBottom = 0; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.width = 100; + node_2.style.height = 100; + } + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 200; + node_0.layout.height = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 0; + node_1.layout.width = 200; + node_1.layout.height = 200; + addChildren(node_1, 1); + { + TestCSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.layout.y = 50; + node_2.layout.x = 0; + node_2.layout.width = 100; + node_2.layout.height = 100; + } + } + } + + test("should layout with complicated position: absolute and justifyContent: center combo", root_node, root_layout); + } + + @Test + public void testCase82() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionBottom = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 100; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should calculate top properly with position: absolute bottom", root_node, root_layout); + } + + @Test + public void testCase83() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionRight = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 100; + node_1.layout.width = 0; + node_1.layout.height = 0; + } + } + + test("should calcluate left properly with position: absolute right", root_node, root_layout); + } + + @Test + public void testCase84() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.height = 10; + node_1.style.positionBottom = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 90; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 10; + } + } + + test("should calculate top properly with position: absolute bottom and height", root_node, root_layout); + } + + @Test + public void testCase85() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 100; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.width = 10; + node_1.style.positionRight = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 100; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = 90; + node_1.layout.width = 10; + node_1.layout.height = 0; + } + } + + test("should calcluate left properly with position: absolute right and width", root_node, root_layout); + } + + @Test + public void testCase86() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.height = 10; + node_1.style.positionBottom = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = -10; + node_1.layout.x = 0; + node_1.layout.width = 0; + node_1.layout.height = 10; + } + } + + test("should calcluate top properly with position: absolute right, width, and no parent dimensions", root_node, root_layout); + } + + @Test + public void testCase87() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.width = 10; + node_1.style.positionRight = 0; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 0; + node_0.layout.height = 0; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 0; + node_1.layout.x = -10; + node_1.layout.width = 10; + node_1.layout.height = 0; + } + } + + test("should calcluate left properly with position: absolute right, width, and no parent dimensions", root_node, root_layout); + } + /** END_GENERATED **/ +} diff --git a/src/java/tests/com/facebook/csslayout/TestConstants.java b/src/java/tests/com/facebook/csslayout/TestConstants.java new file mode 100644 index 00000000..2add7935 --- /dev/null +++ b/src/java/tests/com/facebook/csslayout/TestConstants.java @@ -0,0 +1,17 @@ +package com.facebook.csslayout; + +/** + * Generated constants used in {@link LayoutEngineTest}. + */ +public class TestConstants { + + /** START_GENERATED **/ + public static final float SMALL_WIDTH = 34.671875f; + public static final float SMALL_HEIGHT = 18f; + public static final float BIG_WIDTH = 172.421875f; + public static final float BIG_HEIGHT = 36f; + public static final float BIG_MIN_WIDTH = 100.453125f; + public static final String SMALL_TEXT = "small"; + public static final String LONG_TEXT = "loooooooooong with space"; + /** END_GENERATED **/ +} diff --git a/src/transpile.js b/src/transpile.js index cae5f91f..e09bf7e6 100644 --- a/src/transpile.js +++ b/src/transpile.js @@ -1,6 +1,7 @@ var layoutTestUtils = require('./Layout-test-utils.js'); var computeLayout = require('./Layout.js'); var fs = require('fs'); +var JavaTranspiler = require('./JavaTranspiler.js'); var currentTest = ''; var allTests = []; @@ -223,6 +224,7 @@ function transpileAnnotatedJStoC(jsCode) { .replace(/var\/\*([^\/]+)\*\//g, '$1') .replace(/ === /g, ' == ') .replace(/\n /g, '\n') + .replace(/\/\*\(c\)!([^*]+)\*\//g, '$1') .replace(/\/[*]!([^*]+)[*]\//g, '$1') .split('\n').slice(1, -1).join('\n'); } @@ -250,6 +252,10 @@ function generateFile(fileName, generatedContent) { } -generateFile(__dirname + '/__tests__/Layout-test.c', allTests.map(printLayout).join('\n\n')); +var allTestsInC = allTests.map(printLayout); +generateFile(__dirname + '/__tests__/Layout-test.c', allTestsInC.join('\n\n')); generateFile(__dirname + '/Layout-test-utils.c', makeConstDefs()); generateFile(__dirname + '/Layout.c', transpileAnnotatedJStoC(computeLayout.toString())); +generateFile(__dirname + '/java/src/com/facebook/csslayout/LayoutEngine.java', JavaTranspiler.transpileLayoutEngine(computeLayout.toString())); +generateFile(__dirname + '/java/tests/com/facebook/csslayout/TestConstants.java', JavaTranspiler.transpileCConstDefs(makeConstDefs())); +generateFile(__dirname + '/java/tests/com/facebook/csslayout/LayoutEngineTest.java', JavaTranspiler.transpileCTestsArray(allTestsInC));