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/src/Layout.c b/src/Layout.c index ee2edd77..b1bc5f68 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -397,7 +397,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]) && @@ -490,7 +490,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 diff --git a/src/Layout.js b/src/Layout.js index 91bd6f3f..a8ed3ec3 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 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..f6b2ea2e --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSLayout.java @@ -0,0 +1,32 @@ +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; + } + + @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..325757df --- /dev/null +++ b/src/java/src/com/facebook/csslayout/CSSNode.java @@ -0,0 +1,211 @@ +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 { + + // 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(); + + // 4 is kinda arbitrary, but the default of 10 seems really high for an average View. + private final ArrayList mChildren = new ArrayList(4); + + private MeasureFunction mMeasureFunction = null; + + public int getChildCount() { + return mChildren.size(); + } + + public CSSNode getChildAt(int i) { + return mChildren.get(i); + } + + public void addChildAt(CSSNode child, int i) { + mChildren.add(i, child); + } + + public void setMeasureFunction(MeasureFunction 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); + } + + @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(); + } + } + + public void setFlexDirection(CSSFlexDirection flexDirection) { + style.flexDirection = flexDirection; + } + + public void setJustifyContent(CSSJustify justifyContent) { + style.justifyContent = justifyContent; + } + + public void setAlignItems(CSSAlign alignItems) { + style.alignItems = alignItems; + } + + public void setAlignSelf(CSSAlign alignSelf) { + style.alignSelf = alignSelf; + } + + public void setPositionType(CSSPositionType positionType) { + style.positionType = positionType; + } + + public void setFlex(float flex) { + style.flex = flex; + } + + public void setMarginTop(float marginTop) { + style.marginTop = marginTop; + } + + public void setMarginBottom(float marginBottom) { + style.marginBottom = marginBottom; + } + + public void setMarginLeft(float marginLeft) { + style.marginLeft = marginLeft; + } + + public void setMarginRight(float marginRight) { + style.marginRight = marginRight; + } + + public void setPaddingTop(float paddingTop) { + style.paddingTop = paddingTop; + } + + public void setPaddingBottom(float paddingBottom) { + style.paddingBottom = paddingBottom; + } + + public void setPaddingLeft(float paddingLeft) { + style.paddingLeft = paddingLeft; + } + + public void setPaddingRight(float paddingRight) { + style.paddingRight = paddingRight; + } + + public void setPositionTop(float positionTop) { + style.positionTop = positionTop; + } + + public void setPositionBottom(float positionBottom) { + style.positionBottom = positionBottom; + } + + public void setPositionLeft(float positionLeft) { + style.positionLeft = positionLeft; + } + + public void setPositionRight(float positionRight) { + style.positionRight = positionRight; + } + + public void setBorderTop(float borderTop) { + style.borderTop = borderTop; + } + + public void setBorderBottom(float borderBottom) { + style.borderBottom = borderBottom; + } + + public void setBorderLeft(float borderLeft) { + style.borderLeft = borderLeft; + } + + public void setBorderRight(float borderRight) { + style.borderRight = borderRight; + } + + public void setStyleWidth(float width) { + style.width = width; + } + + public void setStyleHeight(float height) { + style.height = height; + } + + public float getLayoutX() { + return layout.x; + } + + public float getLayoutY() { + return layout.y; + } + + public float getLayoutWidth() { + return layout.x; + } + + public float getLayoutHeight() { + return layout.x; + } +} 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/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java new file mode 100644 index 00000000..4d1fd78d --- /dev/null +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -0,0 +1,600 @@ +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 boolean isUndefined(float f) { + return Float.compare(f, CSSConstants.UNDEFINED) == 0; + } + + 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 !isUndefined(getStyleDimension(node, getDim(axis))); + } + + private static boolean isPosDefined(CSSNode node, PositionIndex position) { + return !isUndefined(getStylePosition(node, position)); + } + + private static float getPosition(CSSNode node, PositionIndex position) { + float result = getStylePosition(node, position); + return 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 (!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 (!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)); + } + + /*package*/ static void layoutNode(CSSNode node, float parentMaxWidth) { + + // + // GENERATED LAYOUT CODE GOES BELOW -- see transpile.html + // (everything below this point is 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 (!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) && + isUndefined(getLayoutDimension(node, getDim(CSSFlexDirection.ROW))); + boolean isColumnUndefined = !isDimDefined(node, CSSFlexDirection.COLUMN) && + 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 && + !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 (!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 (!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 (!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 (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 (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); + } + } + } +} 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/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java new file mode 100644 index 00000000..1481e812 --- /dev/null +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -0,0 +1,2634 @@ +package com.facebook.csslayout; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests for {@link LayoutEngine} + */ +public class LayoutEngineTest { + + private static void test(String message, CSSNode style, CSSNode expectedLayout) { + style.calculateLayout(); + assertLayoutsEqual(message, style, expectedLayout); + } + + private static void addChildren(CSSNode node, int numChildren) { + for (int i = 0; i < numChildren; i++) { + node.addChildAt(new CSSNode(), 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; + } + + // + // GENERATED TEST CODE GOES BELOW -- see transpile.html + // (everything below this point is generated) + // + + @Test + public void testCase0() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 100; + node_0.style.height = 200; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 3); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + CSSNode 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); + { + CSSNode 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; + } + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 300; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.width = 1000; + addChildren(node_1, 1); + { + CSSNode node_2; + node_2 = node_1.getChildAt(0); + node_2.style.flex = 1; + node_2.style.width = 1000; + addChildren(node_2, 1); + { + CSSNode node_3; + node_3 = node_2.getChildAt(0); + node_3.style.flex = 1; + node_3.style.width = 1000; + } + } + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.CENTER; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.width = 100; + node_1.style.height = 100; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.CENTER; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.STRETCH; + node_0.style.width = 1000; + node_0.style.height = 1000; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.height = 100; + addChildren(node_0, 2); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 100; + node_1 = node_0.getChildAt(1); + node_1.style.height = 200; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.CENTER; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.FLEX_END; + node_0.style.height = 100; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginTop = 10; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignItems = CSSAlign.FLEX_END; + addChildren(node_1, 2); + { + CSSNode 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; + } + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.alignItems = CSSAlign.STRETCH; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginLeft = 10; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.paddingLeft = 5; + node_0.style.paddingTop = 5; + node_0.style.paddingRight = 5; + node_0.style.paddingBottom = 5; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.alignSelf = CSSAlign.STRETCH; + addChildren(node_1, 1); + { + CSSNode 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; + } + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.positionLeft = 5; + node_0.style.positionTop = 5; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.positionBottom = 5; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.positionTop = 10; + node_0.style.positionBottom = 5; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 500; + addChildren(node_0, 3); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.marginRight = 15; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.height = 5; + node_0.style.paddingBottom = 20; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 5; + node_0.style.paddingLeft = 20; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 2); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + addChildren(node_1, 1); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 5; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.marginTop = 5; + node_1.style.positionTop = 5; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.marginLeft = 5; + node_1.style.positionLeft = 5; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.justifyContent = CSSJustify.SPACE_AROUND; + node_0.style.height = 200; + addChildren(node_0, 2); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1 = node_0.getChildAt(1); + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 700; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.flex = 1; + node_1.style.marginLeft = 5; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 700; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 700; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.height = 300; + addChildren(node_0, 2); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 600; + node_1 = node_0.getChildAt(1); + node_1.style.flex = 1; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.width = 600; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.flex = 1; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.height = 500; + addChildren(node_0, 2); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.borderLeft = 5; + node_0.style.borderTop = 5; + node_0.style.borderRight = 5; + node_0.style.borderBottom = 5; + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.borderTop = 1; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionTop = -1; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode 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); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.positionType = CSSPositionType.ABSOLUTE; + node_1.style.positionLeft = 5; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.width = 50; + addChildren(node_0, 1); + { + CSSNode 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; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.borderRight = 5; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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() + { + CSSNode root_node = new CSSNode(); + { + CSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.borderRight = 1; + addChildren(node_0, 1); + { + CSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.marginRight = -8; + } + } + + CSSNode root_layout = new CSSNode(); + { + CSSNode 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); + { + CSSNode 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); + } +} diff --git a/src/transpile-java.js b/src/transpile-java.js new file mode 100644 index 00000000..49714368 --- /dev/null +++ b/src/transpile-java.js @@ -0,0 +1,86 @@ +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)') + + // 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 CSSNode') + .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, 'CSSNode$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; + }); +} + +function transpileLayoutEngineToJava(code) { + return __transpileToJavaCommon(code) + .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'); +} + +function transpileCTestsArrayToJava(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'); +} \ No newline at end of file diff --git a/src/transpile.html b/src/transpile.html index 179a4f9c..278bf0b6 100644 --- a/src/transpile.html +++ b/src/transpile.html @@ -7,13 +7,28 @@ textarea { border: 1px solid black; font-size: 12px; font-family: monospace; + margin-bottom: 20px; } -

layoutCode

- +

Layout Code

+

C

+ +

Java

+ + +

Tests

+

C

+ +

Java

+ + + - -

Tests

-