diff --git a/src/JavaTranspiler.js b/src/JavaTranspiler.js index 7d2c9148c0..53ccc85d66 100644 --- a/src/JavaTranspiler.js +++ b/src/JavaTranspiler.js @@ -77,13 +77,13 @@ function __transpileSingleTestToJava(code) { return 'style.' + match1 + match2[0] + match2.substring(1).toLowerCase(); }) .replace( // style.margin[CSS_TOP] = 12.3 => style.margin[Spacing.TOP].set(12.3) - /style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT)\]\s+=\s+(-?[\.\d]+)/g, + /style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]\s+=\s+(-?[\.\d]+)/g, function (str, match1, match2, match3) { var propertyCap = match1.charAt(0).toUpperCase() + match1.slice(1); return 'set' + propertyCap + '(Spacing.' + match2 + ', ' + match3 + ')'; }) - .replace( // style.margin[CSS_TOP] => style.margin.get(Spacing.TOP) - /style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT)\]/g, + .replace( // style.margin[CSS_TOP] => style.margin[Spacing.TOP] + /style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]/g, function (str, match1, match2) { return 'style.' + match1 + '.get(Spacing.' + match2 + ')'; }) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index f2b159592f..69a5766882 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -144,6 +144,10 @@ var layoutTestUtils = (function() { return layout; } + function capitalizeFirst(str) { + return str.charAt(0).toUpperCase() + str.slice(1); + } + function computeCSSLayout(rootNode) { fillNodes(rootNode); realComputeLayout(rootNode); @@ -155,8 +159,10 @@ var layoutTestUtils = (function() { function transfer(div, node, name, ext) { if (name in node.style) { - div.style['-webkit-' + name] = node.style[name] + (ext || ''); - div.style[name] = node.style[name] + (ext || ''); + var value = node.style[name] + (ext || ''); + div.style['-webkit-' + name] = value; + div.style['webkit' + capitalizeFirst(name)] = value; + div.style[name] = value; } } @@ -166,6 +172,8 @@ var layoutTestUtils = (function() { transfer(div, node, type + 'Top' + suffix, 'px'); transfer(div, node, type + 'Bottom' + suffix, 'px'); transfer(div, node, type + 'Right' + suffix, 'px'); + transfer(div, node, type + 'Start' + suffix, 'px'); + transfer(div, node, type + 'End' + suffix, 'px'); } function renderNode(parent, node) { diff --git a/src/Layout.c b/src/Layout.c index baa2d2cc82..4b697d2e90 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -54,6 +54,13 @@ void init_css_node(css_node_t *node) { node->style.position[CSS_RIGHT] = CSS_UNDEFINED; node->style.position[CSS_BOTTOM] = CSS_UNDEFINED; + node->style.margin[CSS_START] = CSS_UNDEFINED; + node->style.margin[CSS_END] = CSS_UNDEFINED; + node->style.padding[CSS_START] = CSS_UNDEFINED; + node->style.padding[CSS_END] = CSS_UNDEFINED; + node->style.border[CSS_START] = CSS_UNDEFINED; + node->style.border[CSS_END] = CSS_UNDEFINED; + node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED; node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED; @@ -170,6 +177,8 @@ static void print_css_node_rec( print_number_0("marginRight", node->style.margin[CSS_RIGHT]); print_number_0("marginTop", node->style.margin[CSS_TOP]); print_number_0("marginBottom", node->style.margin[CSS_BOTTOM]); + print_number_0("marginStart", node->style.margin[CSS_START]); + print_number_0("marginEnd", node->style.margin[CSS_END]); } if (four_equal(node->style.padding)) { @@ -179,6 +188,8 @@ static void print_css_node_rec( print_number_0("paddingRight", node->style.padding[CSS_RIGHT]); print_number_0("paddingTop", node->style.padding[CSS_TOP]); print_number_0("paddingBottom", node->style.padding[CSS_BOTTOM]); + print_number_0("paddingStart", node->style.padding[CSS_START]); + print_number_0("paddingEnd", node->style.padding[CSS_END]); } if (four_equal(node->style.border)) { @@ -188,6 +199,8 @@ static void print_css_node_rec( print_number_0("borderRightWidth", node->style.border[CSS_RIGHT]); print_number_0("borderTopWidth", node->style.border[CSS_TOP]); print_number_0("borderBottomWidth", node->style.border[CSS_BOTTOM]); + print_number_0("borderStartWidth", node->style.border[CSS_START]); + print_number_0("borderEndWidth", node->style.border[CSS_END]); } print_number_nan("width", node->style.dimensions[CSS_WIDTH]); @@ -245,39 +258,106 @@ static css_dimension_t dim[4] = { /* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH }; +static bool isRowDirection(css_flex_direction_t flex_direction) { + return flex_direction == CSS_FLEX_DIRECTION_ROW || + flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE; +} -static float getMargin(css_node_t *node, int location) { - return node->style.margin[location]; +static bool isColumnDirection(css_flex_direction_t flex_direction) { + return flex_direction == CSS_FLEX_DIRECTION_COLUMN || + flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE; } -static float getPadding(css_node_t *node, int location) { - if (node->style.padding[location] >= 0) { - return node->style.padding[location]; +static float getLeadingMargin(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_START])) { + return node->style.margin[CSS_START]; } + + return node->style.margin[leading[axis]]; +} + +static float getTrailingMargin(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_END])) { + return node->style.margin[CSS_END]; + } + + return node->style.margin[trailing[axis]]; +} + +static float getLeadingPadding(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.padding[CSS_START]) && + node->style.padding[CSS_START] >= 0) { + return node->style.padding[CSS_START]; + } + + if (node->style.padding[leading[axis]] >= 0) { + return node->style.padding[leading[axis]]; + } + return 0; } -static float getBorder(css_node_t *node, int location) { - if (node->style.border[location] >= 0) { - return node->style.border[location]; +static float getTrailingPadding(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.padding[CSS_END]) && + node->style.padding[CSS_END] >= 0) { + return node->style.padding[CSS_END]; + } + + if (node->style.padding[trailing[axis]] >= 0) { + return node->style.padding[trailing[axis]]; } + return 0; } -static float getPaddingAndBorder(css_node_t *node, int location) { - return getPadding(node, location) + getBorder(node, location); +static float getLeadingBorder(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.border[CSS_START]) && + node->style.border[CSS_START] >= 0) { + return node->style.border[CSS_START]; + } + + if (node->style.border[leading[axis]] >= 0) { + return node->style.border[leading[axis]]; + } + + return 0; +} + +static float getTrailingBorder(css_node_t *node, css_flex_direction_t axis) { + if (isRowDirection(axis) && + !isUndefined(node->style.border[CSS_END]) && + node->style.border[CSS_END] >= 0) { + return node->style.border[CSS_END]; + } + + if (node->style.border[trailing[axis]] >= 0) { + return node->style.border[trailing[axis]]; + } + + return 0; +} + +static float getLeadingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { + return getLeadingPadding(node, axis) + getLeadingBorder(node, axis); +} + +static float getTrailingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) { + return getTrailingPadding(node, axis) + getTrailingBorder(node, axis); } static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) { - return getBorder(node, leading[axis]) + getBorder(node, trailing[axis]); + return getLeadingBorder(node, axis) + getTrailingBorder(node, axis); } static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) { - return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]); + return getLeadingMargin(node, axis) + getTrailingMargin(node, axis); } static float getPaddingAndBorderAxis(css_node_t *node, css_flex_direction_t axis) { - return getPaddingAndBorder(node, leading[axis]) + getPaddingAndBorder(node, trailing[axis]); + return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis); } static css_position_type_t getPositionType(css_node_t *node) { @@ -295,16 +375,6 @@ static css_align_t getAlignItem(css_node_t *node, css_node_t *child) { return node->style.align_items; } -static bool isRowDirection(css_flex_direction_t flex_direction) { - return flex_direction == CSS_FLEX_DIRECTION_ROW || - flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE; -} - -static bool isColumnDirection(css_flex_direction_t flex_direction) { - return flex_direction == CSS_FLEX_DIRECTION_COLUMN || - flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE; -} - static css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) { css_direction_t direction = node->style.direction; @@ -356,8 +426,8 @@ static bool isFlexWrap(css_node_t *node) { static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) { return node->layout.dimensions[dim[axis]] + - getMargin(node, leading[axis]) + - getMargin(node, trailing[axis]); + getLeadingMargin(node, axis) + + getTrailingMargin(node, axis); } static bool isDimDefined(css_node_t *node, css_flex_direction_t axis) { @@ -451,13 +521,13 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction // 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 - node->layout.position[leading[mainAxis]] += getMargin(node, leading[mainAxis]) + + node->layout.position[leading[mainAxis]] += getLeadingMargin(node, mainAxis) + getRelativePosition(node, mainAxis); - node->layout.position[trailing[mainAxis]] += getMargin(node, trailing[mainAxis]) + + node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) + getRelativePosition(node, mainAxis); - node->layout.position[leading[crossAxis]] += getMargin(node, leading[crossAxis]) + + node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) + getRelativePosition(node, crossAxis); - node->layout.position[trailing[crossAxis]] += getMargin(node, trailing[crossAxis]) + + node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) + getRelativePosition(node, crossAxis); if (isMeasureDefined(node)) { @@ -740,7 +810,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction // container! float crossDim = 0; float mainDim = leadingMainDim + - getPaddingAndBorder(node, leading[mainAxis]); + getLeadingPaddingAndBorder(node, mainAxis); for (i = startLine; i < endLine; ++i) { child = node->get_child(node->context, i); @@ -751,8 +821,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction // defined, we override the position to whatever the user said // (and margin/border). child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) + - getBorder(node, leading[mainAxis]) + - getMargin(child, leading[mainAxis]); + getLeadingBorder(node, mainAxis) + + getLeadingMargin(child, mainAxis); } else { // If the child is position absolute (without top/left) or relative, // we put it at the current accumulated offset. @@ -799,11 +869,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction // top/left/bottom/right being set, we override all the previously // computed positions to set it correctly. child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) + - getBorder(node, leading[crossAxis]) + - getMargin(child, leading[crossAxis]); + getLeadingBorder(node, crossAxis) + + getLeadingMargin(child, crossAxis); } else { - float leadingCrossDim = getPaddingAndBorder(node, leading[crossAxis]); + float leadingCrossDim = getLeadingPaddingAndBorder(node, crossAxis); // For a relative children, we're either using alignItems (parent) or // alignSelf (child) in order to determine the position in the cross axis @@ -838,6 +908,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction // And we apply the position child->layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim; + + // Define the trailing position accordingly. + if (!isUndefined(node->layout.dimensions[dim[crossAxis]])) { + setTrailingPosition(node, child, crossAxis); + } } } @@ -846,22 +921,21 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction startLine = endLine; } + bool needsMainTrailingPos = false; + bool needsCrossTrailingPos = false; + // 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(node->layout.dimensions[dim[mainAxis]])) { node->layout.dimensions[dim[mainAxis]] = fmaxf( // We're missing the last padding at this point to get the final // dimension - boundAxis(node, mainAxis, linesMainDim + getPaddingAndBorder(node, trailing[mainAxis])), + boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) ); - // Now that the width is defined, we should update the trailing - // positions for the children. - for (i = 0; i < node->children_count; ++i) { - setTrailingPosition(node, node->get_child(node->context, i), mainAxis); - } + needsMainTrailingPos = true; } if (isUndefined(node->layout.dimensions[dim[crossAxis]])) { @@ -872,9 +946,27 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)), getPaddingAndBorderAxis(node, crossAxis) ); + + needsCrossTrailingPos = true; + } + + // Set trailing position if necessary + + if (needsMainTrailingPos || needsCrossTrailingPos) { + for (i = 0; i < node->children_count; ++i) { + child = node->get_child(node->context, i); + + if (needsMainTrailingPos) { + setTrailingPosition(node, child, mainAxis); + } + + if (needsCrossTrailingPos) { + setTrailingPosition(node, child, crossAxis); + } + } } - // Calculate dimensions for absolutely positioned elements + // Calculate dimensions for absolutely positioned elements for (i = 0; i < node->children_count; ++i) { child = node->get_child(node->context, i); diff --git a/src/Layout.h b/src/Layout.h index c07dde72bc..2e737e571d 100644 --- a/src/Layout.h +++ b/src/Layout.h @@ -71,6 +71,8 @@ typedef enum { CSS_TOP, CSS_RIGHT, CSS_BOTTOM, + CSS_START, + CSS_END, CSS_POSITION_COUNT } css_position_t; @@ -106,7 +108,7 @@ typedef struct { css_position_type_t position_type; css_wrap_type_t flex_wrap; float flex; - float margin[4]; + float margin[6]; float position[4]; /** * You should skip all the rules that contain negative values for the @@ -118,8 +120,8 @@ typedef struct { * {left: -5 ...} * {left: 0 ...} */ - float padding[4]; - float border[4]; + float padding[6]; + float border[6]; float dimensions[2]; float minDimensions[2]; float maxDimensions[2]; diff --git a/src/Layout.js b/src/Layout.js index 6d09517ae4..300bf2bd1d 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -63,15 +63,19 @@ var computeLayout = (function() { return str.charAt(0).toUpperCase() + str.slice(1); } - function getSpacing(node, type, suffix, location) { - var key = type + capitalizeFirst(location) + suffix; - if (key in node.style) { - return node.style[key]; - } + function getSpacing(node, type, suffix, locations) { + for (var i = 0; i < locations.length; ++i) { + var location = locations[i]; + + var key = type + capitalizeFirst(location) + suffix; + if (key in node.style) { + return node.style[key]; + } - key = type + suffix; - if (key in node.style) { - return node.style[key]; + key = type + suffix; + if (key in node.style) { + return node.style[key]; + } } return 0; @@ -111,15 +115,19 @@ var computeLayout = (function() { return layout; } - function getPositiveSpacing(node, type, suffix, location) { - var key = type + capitalizeFirst(location) + suffix; - if (key in node.style && node.style[key] >= 0) { - return node.style[key]; - } + function getPositiveSpacing(node, type, suffix, locations) { + for (var i = 0; i < locations.length; ++i) { + var location = locations[i]; - key = type + suffix; - if (key in node.style && node.style[key] >= 0) { - return node.style[key]; + var key = type + capitalizeFirst(location) + suffix; + if (key in node.style && node.style[key] >= 0) { + return node.style[key]; + } + + key = type + suffix; + if (key in node.style && node.style[key] >= 0) { + return node.style[key]; + } } return 0; @@ -129,32 +137,89 @@ var computeLayout = (function() { return value === undefined; } - function getMargin(node, location) { - return getSpacing(node, 'margin', '', location); + function isRowDirection(flexDirection) { + return flexDirection === CSS_FLEX_DIRECTION_ROW || + flexDirection === CSS_FLEX_DIRECTION_ROW_REVERSE; + } + + function isColumnDirection(flexDirection) { + return flexDirection === CSS_FLEX_DIRECTION_COLUMN || + flexDirection === CSS_FLEX_DIRECTION_COLUMN_REVERSE; + } + + function getLeadingLocations(axis) { + var locations = [leading[axis]]; + if (isRowDirection(axis)) { + locations.unshift('start'); + } + + return locations; + } + + function getTrailingLocations(axis) { + var locations = [trailing[axis]]; + if (isRowDirection(axis)) { + locations.unshift('end'); + } + + return locations; + } + + function getMargin(node, locations) { + return getSpacing(node, 'margin', '', locations); + } + + function getLeadingMargin(node, axis) { + return getMargin(node, getLeadingLocations(axis)); + } + + function getTrailingMargin(node, axis) { + return getMargin(node, getTrailingLocations(axis)); + } + + function getPadding(node, locations) { + return getPositiveSpacing(node, 'padding', '', locations); + } + + function getLeadingPadding(node, axis) { + return getPadding(node, getLeadingLocations(axis)); } - function getPadding(node, location) { - return getPositiveSpacing(node, 'padding', '', location); + function getTrailingPadding(node, axis) { + return getPadding(node, getTrailingLocations(axis)); } - function getBorder(node, location) { - return getPositiveSpacing(node, 'border', 'Width', location); + function getBorder(node, locations) { + return getPositiveSpacing(node, 'border', 'Width', locations); } - function getPaddingAndBorder(node, location) { - return getPadding(node, location) + getBorder(node, location); + function getLeadingBorder(node, axis) { + return getBorder(node, getLeadingLocations(axis)); + } + + function getTrailingBorder(node, axis) { + return getBorder(node, getTrailingLocations(axis)); + } + + function getLeadingPaddingAndBorder(node, axis) { + return getLeadingPadding(node, axis) + getLeadingBorder(node, axis); + } + + function getTrailingPaddingAndBorder(node, axis) { + return getTrailingPadding(node, axis) + getTrailingBorder(node, axis); } function getBorderAxis(node, axis) { - return getBorder(node, leading[axis]) + getBorder(node, trailing[axis]); + return getLeadingBorder(node, axis) + getTrailingBorder(node, axis); } function getMarginAxis(node, axis) { - return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]); + return getLeadingMargin(node, axis) + getTrailingMargin(node, axis); } function getPaddingAndBorderAxis(node, axis) { - return getPaddingAndBorder(node, leading[axis]) + getPaddingAndBorder(node, trailing[axis]); + return getLeadingPaddingAndBorder(node, axis) + + getTrailingPaddingAndBorder(node, axis); } function getJustifyContent(node) { @@ -174,16 +239,6 @@ var computeLayout = (function() { return 'stretch'; } - function isRowDirection(flexDirection) { - return flexDirection === CSS_FLEX_DIRECTION_ROW || - flexDirection === CSS_FLEX_DIRECTION_ROW_REVERSE; - } - - function isColumnDirection(flexDirection) { - return flexDirection === CSS_FLEX_DIRECTION_COLUMN || - flexDirection === CSS_FLEX_DIRECTION_COLUMN_REVERSE; - } - function resolveAxis(axis, direction) { if (direction === CSS_DIRECTION_RTL) { if (axis === CSS_FLEX_DIRECTION_ROW) { @@ -347,13 +402,13 @@ var computeLayout = (function() { // 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 - node.layout[leading[mainAxis]] += getMargin(node, leading[mainAxis]) + + node.layout[leading[mainAxis]] += getLeadingMargin(node, mainAxis) + getRelativePosition(node, mainAxis); - node.layout[trailing[mainAxis]] += getMargin(node, trailing[mainAxis]) + + node.layout[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) + getRelativePosition(node, mainAxis); - node.layout[leading[crossAxis]] += getMargin(node, leading[crossAxis]) + + node.layout[leading[crossAxis]] += getLeadingMargin(node, crossAxis) + getRelativePosition(node, crossAxis); - node.layout[trailing[crossAxis]] += getMargin(node, trailing[crossAxis]) + + node.layout[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) + getRelativePosition(node, crossAxis); if (isMeasureDefined(node)) { @@ -636,7 +691,7 @@ var computeLayout = (function() { // container! var/*float*/ crossDim = 0; var/*float*/ mainDim = leadingMainDim + - getPaddingAndBorder(node, leading[mainAxis]); + getLeadingPaddingAndBorder(node, mainAxis); for (i = startLine; i < endLine; ++i) { child = node.children[i]; @@ -647,8 +702,8 @@ var computeLayout = (function() { // defined, we override the position to whatever the user said // (and margin/border). child.layout[pos[mainAxis]] = getPosition(child, leading[mainAxis]) + - getBorder(node, leading[mainAxis]) + - getMargin(child, leading[mainAxis]); + getLeadingBorder(node, mainAxis) + + getLeadingMargin(child, mainAxis); } else { // If the child is position absolute (without top/left) or relative, // we put it at the current accumulated offset. @@ -695,11 +750,11 @@ var computeLayout = (function() { // top/left/bottom/right being set, we override all the previously // computed positions to set it correctly. child.layout[pos[crossAxis]] = getPosition(child, leading[crossAxis]) + - getBorder(node, leading[crossAxis]) + - getMargin(child, leading[crossAxis]); + getLeadingBorder(node, crossAxis) + + getLeadingMargin(child, crossAxis); } else { - var/*float*/ leadingCrossDim = getPaddingAndBorder(node, leading[crossAxis]); + var/*float*/ leadingCrossDim = getLeadingPaddingAndBorder(node, crossAxis); // For a relative children, we're either using alignItems (parent) or // alignSelf (child) in order to determine the position in the cross axis @@ -734,6 +789,11 @@ var computeLayout = (function() { // And we apply the position child.layout[pos[crossAxis]] += linesCrossDim + leadingCrossDim; + + // Define the trailing position accordingly. + if (!isUndefined(node.layout[dim[crossAxis]])) { + setTrailingPosition(node, child, crossAxis); + } } } @@ -742,22 +802,21 @@ var computeLayout = (function() { startLine = endLine; } + var/*bool*/ needsMainTrailingPos = false; + var/*bool*/ needsCrossTrailingPos = false; + // 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(node.layout[dim[mainAxis]])) { node.layout[dim[mainAxis]] = fmaxf( // We're missing the last padding at this point to get the final // dimension - boundAxis(node, mainAxis, linesMainDim + getPaddingAndBorder(node, trailing[mainAxis])), + boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) ); - // Now that the width is defined, we should update the trailing - // positions for the children. - for (i = 0; i < node.children.length; ++i) { - setTrailingPosition(node, node.children[i], mainAxis); - } + needsMainTrailingPos = true; } if (isUndefined(node.layout[dim[crossAxis]])) { @@ -768,9 +827,27 @@ var computeLayout = (function() { boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)), getPaddingAndBorderAxis(node, crossAxis) ); + + needsCrossTrailingPos = true; + } + + // Set trailing position if necessary + + if (needsMainTrailingPos || needsCrossTrailingPos) { + for (i = 0; i < node.children.length; ++i) { + child = node.children[i]; + + if (needsMainTrailingPos) { + setTrailingPosition(node, child, mainAxis); + } + + if (needsCrossTrailingPos) { + setTrailingPosition(node, child, crossAxis); + } + } } - // Calculate dimensions for absolutely positioned elements + // Calculate dimensions for absolutely positioned elements for (i = 0; i < node.children.length; ++i) { child = node.children[i]; diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c index 6a67bb4cbc..917ed223e8 100644 --- a/src/__tests__/Layout-test.c +++ b/src/__tests__/Layout-test.c @@ -287,6 +287,8 @@ int main() node_0->style.margin[CSS_TOP] = 10; node_0->style.margin[CSS_RIGHT] = 10; node_0->style.margin[CSS_BOTTOM] = 10; + node_0->style.margin[CSS_START] = 10; + node_0->style.margin[CSS_END] = 10; } css_node_t *root_layout = new_test_css_node(); @@ -311,6 +313,8 @@ int main() node_0->style.margin[CSS_TOP] = 10; node_0->style.margin[CSS_RIGHT] = 10; node_0->style.margin[CSS_BOTTOM] = 10; + node_0->style.margin[CSS_START] = 10; + node_0->style.margin[CSS_END] = 10; init_css_node_children(node_0, 3); { css_node_t *node_1; @@ -321,6 +325,8 @@ int main() node_1->style.margin[CSS_TOP] = 50; node_1->style.margin[CSS_RIGHT] = 50; node_1->style.margin[CSS_BOTTOM] = 50; + node_1->style.margin[CSS_START] = 50; + node_1->style.margin[CSS_END] = 50; node_1 = node_0->get_child(node_0->context, 1); node_1->style.dimensions[CSS_WIDTH] = 100; node_1->style.dimensions[CSS_HEIGHT] = 100; @@ -328,6 +334,8 @@ int main() node_1->style.margin[CSS_TOP] = 25; node_1->style.margin[CSS_RIGHT] = 25; node_1->style.margin[CSS_BOTTOM] = 25; + node_1->style.margin[CSS_START] = 25; + node_1->style.margin[CSS_END] = 25; node_1 = node_0->get_child(node_0->context, 2); node_1->style.dimensions[CSS_WIDTH] = 100; node_1->style.dimensions[CSS_HEIGHT] = 100; @@ -335,6 +343,8 @@ int main() node_1->style.margin[CSS_TOP] = 10; node_1->style.margin[CSS_RIGHT] = 10; node_1->style.margin[CSS_BOTTOM] = 10; + node_1->style.margin[CSS_START] = 10; + node_1->style.margin[CSS_END] = 10; } } @@ -380,6 +390,8 @@ int main() node_0->style.margin[CSS_TOP] = 10; node_0->style.margin[CSS_RIGHT] = 10; node_0->style.margin[CSS_BOTTOM] = 10; + node_0->style.margin[CSS_START] = 10; + node_0->style.margin[CSS_END] = 10; init_css_node_children(node_0, 3); { css_node_t *node_1; @@ -390,6 +402,8 @@ int main() node_1->style.margin[CSS_TOP] = 50; node_1->style.margin[CSS_RIGHT] = 50; node_1->style.margin[CSS_BOTTOM] = 50; + node_1->style.margin[CSS_START] = 50; + node_1->style.margin[CSS_END] = 50; node_1 = node_0->get_child(node_0->context, 1); node_1->style.dimensions[CSS_WIDTH] = 100; node_1->style.dimensions[CSS_HEIGHT] = 100; @@ -397,6 +411,8 @@ int main() node_1->style.margin[CSS_TOP] = 25; node_1->style.margin[CSS_RIGHT] = 25; node_1->style.margin[CSS_BOTTOM] = 25; + node_1->style.margin[CSS_START] = 25; + node_1->style.margin[CSS_END] = 25; node_1 = node_0->get_child(node_0->context, 2); node_1->style.dimensions[CSS_WIDTH] = 100; node_1->style.dimensions[CSS_HEIGHT] = 100; @@ -404,6 +420,8 @@ int main() node_1->style.margin[CSS_TOP] = 10; node_1->style.margin[CSS_RIGHT] = 10; node_1->style.margin[CSS_BOTTOM] = 10; + node_1->style.margin[CSS_START] = 10; + node_1->style.margin[CSS_END] = 10; } } @@ -2000,6 +2018,8 @@ int main() node_1->style.margin[CSS_TOP] = 5; node_1->style.margin[CSS_RIGHT] = 5; node_1->style.margin[CSS_BOTTOM] = 5; + node_1->style.margin[CSS_START] = 5; + node_1->style.margin[CSS_END] = 5; } } @@ -2037,6 +2057,8 @@ int main() node_1->style.margin[CSS_TOP] = 5; node_1->style.margin[CSS_RIGHT] = 5; node_1->style.margin[CSS_BOTTOM] = 5; + node_1->style.margin[CSS_START] = 5; + node_1->style.margin[CSS_END] = 5; } } @@ -2251,6 +2273,8 @@ int main() node_2->style.margin[CSS_TOP] = 10; node_2->style.margin[CSS_RIGHT] = 10; node_2->style.margin[CSS_BOTTOM] = 10; + node_2->style.margin[CSS_START] = 10; + node_2->style.margin[CSS_END] = 10; node_2 = node_1->get_child(node_1->context, 1); node_2->style.dimensions[CSS_HEIGHT] = 100; } @@ -2310,6 +2334,8 @@ int main() node_2->style.margin[CSS_TOP] = 10; node_2->style.margin[CSS_RIGHT] = 10; node_2->style.margin[CSS_BOTTOM] = 10; + node_2->style.margin[CSS_START] = 10; + node_2->style.margin[CSS_END] = 10; node_2 = node_1->get_child(node_1->context, 1); node_2->style.dimensions[CSS_HEIGHT] = 100; } @@ -2461,6 +2487,8 @@ int main() node_0->style.padding[CSS_TOP] = 5; node_0->style.padding[CSS_RIGHT] = 5; node_0->style.padding[CSS_BOTTOM] = 5; + node_0->style.padding[CSS_START] = 5; + node_0->style.padding[CSS_END] = 5; } css_node_t *root_layout = new_test_css_node(); @@ -2483,6 +2511,8 @@ int main() node_0->style.padding[CSS_TOP] = 5; node_0->style.padding[CSS_RIGHT] = 5; node_0->style.padding[CSS_BOTTOM] = 5; + node_0->style.padding[CSS_START] = 5; + node_0->style.padding[CSS_END] = 5; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -2519,6 +2549,8 @@ int main() node_0->style.padding[CSS_TOP] = 5; node_0->style.padding[CSS_RIGHT] = 5; node_0->style.padding[CSS_BOTTOM] = 5; + node_0->style.padding[CSS_START] = 5; + node_0->style.padding[CSS_END] = 5; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -2527,6 +2559,8 @@ int main() node_1->style.margin[CSS_TOP] = 5; node_1->style.margin[CSS_RIGHT] = 5; node_1->style.margin[CSS_BOTTOM] = 5; + node_1->style.margin[CSS_START] = 5; + node_1->style.margin[CSS_END] = 5; } } @@ -2564,6 +2598,8 @@ int main() node_1->style.padding[CSS_TOP] = 10; node_1->style.padding[CSS_RIGHT] = 10; node_1->style.padding[CSS_BOTTOM] = 10; + node_1->style.padding[CSS_START] = 10; + node_1->style.padding[CSS_END] = 10; } } @@ -2596,6 +2632,8 @@ int main() node_0->style.padding[CSS_TOP] = 50; node_0->style.padding[CSS_RIGHT] = 50; node_0->style.padding[CSS_BOTTOM] = 50; + node_0->style.padding[CSS_START] = 50; + node_0->style.padding[CSS_END] = 50; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -2605,6 +2643,8 @@ int main() node_1->style.padding[CSS_TOP] = 10; node_1->style.padding[CSS_RIGHT] = 10; node_1->style.padding[CSS_BOTTOM] = 10; + node_1->style.padding[CSS_START] = 10; + node_1->style.padding[CSS_END] = 10; } } @@ -2646,6 +2686,8 @@ int main() node_2->style.margin[CSS_TOP] = 16; node_2->style.margin[CSS_RIGHT] = 16; node_2->style.margin[CSS_BOTTOM] = 16; + node_2->style.margin[CSS_START] = 16; + node_2->style.margin[CSS_END] = 16; } } } @@ -2996,6 +3038,8 @@ int main() node_0->style.padding[CSS_TOP] = 5; node_0->style.padding[CSS_RIGHT] = 5; node_0->style.padding[CSS_BOTTOM] = 5; + node_0->style.padding[CSS_START] = 5; + node_0->style.padding[CSS_END] = 5; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -3075,6 +3119,8 @@ int main() node_0->style.padding[CSS_TOP] = 20; node_0->style.padding[CSS_RIGHT] = 20; node_0->style.padding[CSS_BOTTOM] = 20; + node_0->style.padding[CSS_START] = 20; + node_0->style.padding[CSS_END] = 20; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -3669,6 +3715,8 @@ int main() node_0->style.border[CSS_TOP] = 5; node_0->style.border[CSS_RIGHT] = 5; node_0->style.border[CSS_BOTTOM] = 5; + node_0->style.border[CSS_START] = 5; + node_0->style.border[CSS_END] = 5; } css_node_t *root_layout = new_test_css_node(); @@ -3726,6 +3774,8 @@ int main() node_0->style.border[CSS_TOP] = 1; node_0->style.border[CSS_RIGHT] = 1; node_0->style.border[CSS_BOTTOM] = 1; + node_0->style.border[CSS_START] = 1; + node_0->style.border[CSS_END] = 1; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -3771,6 +3821,8 @@ int main() node_1->style.padding[CSS_TOP] = 20; node_1->style.padding[CSS_RIGHT] = 20; node_1->style.padding[CSS_BOTTOM] = 20; + node_1->style.padding[CSS_START] = 20; + node_1->style.padding[CSS_END] = 20; } } @@ -4263,6 +4315,8 @@ int main() node_0->style.padding[CSS_TOP] = 10; node_0->style.padding[CSS_RIGHT] = 10; node_0->style.padding[CSS_BOTTOM] = 10; + node_0->style.padding[CSS_START] = 10; + node_0->style.padding[CSS_END] = 10; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -4272,6 +4326,8 @@ int main() node_1->style.margin[CSS_TOP] = 10; node_1->style.margin[CSS_RIGHT] = 10; node_1->style.margin[CSS_BOTTOM] = 10; + node_1->style.margin[CSS_START] = 10; + node_1->style.margin[CSS_END] = 10; init_css_node_children(node_1, 1); { css_node_t *node_2; @@ -4486,6 +4542,8 @@ int main() node_2->style.margin[CSS_TOP] = 20; node_2->style.margin[CSS_RIGHT] = 20; node_2->style.margin[CSS_BOTTOM] = 20; + node_2->style.margin[CSS_START] = 20; + node_2->style.margin[CSS_END] = 20; node_2->measure = measure; node_2->context = "loooooooooong with space"; } @@ -4541,6 +4599,8 @@ int main() node_2->style.margin[CSS_TOP] = 20; node_2->style.margin[CSS_RIGHT] = 20; node_2->style.margin[CSS_BOTTOM] = 20; + node_2->style.margin[CSS_START] = 20; + node_2->style.margin[CSS_END] = 20; node_2->measure = measure; node_2->context = "loooooooooong with space"; } @@ -4594,6 +4654,8 @@ int main() node_2->style.margin[CSS_TOP] = 20; node_2->style.margin[CSS_RIGHT] = 20; node_2->style.margin[CSS_BOTTOM] = 20; + node_2->style.margin[CSS_START] = 20; + node_2->style.margin[CSS_END] = 20; node_2->measure = measure; node_2->context = "loooooooooong with space"; } @@ -6723,6 +6785,8 @@ int main() node_1->style.padding[CSS_TOP] = 10; node_1->style.padding[CSS_RIGHT] = 10; node_1->style.padding[CSS_BOTTOM] = 10; + node_1->style.padding[CSS_START] = 10; + node_1->style.padding[CSS_END] = 10; node_1->style.position[CSS_LEFT] = 100; node_1->style.position[CSS_TOP] = 100; node_1->style.position[CSS_RIGHT] = 100; @@ -6785,10 +6849,14 @@ int main() node_1->style.padding[CSS_TOP] = 10; node_1->style.padding[CSS_RIGHT] = 10; node_1->style.padding[CSS_BOTTOM] = 10; + node_1->style.padding[CSS_START] = 10; + node_1->style.padding[CSS_END] = 10; node_1->style.border[CSS_LEFT] = 1; node_1->style.border[CSS_TOP] = 1; node_1->style.border[CSS_RIGHT] = 1; node_1->style.border[CSS_BOTTOM] = 1; + node_1->style.border[CSS_START] = 1; + node_1->style.border[CSS_END] = 1; node_1->style.position[CSS_LEFT] = 100; node_1->style.position[CSS_TOP] = 100; node_1->style.position[CSS_RIGHT] = 100; @@ -6851,6 +6919,8 @@ int main() node_1->style.padding[CSS_TOP] = 10; node_1->style.padding[CSS_RIGHT] = 10; node_1->style.padding[CSS_BOTTOM] = 10; + node_1->style.padding[CSS_START] = 10; + node_1->style.padding[CSS_END] = 10; init_css_node_children(node_1, 1); { css_node_t *node_2; @@ -7064,6 +7134,339 @@ int main() test("should correctly space wrapped nodes", root_node, root_layout); } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 200; + node_0->style.padding[CSS_LEFT] = 5; + node_0->style.padding[CSS_RIGHT] = 5; + node_0->style.padding[CSS_START] = 15; + node_0->style.padding[CSS_END] = 15; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 15; + node_1->layout.dimensions[CSS_WIDTH] = 170; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should give start/end padding precedence over left/right padding", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 5; + node_1->style.margin[CSS_RIGHT] = 5; + node_1->style.margin[CSS_START] = 15; + node_1->style.margin[CSS_END] = 15; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 15; + node_1->layout.dimensions[CSS_WIDTH] = 170; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should give start/end margin precedence over left/right margin", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 200; + node_0->style.border[CSS_LEFT] = 5; + node_0->style.border[CSS_RIGHT] = 5; + node_0->style.border[CSS_START] = 15; + node_0->style.border[CSS_END] = 15; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 15; + node_1->layout.dimensions[CSS_WIDTH] = 170; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should give start/end border precedence over left/right border", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 200; + node_0->style.padding[CSS_START] = 15; + node_0->style.padding[CSS_END] = 5; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 15; + node_1->layout.dimensions[CSS_WIDTH] = 180; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should layout node with correct start/end padding", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.direction = CSS_DIRECTION_RTL; + node_0->style.dimensions[CSS_WIDTH] = 200; + node_0->style.padding[CSS_START] = 15; + node_0->style.padding[CSS_END] = 5; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 5; + node_1->layout.dimensions[CSS_WIDTH] = 180; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should layout node with correct start/end padding in rtl", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_START] = 15; + node_1->style.margin[CSS_END] = 5; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 15; + node_1->layout.dimensions[CSS_WIDTH] = 180; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should layout node with correct start/end margin", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 200; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.direction = CSS_DIRECTION_RTL; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_START] = 15; + node_1->style.margin[CSS_END] = 5; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 5; + node_1->layout.dimensions[CSS_WIDTH] = 180; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should layout node with correct start/end margin in rtl", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.dimensions[CSS_WIDTH] = 200; + node_0->style.border[CSS_START] = 15; + node_0->style.border[CSS_END] = 5; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 15; + node_1->layout.dimensions[CSS_WIDTH] = 180; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should layout node with correct start/end border", root_node, root_layout); + } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.direction = CSS_DIRECTION_RTL; + node_0->style.dimensions[CSS_WIDTH] = 200; + node_0->style.border[CSS_START] = 15; + node_0->style.border[CSS_END] = 5; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_HEIGHT] = 50; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 200; + node_0->layout.dimensions[CSS_HEIGHT] = 50; + init_css_node_children(node_0, 1); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 0; + node_1->layout.position[CSS_LEFT] = 5; + node_1->layout.dimensions[CSS_WIDTH] = 180; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should layout node with correct start/end border in rtl", root_node, root_layout); + } /** END_GENERATED **/ return tests_finished(); } diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index 399e6a6c0b..d219acf3ad 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -2185,7 +2185,7 @@ describe('Layout', function() { ]} ); }); - + it('should correctly space wrapped nodes', function() { testLayout( {style: {width: 320, height: 200, flexDirection: 'row', justifyContent: 'space-between', flexWrap: 'wrap'}, children: [ @@ -2206,4 +2206,103 @@ describe('Layout', function() { ]} ); }); + + it('should give start/end padding precedence over left/right padding', function() { + testLayout( + {style: {width: 200, paddingLeft: 5, paddingStart: 15, paddingRight: 5, paddingEnd: 15}, children: [ + {style: {height: 50}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 170, height: 50, top: 0, left: 15} + ]} + ); + }); + + it('should give start/end margin precedence over left/right margin', function() { + testLayout( + {style: {width: 200}, children: [ + {style: {height: 50, marginLeft: 5, marginStart: 15, marginRight: 5, marginEnd: 15}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 170, height: 50, top: 0, left: 15} + ]} + ); + }); + + it('should give start/end border precedence over left/right border', function() { + testLayout( + {style: {width: 200, borderLeftWidth: 5, borderStartWidth: 15, borderRightWidth: 5, borderEndWidth: 15}, children: [ + {style: {height: 50}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 170, height: 50, top: 0, left: 15} + ]} + ); + }); + + it('should layout node with correct start/end padding', function() { + testLayout( + {style: {width: 200, paddingStart: 15, paddingEnd: 5}, children: [ + {style: {height: 50}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 180, height: 50, top: 0, left: 15} + ]} + ); + }); + + it('should layout node with correct start/end padding in rtl', function() { + testLayout( + {style: {width: 200, direction: 'rtl', paddingStart: 15, paddingEnd: 5}, children: [ + {style: {height: 50}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 180, height: 50, top: 0, left: 5} + ]} + ); + }); + + it('should layout node with correct start/end margin', function() { + testLayout( + {style: {width: 200}, children: [ + {style: {height: 50, marginStart: 15, marginEnd: 5}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 180, height: 50, top: 0, left: 15} + ]} + ); + }); + + it('should layout node with correct start/end margin in rtl', function() { + testLayout( + {style: {width: 200}, children: [ + {style: {height: 50, direction: 'rtl', marginStart: 15, marginEnd: 5}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 180, height: 50, top: 0, left: 5} + ]} + ); + }); + + it('should layout node with correct start/end border', function() { + testLayout( + {style: {width: 200, borderStartWidth: 15, borderEndWidth: 5}, children: [ + {style: {height: 50}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 180, height: 50, top: 0, left: 15} + ]} + ); + }); + + it('should layout node with correct start/end border in rtl', function() { + testLayout( + {style: {width: 200, direction: 'rtl', borderStartWidth: 15, borderEndWidth: 5}, children: [ + {style: {height: 50}} + ]}, + {width: 200, height: 50, top: 0, left: 0, children: [ + {width: 180, height: 50, top: 0, left: 5} + ]} + ); + }); }); diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java index c96dd17c74..41e895a27e 100644 --- a/src/java/src/com/facebook/csslayout/LayoutEngine.java +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -18,6 +18,8 @@ private static enum PositionIndex { LEFT, BOTTOM, RIGHT, + START, + END, } private static enum DimensionIndex { @@ -191,11 +193,37 @@ private static float getMargin(CSSNode node, PositionIndex position) { return node.style.margin.get(Spacing.LEFT); case RIGHT: return node.style.margin.get(Spacing.RIGHT); + case START: + return node.style.margin.get(Spacing.START); + case END: + return node.style.margin.get(Spacing.END); default: throw new RuntimeException("Someone added a new cardinal direction..."); } } + private static float getLeadingMargin(CSSNode node, CSSFlexDirection axis) { + if (isRowDirection(axis)) { + float leadingMargin = getMargin(node, PositionIndex.START); + if (!CSSConstants.isUndefined(leadingMargin)) { + return leadingMargin; + } + } + + return getMargin(node, getLeading(axis)); + } + + private static float getTrailingMargin(CSSNode node, CSSFlexDirection axis) { + if (isRowDirection(axis)) { + float trailingMargin = getMargin(node, PositionIndex.END); + if (!CSSConstants.isUndefined(trailingMargin)) { + return trailingMargin; + } + } + + return getMargin(node, getTrailing(axis)); + } + private static float getPadding(CSSNode node, PositionIndex position) { switch (position) { case TOP: @@ -206,11 +234,37 @@ private static float getPadding(CSSNode node, PositionIndex position) { return node.style.padding.get(Spacing.LEFT); case RIGHT: return node.style.padding.get(Spacing.RIGHT); + case START: + return node.style.padding.get(Spacing.START); + case END: + return node.style.padding.get(Spacing.END); default: throw new RuntimeException("Someone added a new cardinal direction..."); } } + private static float getLeadingPadding(CSSNode node, CSSFlexDirection axis) { + if (isRowDirection(axis)) { + float leadingPadding = getPadding(node, PositionIndex.START); + if (!CSSConstants.isUndefined(leadingPadding)) { + return leadingPadding; + } + } + + return getPadding(node, getLeading(axis)); + } + + private static float getTrailingPadding(CSSNode node, CSSFlexDirection axis) { + if (isRowDirection(axis)) { + float trailingPadding = getPadding(node, PositionIndex.END); + if (!CSSConstants.isUndefined(trailingPadding)) { + return trailingPadding; + } + } + + return getPadding(node, getTrailing(axis)); + } + private static float getBorder(CSSNode node, PositionIndex position) { switch (position) { case TOP: @@ -221,27 +275,55 @@ private static float getBorder(CSSNode node, PositionIndex position) { return node.style.border.get(Spacing.LEFT); case RIGHT: return node.style.border.get(Spacing.RIGHT); + case START: + return node.style.border.get(Spacing.START); + case END: + return node.style.border.get(Spacing.END); 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 getLeadingBorder(CSSNode node, CSSFlexDirection axis) { + if (isRowDirection(axis)) { + float leadingBorder = getBorder(node, PositionIndex.START); + if (!CSSConstants.isUndefined(leadingBorder)) { + return leadingBorder; + } + } + + return getBorder(node, getLeading(axis)); + } + + private static float getTrailingBorder(CSSNode node, CSSFlexDirection axis) { + if (isRowDirection(axis)) { + float trailingBorder = getBorder(node, PositionIndex.END); + if (!CSSConstants.isUndefined(trailingBorder)) { + return trailingBorder; + } + } + + return getBorder(node, getTrailing(axis)); + } + + private static float getLeadingPaddingAndBorder(CSSNode node, CSSFlexDirection axis) { + return getLeadingPadding(node, axis) + getLeadingBorder(node, axis); + } + + private static float getTrailingPaddingAndBorder(CSSNode node, CSSFlexDirection axis) { + return getTrailingPadding(node, axis) + getTrailingBorder(node, axis); } private static float getBorderAxis(CSSNode node, CSSFlexDirection axis) { - return getBorder(node, getLeading(axis)) + getBorder(node, getTrailing(axis)); + return getLeadingBorder(node, axis) + getTrailingBorder(node, axis); } private static float getMarginAxis(CSSNode node, CSSFlexDirection axis) { - return getMargin(node, getLeading(axis)) + getMargin(node, getTrailing(axis)); + return getLeadingMargin(node, axis) + getTrailingMargin(node, axis); } private static float getPaddingAndBorderAxis(CSSNode node, CSSFlexDirection axis) { - return getPaddingAndBorder( - node, - getLeading(axis)) + getPaddingAndBorder(node, getTrailing(axis)); + return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis); } private static float boundAxis(CSSNode node, CSSFlexDirection axis, float value) { @@ -385,8 +467,8 @@ private static boolean isMeasureDefined(CSSNode node) { private static float getDimWithMargin(CSSNode node, CSSFlexDirection axis) { return getLayoutDimension(node, getDim(axis)) + - getMargin(node, getLeading(axis)) + - getMargin(node, getTrailing(axis)); + getLeadingMargin(node, axis) + + getTrailingMargin(node, axis); } private static boolean needsRelayout(CSSNode node, float parentMaxWidth) { @@ -437,13 +519,13 @@ private static void layoutNodeImpl( // 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)) + + setLayoutPosition(node, getLeading(mainAxis), getLayoutPosition(node, getLeading(mainAxis)) + getLeadingMargin(node, mainAxis) + getRelativePosition(node, mainAxis)); - setLayoutPosition(node, getTrailing(mainAxis), getLayoutPosition(node, getTrailing(mainAxis)) + getMargin(node, getTrailing(mainAxis)) + + setLayoutPosition(node, getTrailing(mainAxis), getLayoutPosition(node, getTrailing(mainAxis)) + getTrailingMargin(node, mainAxis) + getRelativePosition(node, mainAxis)); - setLayoutPosition(node, getLeading(crossAxis), getLayoutPosition(node, getLeading(crossAxis)) + getMargin(node, getLeading(crossAxis)) + + setLayoutPosition(node, getLeading(crossAxis), getLayoutPosition(node, getLeading(crossAxis)) + getLeadingMargin(node, crossAxis) + getRelativePosition(node, crossAxis)); - setLayoutPosition(node, getTrailing(crossAxis), getLayoutPosition(node, getTrailing(crossAxis)) + getMargin(node, getTrailing(crossAxis)) + + setLayoutPosition(node, getTrailing(crossAxis), getLayoutPosition(node, getTrailing(crossAxis)) + getTrailingMargin(node, crossAxis) + getRelativePosition(node, crossAxis)); if (isMeasureDefined(node)) { @@ -725,7 +807,7 @@ private static void layoutNodeImpl( // container! float crossDim = 0; float mainDim = leadingMainDim + - getPaddingAndBorder(node, getLeading(mainAxis)); + getLeadingPaddingAndBorder(node, mainAxis); for (i = startLine; i < endLine; ++i) { child = node.getChildAt(i); @@ -736,8 +818,8 @@ private static void layoutNodeImpl( // 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))); + getLeadingBorder(node, mainAxis) + + getLeadingMargin(child, mainAxis)); } else { // If the child is position absolute (without top/left) or relative, // we put it at the current accumulated offset. @@ -784,11 +866,11 @@ private static void layoutNodeImpl( // 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))); + getLeadingBorder(node, crossAxis) + + getLeadingMargin(child, crossAxis)); } else { - float leadingCrossDim = getPaddingAndBorder(node, getLeading(crossAxis)); + float leadingCrossDim = getLeadingPaddingAndBorder(node, crossAxis); // For a relative children, we're either using alignItems (parent) or // alignSelf (child) in order to determine the position in the cross axis @@ -823,6 +905,11 @@ private static void layoutNodeImpl( // And we apply the position setLayoutPosition(child, getPos(crossAxis), getLayoutPosition(child, getPos(crossAxis)) + linesCrossDim + leadingCrossDim); + + // Define the trailing position accordingly. + if (!CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis)))) { + setTrailingPosition(node, child, crossAxis); + } } } @@ -831,22 +918,21 @@ private static void layoutNodeImpl( startLine = endLine; } + boolean needsMainTrailingPos = false; + boolean needsCrossTrailingPos = false; + // 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 (CSSConstants.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 - boundAxis(node, mainAxis, linesMainDim + getPaddingAndBorder(node, getTrailing(mainAxis))), + boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)), // We can never assign a width smaller than the padding and borders getPaddingAndBorderAxis(node, mainAxis) )); - // Now that the width is defined, we should update the trailing - // positions for the children. - for (i = 0; i < node.getChildCount(); ++i) { - setTrailingPosition(node, node.getChildAt(i), mainAxis); - } + needsMainTrailingPos = true; } if (CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis)))) { @@ -857,9 +943,27 @@ private static void layoutNodeImpl( boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)), getPaddingAndBorderAxis(node, crossAxis) )); + + needsCrossTrailingPos = true; + } + + // Set trailing position if necessary + + if (needsMainTrailingPos || needsCrossTrailingPos) { + for (i = 0; i < node.getChildCount(); ++i) { + child = node.getChildAt(i); + + if (needsMainTrailingPos) { + setTrailingPosition(node, child, mainAxis); + } + + if (needsCrossTrailingPos) { + setTrailingPosition(node, child, crossAxis); + } + } } - // Calculate dimensions for absolutely positioned elements + // Calculate dimensions for absolutely positioned elements for (i = 0; i < node.getChildCount(); ++i) { child = node.getChildAt(i); diff --git a/src/java/src/com/facebook/csslayout/Spacing.java b/src/java/src/com/facebook/csslayout/Spacing.java index 24b255901c..cbdbce2cd4 100644 --- a/src/java/src/com/facebook/csslayout/Spacing.java +++ b/src/java/src/com/facebook/csslayout/Spacing.java @@ -40,10 +40,18 @@ public class Spacing { * {@code marginHorizontal}. */ public static final int HORIZONTAL = 5; + /** + * Spacing type that represents start direction e.g. left in left-to-right, right in right-to-left. + */ + public static final int START = 6; + /** + * Spacing type that represents end direction e.g. right in left-to-right, left in right-to-left. + */ + public static final int END = 7; /** * Spacing type that represents all directions (left, top, right, bottom). E.g. {@code margin}. */ - public static final int ALL = 6; + public static final int ALL = 8; private final float[] mSpacing = newFullSpacingArray(); private final float[] mDefaultSpacing = newSpacingResultArray(); @@ -114,6 +122,7 @@ private static float[] newFullSpacingArray() { CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, + CSSConstants.UNDEFINED, }; } @@ -127,6 +136,11 @@ private static float[] newSpacingResultArray(float defaultValue) { defaultValue, defaultValue, defaultValue, + defaultValue, + defaultValue, + CSSConstants.UNDEFINED, + CSSConstants.UNDEFINED, + defaultValue, }; } @@ -170,6 +184,22 @@ private void ensureResult() { : !CSSConstants.isUndefined(mSpacing[ALL]) ? mSpacing[ALL] : mDefaultSpacing[RIGHT]; + mSpacingResult[START] = + !CSSConstants.isUndefined(mSpacing[START]) + ? mSpacing[START] + : !CSSConstants.isUndefined(mSpacing[HORIZONTAL]) + ? mSpacing[HORIZONTAL] + : !CSSConstants.isUndefined(mSpacing[ALL]) + ? mSpacing[ALL] + : mDefaultSpacing[START]; + mSpacingResult[END] = + !CSSConstants.isUndefined(mSpacing[END]) + ? mSpacing[END] + : !CSSConstants.isUndefined(mSpacing[HORIZONTAL]) + ? mSpacing[HORIZONTAL] + : !CSSConstants.isUndefined(mSpacing[ALL]) + ? mSpacing[ALL] + : mDefaultSpacing[END]; mDirty = false; } } diff --git a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java index a0c0188514..9104b51474 100644 --- a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -374,6 +374,8 @@ public void testCase5() node_0.setMargin(Spacing.TOP, 10); node_0.setMargin(Spacing.RIGHT, 10); node_0.setMargin(Spacing.BOTTOM, 10); + node_0.setMargin(Spacing.START, 10); + node_0.setMargin(Spacing.END, 10); } TestCSSNode root_layout = new TestCSSNode(); @@ -400,6 +402,8 @@ public void testCase6() node_0.setMargin(Spacing.TOP, 10); node_0.setMargin(Spacing.RIGHT, 10); node_0.setMargin(Spacing.BOTTOM, 10); + node_0.setMargin(Spacing.START, 10); + node_0.setMargin(Spacing.END, 10); addChildren(node_0, 3); { TestCSSNode node_1; @@ -410,6 +414,8 @@ public void testCase6() node_1.setMargin(Spacing.TOP, 50); node_1.setMargin(Spacing.RIGHT, 50); node_1.setMargin(Spacing.BOTTOM, 50); + node_1.setMargin(Spacing.START, 50); + node_1.setMargin(Spacing.END, 50); node_1 = node_0.getChildAt(1); node_1.style.width = 100; node_1.style.height = 100; @@ -417,6 +423,8 @@ public void testCase6() node_1.setMargin(Spacing.TOP, 25); node_1.setMargin(Spacing.RIGHT, 25); node_1.setMargin(Spacing.BOTTOM, 25); + node_1.setMargin(Spacing.START, 25); + node_1.setMargin(Spacing.END, 25); node_1 = node_0.getChildAt(2); node_1.style.width = 100; node_1.style.height = 100; @@ -424,6 +432,8 @@ public void testCase6() node_1.setMargin(Spacing.TOP, 10); node_1.setMargin(Spacing.RIGHT, 10); node_1.setMargin(Spacing.BOTTOM, 10); + node_1.setMargin(Spacing.START, 10); + node_1.setMargin(Spacing.END, 10); } } @@ -471,6 +481,8 @@ public void testCase7() node_0.setMargin(Spacing.TOP, 10); node_0.setMargin(Spacing.RIGHT, 10); node_0.setMargin(Spacing.BOTTOM, 10); + node_0.setMargin(Spacing.START, 10); + node_0.setMargin(Spacing.END, 10); addChildren(node_0, 3); { TestCSSNode node_1; @@ -481,6 +493,8 @@ public void testCase7() node_1.setMargin(Spacing.TOP, 50); node_1.setMargin(Spacing.RIGHT, 50); node_1.setMargin(Spacing.BOTTOM, 50); + node_1.setMargin(Spacing.START, 50); + node_1.setMargin(Spacing.END, 50); node_1 = node_0.getChildAt(1); node_1.style.width = 100; node_1.style.height = 100; @@ -488,6 +502,8 @@ public void testCase7() node_1.setMargin(Spacing.TOP, 25); node_1.setMargin(Spacing.RIGHT, 25); node_1.setMargin(Spacing.BOTTOM, 25); + node_1.setMargin(Spacing.START, 25); + node_1.setMargin(Spacing.END, 25); node_1 = node_0.getChildAt(2); node_1.style.width = 100; node_1.style.height = 100; @@ -495,6 +511,8 @@ public void testCase7() node_1.setMargin(Spacing.TOP, 10); node_1.setMargin(Spacing.RIGHT, 10); node_1.setMargin(Spacing.BOTTOM, 10); + node_1.setMargin(Spacing.START, 10); + node_1.setMargin(Spacing.END, 10); } } @@ -2161,6 +2179,8 @@ public void testCase42() node_1.setMargin(Spacing.TOP, 5); node_1.setMargin(Spacing.RIGHT, 5); node_1.setMargin(Spacing.BOTTOM, 5); + node_1.setMargin(Spacing.START, 5); + node_1.setMargin(Spacing.END, 5); } } @@ -2200,6 +2220,8 @@ public void testCase43() node_1.setMargin(Spacing.TOP, 5); node_1.setMargin(Spacing.RIGHT, 5); node_1.setMargin(Spacing.BOTTOM, 5); + node_1.setMargin(Spacing.START, 5); + node_1.setMargin(Spacing.END, 5); } } @@ -2426,6 +2448,8 @@ public void testCase49() node_2.setMargin(Spacing.TOP, 10); node_2.setMargin(Spacing.RIGHT, 10); node_2.setMargin(Spacing.BOTTOM, 10); + node_2.setMargin(Spacing.START, 10); + node_2.setMargin(Spacing.END, 10); node_2 = node_1.getChildAt(1); node_2.style.height = 100; } @@ -2487,6 +2511,8 @@ public void testCase50() node_2.setMargin(Spacing.TOP, 10); node_2.setMargin(Spacing.RIGHT, 10); node_2.setMargin(Spacing.BOTTOM, 10); + node_2.setMargin(Spacing.START, 10); + node_2.setMargin(Spacing.END, 10); node_2 = node_1.getChildAt(1); node_2.style.height = 100; } @@ -2646,6 +2672,8 @@ public void testCase54() node_0.setPadding(Spacing.TOP, 5); node_0.setPadding(Spacing.RIGHT, 5); node_0.setPadding(Spacing.BOTTOM, 5); + node_0.setPadding(Spacing.START, 5); + node_0.setPadding(Spacing.END, 5); } TestCSSNode root_layout = new TestCSSNode(); @@ -2670,6 +2698,8 @@ public void testCase55() node_0.setPadding(Spacing.TOP, 5); node_0.setPadding(Spacing.RIGHT, 5); node_0.setPadding(Spacing.BOTTOM, 5); + node_0.setPadding(Spacing.START, 5); + node_0.setPadding(Spacing.END, 5); addChildren(node_0, 1); { TestCSSNode node_1; @@ -2708,6 +2738,8 @@ public void testCase56() node_0.setPadding(Spacing.TOP, 5); node_0.setPadding(Spacing.RIGHT, 5); node_0.setPadding(Spacing.BOTTOM, 5); + node_0.setPadding(Spacing.START, 5); + node_0.setPadding(Spacing.END, 5); addChildren(node_0, 1); { TestCSSNode node_1; @@ -2716,6 +2748,8 @@ public void testCase56() node_1.setMargin(Spacing.TOP, 5); node_1.setMargin(Spacing.RIGHT, 5); node_1.setMargin(Spacing.BOTTOM, 5); + node_1.setMargin(Spacing.START, 5); + node_1.setMargin(Spacing.END, 5); } } @@ -2755,6 +2789,8 @@ public void testCase57() node_1.setPadding(Spacing.TOP, 10); node_1.setPadding(Spacing.RIGHT, 10); node_1.setPadding(Spacing.BOTTOM, 10); + node_1.setPadding(Spacing.START, 10); + node_1.setPadding(Spacing.END, 10); } } @@ -2789,6 +2825,8 @@ public void testCase58() node_0.setPadding(Spacing.TOP, 50); node_0.setPadding(Spacing.RIGHT, 50); node_0.setPadding(Spacing.BOTTOM, 50); + node_0.setPadding(Spacing.START, 50); + node_0.setPadding(Spacing.END, 50); addChildren(node_0, 1); { TestCSSNode node_1; @@ -2798,6 +2836,8 @@ public void testCase58() node_1.setPadding(Spacing.TOP, 10); node_1.setPadding(Spacing.RIGHT, 10); node_1.setPadding(Spacing.BOTTOM, 10); + node_1.setPadding(Spacing.START, 10); + node_1.setPadding(Spacing.END, 10); } } @@ -2841,6 +2881,8 @@ public void testCase59() node_2.setMargin(Spacing.TOP, 16); node_2.setMargin(Spacing.RIGHT, 16); node_2.setMargin(Spacing.BOTTOM, 16); + node_2.setMargin(Spacing.START, 16); + node_2.setMargin(Spacing.END, 16); } } } @@ -3213,6 +3255,8 @@ public void testCase70() node_0.setPadding(Spacing.TOP, 5); node_0.setPadding(Spacing.RIGHT, 5); node_0.setPadding(Spacing.BOTTOM, 5); + node_0.setPadding(Spacing.START, 5); + node_0.setPadding(Spacing.END, 5); addChildren(node_0, 1); { TestCSSNode node_1; @@ -3296,6 +3340,8 @@ public void testCase72() node_0.setPadding(Spacing.TOP, 20); node_0.setPadding(Spacing.RIGHT, 20); node_0.setPadding(Spacing.BOTTOM, 20); + node_0.setPadding(Spacing.START, 20); + node_0.setPadding(Spacing.END, 20); addChildren(node_0, 1); { TestCSSNode node_1; @@ -3920,6 +3966,8 @@ public void testCase87() node_0.setBorder(Spacing.TOP, 5); node_0.setBorder(Spacing.RIGHT, 5); node_0.setBorder(Spacing.BOTTOM, 5); + node_0.setBorder(Spacing.START, 5); + node_0.setBorder(Spacing.END, 5); } TestCSSNode root_layout = new TestCSSNode(); @@ -3981,6 +4029,8 @@ public void testCase89() node_0.setBorder(Spacing.TOP, 1); node_0.setBorder(Spacing.RIGHT, 1); node_0.setBorder(Spacing.BOTTOM, 1); + node_0.setBorder(Spacing.START, 1); + node_0.setBorder(Spacing.END, 1); addChildren(node_0, 1); { TestCSSNode node_1; @@ -4028,6 +4078,8 @@ public void testCase90() node_1.setPadding(Spacing.TOP, 20); node_1.setPadding(Spacing.RIGHT, 20); node_1.setPadding(Spacing.BOTTOM, 20); + node_1.setPadding(Spacing.START, 20); + node_1.setPadding(Spacing.END, 20); } } @@ -4546,6 +4598,8 @@ public void testCase103() node_0.setPadding(Spacing.TOP, 10); node_0.setPadding(Spacing.RIGHT, 10); node_0.setPadding(Spacing.BOTTOM, 10); + node_0.setPadding(Spacing.START, 10); + node_0.setPadding(Spacing.END, 10); addChildren(node_0, 1); { TestCSSNode node_1; @@ -4555,6 +4609,8 @@ public void testCase103() node_1.setMargin(Spacing.TOP, 10); node_1.setMargin(Spacing.RIGHT, 10); node_1.setMargin(Spacing.BOTTOM, 10); + node_1.setMargin(Spacing.START, 10); + node_1.setMargin(Spacing.END, 10); addChildren(node_1, 1); { TestCSSNode node_2; @@ -4779,6 +4835,8 @@ public void testCase108() node_2.setMargin(Spacing.TOP, 20); node_2.setMargin(Spacing.RIGHT, 20); node_2.setMargin(Spacing.BOTTOM, 20); + node_2.setMargin(Spacing.START, 20); + node_2.setMargin(Spacing.END, 20); node_2.setMeasureFunction(sTestMeasureFunction); node_2.context = "loooooooooong with space"; } @@ -4836,6 +4894,8 @@ public void testCase109() node_2.setMargin(Spacing.TOP, 20); node_2.setMargin(Spacing.RIGHT, 20); node_2.setMargin(Spacing.BOTTOM, 20); + node_2.setMargin(Spacing.START, 20); + node_2.setMargin(Spacing.END, 20); node_2.setMeasureFunction(sTestMeasureFunction); node_2.context = "loooooooooong with space"; } @@ -4891,6 +4951,8 @@ public void testCase110() node_2.setMargin(Spacing.TOP, 20); node_2.setMargin(Spacing.RIGHT, 20); node_2.setMargin(Spacing.BOTTOM, 20); + node_2.setMargin(Spacing.START, 20); + node_2.setMargin(Spacing.END, 20); node_2.setMeasureFunction(sTestMeasureFunction); node_2.context = "loooooooooong with space"; } @@ -7126,6 +7188,8 @@ public void testCase163() node_1.setPadding(Spacing.TOP, 10); node_1.setPadding(Spacing.RIGHT, 10); node_1.setPadding(Spacing.BOTTOM, 10); + node_1.setPadding(Spacing.START, 10); + node_1.setPadding(Spacing.END, 10); node_1.style.positionLeft = 100; node_1.style.positionTop = 100; node_1.style.positionRight = 100; @@ -7190,10 +7254,14 @@ public void testCase164() node_1.setPadding(Spacing.TOP, 10); node_1.setPadding(Spacing.RIGHT, 10); node_1.setPadding(Spacing.BOTTOM, 10); + node_1.setPadding(Spacing.START, 10); + node_1.setPadding(Spacing.END, 10); node_1.setBorder(Spacing.LEFT, 1); node_1.setBorder(Spacing.TOP, 1); node_1.setBorder(Spacing.RIGHT, 1); node_1.setBorder(Spacing.BOTTOM, 1); + node_1.setBorder(Spacing.START, 1); + node_1.setBorder(Spacing.END, 1); node_1.style.positionLeft = 100; node_1.style.positionTop = 100; node_1.style.positionRight = 100; @@ -7258,6 +7326,8 @@ public void testCase165() node_1.setPadding(Spacing.TOP, 10); node_1.setPadding(Spacing.RIGHT, 10); node_1.setPadding(Spacing.BOTTOM, 10); + node_1.setPadding(Spacing.START, 10); + node_1.setPadding(Spacing.END, 10); addChildren(node_1, 1); { TestCSSNode node_2; @@ -7475,5 +7545,356 @@ public void testCase167() test("should correctly space wrapped nodes", root_node, root_layout); } + + @Test + public void testCase168() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + node_0.setPadding(Spacing.LEFT, 5); + node_0.setPadding(Spacing.RIGHT, 5); + node_0.setPadding(Spacing.START, 15); + node_0.setPadding(Spacing.END, 15); + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 15; + node_1.layout.width = 170; + node_1.layout.height = 50; + } + } + + test("should give start/end padding precedence over left/right padding", root_node, root_layout); + } + + @Test + public void testCase169() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + node_1.setMargin(Spacing.LEFT, 5); + node_1.setMargin(Spacing.RIGHT, 5); + node_1.setMargin(Spacing.START, 15); + node_1.setMargin(Spacing.END, 15); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 15; + node_1.layout.width = 170; + node_1.layout.height = 50; + } + } + + test("should give start/end margin precedence over left/right margin", root_node, root_layout); + } + + @Test + public void testCase170() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + node_0.setBorder(Spacing.LEFT, 5); + node_0.setBorder(Spacing.RIGHT, 5); + node_0.setBorder(Spacing.START, 15); + node_0.setBorder(Spacing.END, 15); + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 15; + node_1.layout.width = 170; + node_1.layout.height = 50; + } + } + + test("should give start/end border precedence over left/right border", root_node, root_layout); + } + + @Test + public void testCase171() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + node_0.setPadding(Spacing.START, 15); + node_0.setPadding(Spacing.END, 5); + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 15; + node_1.layout.width = 180; + node_1.layout.height = 50; + } + } + + test("should layout node with correct start/end padding", root_node, root_layout); + } + + @Test + public void testCase172() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.direction = CSSDirection.RTL; + node_0.style.width = 200; + node_0.setPadding(Spacing.START, 15); + node_0.setPadding(Spacing.END, 5); + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 5; + node_1.layout.width = 180; + node_1.layout.height = 50; + } + } + + test("should layout node with correct start/end padding in rtl", root_node, root_layout); + } + + @Test + public void testCase173() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + node_1.setMargin(Spacing.START, 15); + node_1.setMargin(Spacing.END, 5); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 15; + node_1.layout.width = 180; + node_1.layout.height = 50; + } + } + + test("should layout node with correct start/end margin", root_node, root_layout); + } + + @Test + public void testCase174() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.direction = CSSDirection.RTL; + node_1.style.height = 50; + node_1.setMargin(Spacing.START, 15); + node_1.setMargin(Spacing.END, 5); + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 5; + node_1.layout.width = 180; + node_1.layout.height = 50; + } + } + + test("should layout node with correct start/end margin in rtl", root_node, root_layout); + } + + @Test + public void testCase175() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.width = 200; + node_0.setBorder(Spacing.START, 15); + node_0.setBorder(Spacing.END, 5); + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 15; + node_1.layout.width = 180; + node_1.layout.height = 50; + } + } + + test("should layout node with correct start/end border", root_node, root_layout); + } + + @Test + public void testCase176() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.direction = CSSDirection.RTL; + node_0.style.width = 200; + node_0.setBorder(Spacing.START, 15); + node_0.setBorder(Spacing.END, 5); + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.height = 50; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.top = 0; + node_0.layout.left = 0; + node_0.layout.width = 200; + node_0.layout.height = 50; + addChildren(node_0, 1); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.top = 0; + node_1.layout.left = 5; + node_1.layout.width = 180; + node_1.layout.height = 50; + } + } + + test("should layout node with correct start/end border in rtl", root_node, root_layout); + } /** END_GENERATED **/ } diff --git a/src/transpile.js b/src/transpile.js index cc39b2f172..e2f7b26883 100644 --- a/src/transpile.js +++ b/src/transpile.js @@ -97,11 +97,15 @@ function printLayout(test) { addFloat(node, spacing + suffix, spacing + '[CSS_TOP]'); addFloat(node, spacing + suffix, spacing + '[CSS_RIGHT]'); addFloat(node, spacing + suffix, spacing + '[CSS_BOTTOM]'); + addFloat(node, spacing + suffix, spacing + '[CSS_START]'); + addFloat(node, spacing + suffix, spacing + '[CSS_END]'); addFloat(node, spacing + 'Left' + suffix, spacing + '[CSS_LEFT]'); addFloat(node, spacing + 'Top' + suffix, spacing + '[CSS_TOP]'); addFloat(node, spacing + 'Right' + suffix, spacing + '[CSS_RIGHT]'); addFloat(node, spacing + 'Bottom' + suffix, spacing + '[CSS_BOTTOM]'); + addFloat(node, spacing + 'Start' + suffix, spacing + '[CSS_START]'); + addFloat(node, spacing + 'End' + suffix, spacing + '[CSS_END]'); } function addMeasure(node) {