Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Pierre Renaux
2015-05-17 21:54:30 +08:00
17 changed files with 8118 additions and 1334 deletions

View File

@@ -11,6 +11,8 @@ function __transpileToJavaCommon(code) {
return code
.replace(/CSS_UNDEFINED/g, 'CSSConstants.UNDEFINED')
.replace(/css_flex_direction_t/g, 'CSSFlexDirection')
.replace(/css_direction_t/g, 'CSSDirection')
.replace(/CSS_DIRECTION_/g, 'CSSDirection.')
.replace(/CSS_FLEX_DIRECTION_/g, 'CSSFlexDirection.')
.replace(/css_align_t/g, 'CSSAlign')
.replace(/CSS_ALIGN_/g, 'CSSAlign.')
@@ -33,7 +35,11 @@ function __transpileToJavaCommon(code) {
.replace(
/(\w+)\.layout\[((?:getLeading|getPos)\([^\)]+\))\]\s+=\s+([^;]+);/gm,
'setLayoutPosition($1, $2, $3);')
.replace(
/(\w+)\.layout\[((?:getTrailing|getPos)\([^\)]+\))\]\s+=\s+([^;]+);/gm,
'setLayoutPosition($1, $2, $3);')
.replace(/(\w+)\.layout\[((?:getLeading|getPos)\([^\]]+\))\]/g, 'getLayoutPosition($1, $2)')
.replace(/(\w+)\.layout\[((?:getTrailing|getPos)\([^\]]+\))\]/g, 'getLayoutPosition($1, $2)')
.replace(
/(\w+)\.layout\[(getDim\([^\)]+\))\]\s+=\s+([^;]+);/gm,
'setLayoutDimension($1, $2, $3);')
@@ -63,17 +69,23 @@ function __transpileSingleTestToJava(code) {
.replace( // layout.position[CSS_TOP] => layout.y
/layout\.position\[CSS_(TOP|LEFT)\]/g,
function (str, match1) {
return 'layout.' + (match1 === 'TOP' ? 'y' : 'x');
return 'layout.' + (match1 === 'TOP' ? 'top' : 'left');
})
.replace( // style.position[CSS_TOP] => style.positionTop
/style\.(position)\[CSS_(TOP|BOTTOM|LEFT|RIGHT)\]/g,
function (str, match1, match2) {
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|START|END)\]\s+=\s+(-?[\.\d]+)/g,
function (str, match1, match2, match3) {
var propertyCap = match1.charAt(0).toUpperCase() + match1.slice(1);
return 'set' + propertyCap + '(Spacing.' + match2 + ', ' + match3 + ')';
})
.replace( // style.margin[CSS_TOP] => style.margin[Spacing.TOP]
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT)\]/g,
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]/g,
function (str, match1, match2) {
return 'style.' + match1 + '[Spacing.' + match2 + ']';
return 'style.' + match1 + '.get(Spacing.' + match2 + ')';
})
.replace(/get_child\(.*context\,\s([^\)]+)\)/g, 'getChildAt($1)')
.replace(/init_css_node_children/g, 'addChildren')

View File

@@ -106,8 +106,7 @@ css_dim_t measure(void *context, float width) {
static int test_ran_count = 0;
void test(const char *name, css_node_t *style, css_node_t *expected_layout) {
++test_ran_count;
layoutNode(style, CSS_UNDEFINED);
layoutNode(style, CSS_UNDEFINED, (css_direction_t)-1);
if (!are_layout_equal(style, expected_layout)) {
printf("%sF%s", "\x1B[31m", "\x1B[0m");

View File

@@ -156,6 +156,10 @@ var layoutTestUtils = (function() {
return layout;
}
function capitalizeFirst(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function computeCSSLayout(rootNode) {
fillNodes(rootNode);
realComputeLayout(rootNode);
@@ -167,8 +171,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;
}
}
@@ -178,6 +184,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) {
@@ -196,6 +204,7 @@ var layoutTestUtils = (function() {
transferSpacing(div, node, 'padding', '');
transferSpacing(div, node, 'border', 'Width');
transfer(div, node, 'flexDirection');
transfer(div, node, 'direction');
transfer(div, node, 'flex');
transfer(div, node, 'flexWrap');
transfer(div, node, 'justifyContent');

View File

@@ -41,6 +41,9 @@ void init_css_node(css_node_t *node) {
node->style.align_items = CSS_ALIGN_STRETCH;
node->style.align_content = CSS_ALIGN_FLEX_START;
node->style.direction = CSS_DIRECTION_INHERIT;
node->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
// Some of the fields default to undefined and not 0
node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
node->style.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
@@ -56,6 +59,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;
@@ -63,6 +73,7 @@ void init_css_node(css_node_t *node) {
node->layout.last_requested_dimensions[CSS_WIDTH] = -1;
node->layout.last_requested_dimensions[CSS_HEIGHT] = -1;
node->layout.last_parent_max_width = -1;
node->layout.last_direction = (css_direction_t)-1;
node->layout.should_update = true;
}
@@ -124,8 +135,14 @@ static void print_css_node_rec(
}
if (options & CSS_PRINT_STYLE) {
if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW) {
if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN) {
printf("flexDirection: 'column', ");
} else if (node->style.flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE) {
printf("flexDirection: 'columnReverse', ");
} else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW) {
printf("flexDirection: 'row', ");
} else if (node->style.flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) {
printf("flexDirection: 'rowReverse', ");
}
if (node->style.justify_content == CSS_JUSTIFY_CENTER) {
@@ -173,6 +190,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)) {
@@ -182,6 +201,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)) {
@@ -191,6 +212,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]);
@@ -223,57 +246,131 @@ void print_css_node(css_node_t *node, css_print_options_t options) {
}
static css_position_t leading[2] = {
static css_position_t leading[4] = {
/* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT
/* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT,
/* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT
};
static css_position_t trailing[2] = {
static css_position_t trailing[4] = {
/* CSS_FLEX_DIRECTION_COLUMN = */ CSS_BOTTOM,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_RIGHT
/* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_TOP,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_RIGHT,
/* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_LEFT
};
static css_position_t pos[2] = {
static css_position_t pos[4] = {
/* CSS_FLEX_DIRECTION_COLUMN = */ CSS_TOP,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT
/* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_BOTTOM,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_LEFT,
/* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_RIGHT
};
static css_dimension_t dim[2] = {
static css_dimension_t dim[4] = {
/* CSS_FLEX_DIRECTION_COLUMN = */ CSS_HEIGHT,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_WIDTH
/* CSS_FLEX_DIRECTION_COLUMN_REVERSE = */ CSS_HEIGHT,
/* CSS_FLEX_DIRECTION_ROW = */ CSS_WIDTH,
/* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH
};
static float getMargin(css_node_t *node, int location) {
return node->style.margin[location];
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 getPadding(css_node_t *node, int location) {
if (node->style.padding[location] >= 0) {
return node->style.padding[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 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,10 +392,40 @@ static css_align_t getAlignItem(css_node_t *node, css_node_t *child) {
return node->style.align_items;
}
static css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) {
css_direction_t direction = node->style.direction;
if (direction == CSS_DIRECTION_INHERIT) {
direction = parentDirection > CSS_DIRECTION_INHERIT ? parentDirection : CSS_DIRECTION_LTR;
}
return direction;
}
static css_flex_direction_t getFlexDirection(css_node_t *node) {
return node->style.flex_direction;
}
static css_flex_direction_t resolveAxis(css_flex_direction_t flex_direction, css_direction_t direction) {
if (direction == CSS_DIRECTION_RTL) {
if (flex_direction == CSS_FLEX_DIRECTION_ROW) {
return CSS_FLEX_DIRECTION_ROW_REVERSE;
} else if (flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE) {
return CSS_FLEX_DIRECTION_ROW;
}
}
return flex_direction;
}
static css_flex_direction_t getCrossFlexDirection(css_flex_direction_t flex_direction, css_direction_t direction) {
if (isColumnDirection(flex_direction)) {
return resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);
} else {
return CSS_FLEX_DIRECTION_COLUMN;
}
}
static float getFlex(css_node_t *node) {
return node->style.flex;
}
@@ -316,8 +443,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) {
@@ -345,10 +472,10 @@ static float boundAxis(css_node_t *node, css_flex_direction_t axis, float value)
float min = CSS_UNDEFINED;
float max = CSS_UNDEFINED;
if (axis == CSS_FLEX_DIRECTION_COLUMN) {
if (isColumnDirection(axis)) {
min = node->style.minDimensions[CSS_HEIGHT];
max = node->style.maxDimensions[CSS_HEIGHT];
} else if (axis == CSS_FLEX_DIRECTION_ROW) {
} else if (isRowDirection(axis)) {
min = node->style.minDimensions[CSS_WIDTH];
max = node->style.maxDimensions[CSS_WIDTH];
}
@@ -383,6 +510,11 @@ static void setDimensionFromStyle(css_node_t *node, css_flex_direction_t axis) {
);
}
static void setTrailingPosition(css_node_t *node, css_node_t *child, css_flex_direction_t axis) {
child->layout.position[trailing[axis]] = node->layout.dimensions[dim[axis]] -
child->layout.dimensions[dim[axis]] - child->layout.position[pos[axis]];
}
// If both left and right are defined, then use left. Otherwise return
// +left or -right depending on which is defined.
static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) {
@@ -393,13 +525,12 @@ static float getRelativePosition(css_node_t *node, css_flex_direction_t axis) {
return -getPosition(node, trailing[axis]);
}
static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) {
/** START_GENERATED **/
css_flex_direction_t mainAxis = getFlexDirection(node);
css_flex_direction_t crossAxis = mainAxis == CSS_FLEX_DIRECTION_ROW ?
CSS_FLEX_DIRECTION_COLUMN :
CSS_FLEX_DIRECTION_ROW;
css_direction_t direction = resolveDirection(node, parentDirection);
css_flex_direction_t mainAxis = resolveAxis(getFlexDirection(node), direction);
css_flex_direction_t crossAxis = getCrossFlexDirection(mainAxis, direction);
css_flex_direction_t resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);
// Handle width and height style attributes
setDimensionFromStyle(node, mainAxis);
@@ -407,28 +538,32 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// 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[leading[crossAxis]] += getMargin(node, leading[crossAxis]) +
node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) +
getRelativePosition(node, mainAxis);
node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis);
node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis);
if (isMeasureDefined(node)) {
float width = CSS_UNDEFINED;
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
if (isDimDefined(node, resolvedRowAxis)) {
width = node->style.dimensions[CSS_WIDTH];
} else if (!isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]])) {
width = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]];
} else if (!isUndefined(node->layout.dimensions[dim[resolvedRowAxis]])) {
width = node->layout.dimensions[dim[resolvedRowAxis]];
} else {
width = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
getMarginAxis(node, resolvedRowAxis);
}
width -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
width -= getPaddingAndBorderAxis(node, resolvedRowAxis);
// 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.
bool isRowUndefined = !isDimDefined(node, CSS_FLEX_DIRECTION_ROW) &&
isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]]);
bool isRowUndefined = !isDimDefined(node, resolvedRowAxis) &&
isUndefined(node->layout.dimensions[dim[resolvedRowAxis]]);
bool isColumnUndefined = !isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) &&
isUndefined(node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]);
@@ -441,14 +576,16 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
);
if (isRowUndefined) {
node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] +
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
if (isColumnUndefined) {
node->layout.dimensions[CSS_HEIGHT] = measureDim.dimensions[CSS_HEIGHT] +
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
}
}
return;
if (node->children_count == 0) {
return;
}
}
int i;
@@ -545,20 +682,20 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
} else {
maxWidth = CSS_UNDEFINED;
if (mainAxis != CSS_FLEX_DIRECTION_ROW) {
if (!isRowDirection(mainAxis)) {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
getMarginAxis(node, resolvedRowAxis) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
if (isDimDefined(node, resolvedRowAxis)) {
maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] -
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
}
// This is the main recursive call. We layout non flexible children.
if (alreadyComputedNextLayout == 0) {
layoutNode(child, maxWidth);
layoutNode(child, maxWidth, direction);
}
// Absolute positioned elements do not take part of the layout, so we
@@ -577,6 +714,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// If there's only one element, then it's bigger than the content
// and needs its own line
i != startLine) {
nonFlexibleChildrenCount--;
alreadyComputedNextLayout = 1;
break;
}
@@ -644,17 +782,17 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
);
maxWidth = CSS_UNDEFINED;
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
maxWidth = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_ROW]] -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
} else if (mainAxis != CSS_FLEX_DIRECTION_ROW) {
if (isDimDefined(node, resolvedRowAxis)) {
maxWidth = node->layout.dimensions[dim[resolvedRowAxis]] -
getPaddingAndBorderAxis(node, resolvedRowAxis);
} else if (!isRowDirection(mainAxis)) {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
getMarginAxis(node, resolvedRowAxis) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
// And we recursively call the layout algorithm for this child
layoutNode(child, maxWidth);
layoutNode(child, maxWidth, direction);
}
}
@@ -690,7 +828,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// 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);
@@ -702,12 +840,17 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// 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.
child->layout.position[pos[mainAxis]] += mainDim;
// Define the trailing position accordingly.
if (!isUndefined(node->layout.dimensions[dim[mainAxis]])) {
setTrailingPosition(node, child, mainAxis);
}
}
// Now that we placed the element, we need to update the variables
@@ -735,7 +878,6 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
}
// <Loop D> Position elements in the cross axis
for (i = startLine; i < endLine; ++i) {
child = node->get_child(node->context, i);
@@ -745,11 +887,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// 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
@@ -784,6 +926,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
// 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);
}
}
}
@@ -810,19 +957,19 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
!isUndefined(node->layout.dimensions[dim[crossAxis]])) {
float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] -
getPaddingAndBorderAxis(node, crossAxis);
float remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim;
float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim;
float crossDimLead = 0;
float currentLead = getPaddingAndBorder(node, leading[crossAxis]);
float currentLead = getLeadingPaddingAndBorder(node, crossAxis);
css_align_t alignContent = getAlignContent(node);
if (alignContent == CSS_ALIGN_FLEX_END) {
currentLead += remainingCrossDim;
currentLead += remainingAlignContentDim;
} else if (alignContent == CSS_ALIGN_CENTER) {
currentLead += remainingCrossDim / 2;
currentLead += remainingAlignContentDim / 2;
} else if (alignContent == CSS_ALIGN_STRETCH) {
if (nodeCrossAxisInnerSize > linesCrossDim) {
crossDimLead = (remainingCrossDim / linesCount);
crossDimLead = (remainingAlignContentDim / linesCount);
}
}
@@ -856,16 +1003,16 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
continue;
}
css_align_t alignItem = getAlignItem(node, child);
if (alignItem == CSS_ALIGN_FLEX_START) {
child->layout.position[pos[crossAxis]] = currentLead + getMargin(child, leading[crossAxis]);
} else if (alignItem == CSS_ALIGN_FLEX_END) {
child->layout.position[pos[crossAxis]] = currentLead + lineHeight - getMargin(child,trailing[crossAxis]) - child->layout.dimensions[dim[crossAxis]];
} else if (alignItem == CSS_ALIGN_CENTER) {
css_align_t alignContentAlignItem = getAlignItem(node, child);
if (alignContentAlignItem == CSS_ALIGN_FLEX_START) {
child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);
} else if (alignContentAlignItem == CSS_ALIGN_FLEX_END) {
child->layout.position[pos[crossAxis]] = currentLead + lineHeight - getTrailingMargin(child, crossAxis) - child->layout.dimensions[dim[crossAxis]];
} else if (alignContentAlignItem == CSS_ALIGN_CENTER) {
float childHeight = child->layout.dimensions[dim[crossAxis]];
child->layout.position[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2;
} else if (alignItem == CSS_ALIGN_STRETCH) {
child->layout.position[pos[crossAxis]] = currentLead + getMargin(child, leading[crossAxis]);
} else if (alignContentAlignItem == CSS_ALIGN_STRETCH) {
child->layout.position[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);
// TODO(prenaux): Correctly set the height of items with undefined
// (auto) crossAxis dimension.
}
@@ -875,16 +1022,21 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
}
}
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)
);
needsMainTrailingPos = true;
}
if (isUndefined(node->layout.dimensions[dim[crossAxis]])) {
@@ -895,9 +1047,26 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)),
getPaddingAndBorderAxis(node, crossAxis)
);
needsCrossTrailingPos = true;
}
// <Loop F> Calculate dimensions for absolutely positioned elements
// <Loop F> 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);
}
}
}
// <Loop G> Calculate dimensions for absolutely positioned elements
for (i = 0; i < node->children_count; ++i) {
child = node->get_child(node->context, i);
if (getPositionType(child) == CSS_POSITION_ABSOLUTE) {
@@ -936,8 +1105,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) {
/** END_GENERATED **/
}
void layoutNode(css_node_t *node, float parentMaxWidth) {
void layoutNode(css_node_t *node, float parentMaxWidth, css_direction_t parentDirection) {
css_layout_t *layout = &node->layout;
css_direction_t direction = node->style.direction;
layout->should_update = true;
bool skipLayout =
@@ -945,6 +1115,7 @@ void layoutNode(css_node_t *node, float parentMaxWidth) {
eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) &&
eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) &&
eq(layout->last_parent_max_width, parentMaxWidth);
eq(layout->last_direction, direction);
if (skipLayout) {
layout->dimensions[CSS_WIDTH] = layout->last_dimensions[CSS_WIDTH];
@@ -955,8 +1126,9 @@ void layoutNode(css_node_t *node, float parentMaxWidth) {
layout->last_requested_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];
layout->last_requested_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];
layout->last_parent_max_width = parentMaxWidth;
layout->last_direction = direction;
layoutNodeImpl(node, parentMaxWidth);
layoutNodeImpl(node, parentMaxWidth, parentDirection);
layout->last_dimensions[CSS_WIDTH] = layout->dimensions[CSS_WIDTH];
layout->last_dimensions[CSS_HEIGHT] = layout->dimensions[CSS_HEIGHT];

View File

@@ -23,9 +23,17 @@ static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
#define CSS_UNDEFINED NAN
typedef enum {
CSS_DIRECTION_INHERIT = 0,
CSS_DIRECTION_LTR,
CSS_DIRECTION_RTL
} css_direction_t;
typedef enum {
CSS_FLEX_DIRECTION_COLUMN = 0,
CSS_FLEX_DIRECTION_ROW
CSS_FLEX_DIRECTION_COLUMN_REVERSE,
CSS_FLEX_DIRECTION_ROW,
CSS_FLEX_DIRECTION_ROW_REVERSE
} css_flex_direction_t;
typedef enum {
@@ -63,6 +71,8 @@ typedef enum {
CSS_TOP,
CSS_RIGHT,
CSS_BOTTOM,
CSS_START,
CSS_END,
CSS_POSITION_COUNT
} css_position_t;
@@ -72,7 +82,7 @@ typedef enum {
} css_dimension_t;
typedef struct {
float position[2];
float position[4];
float dimensions[2];
// Instead of recomputing the entire layout every single time, we
@@ -82,7 +92,7 @@ typedef struct {
float last_parent_max_width;
float last_dimensions[2];
float last_position[2];
css_direction_t last_direction;
} css_layout_t;
typedef struct {
@@ -90,6 +100,7 @@ typedef struct {
} css_dim_t;
typedef struct {
css_direction_t direction;
css_flex_direction_t flex_direction;
css_justify_t justify_content;
css_align_t align_content;
@@ -98,7 +109,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
@@ -110,8 +121,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];
@@ -145,7 +156,7 @@ typedef enum {
void print_css_node(css_node_t *node, css_print_options_t options);
// Function that computes the layout!
void layoutNode(css_node_t *node, float maxWidth);
void layoutNode(css_node_t *node, float maxWidth, css_direction_t parentDirection);
bool isUndefined(float value);
#endif

View File

@@ -11,8 +11,14 @@ var computeLayout = (function() {
var CSS_UNDEFINED;
var CSS_DIRECTION_INHERIT = 'inherit';
var CSS_DIRECTION_LTR = 'ltr';
var CSS_DIRECTION_RTL = 'rtl';
var CSS_FLEX_DIRECTION_ROW = 'row';
var CSS_FLEX_DIRECTION_ROW_REVERSE = 'row-reverse';
var CSS_FLEX_DIRECTION_COLUMN = 'column';
var CSS_FLEX_DIRECTION_COLUMN_REVERSE = 'column-reverse';
// var CSS_JUSTIFY_FLEX_START = 'flex-start';
var CSS_JUSTIFY_CENTER = 'center';
@@ -29,35 +35,47 @@ var computeLayout = (function() {
var CSS_POSITION_ABSOLUTE = 'absolute';
var leading = {
row: 'left',
column: 'top'
'row': 'left',
'row-reverse': 'right',
'column': 'top',
'column-reverse': 'bottom'
};
var trailing = {
row: 'right',
column: 'bottom'
'row': 'right',
'row-reverse': 'left',
'column': 'bottom',
'column-reverse': 'top'
};
var pos = {
row: 'left',
column: 'top'
'row': 'left',
'row-reverse': 'right',
'column': 'top',
'column-reverse': 'bottom'
};
var dim = {
row: 'width',
column: 'height'
'row': 'width',
'row-reverse': 'width',
'column': 'height',
'column-reverse': 'height'
};
function capitalizeFirst(str) {
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];
key = type + suffix;
if (key in node.style) {
return node.style[key];
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];
}
}
return 0;
@@ -67,7 +85,9 @@ var computeLayout = (function() {
width: undefined,
height: undefined,
top: 0,
left: 0
left: 0,
right: 0,
bottom: 0
};
if (!node.style) {
node.style = {};
@@ -88,18 +108,26 @@ var computeLayout = (function() {
} else {
delete node.children;
}
delete layout.right;
delete layout.bottom;
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;
@@ -109,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 getPadding(node, location) {
return getPositiveSpacing(node, 'padding', '', location);
function isColumnDirection(flexDirection) {
return flexDirection === CSS_FLEX_DIRECTION_COLUMN ||
flexDirection === CSS_FLEX_DIRECTION_COLUMN_REVERSE;
}
function getBorder(node, location) {
return getPositiveSpacing(node, 'border', 'Width', location);
function getLeadingLocations(axis) {
var locations = [leading[axis]];
if (isRowDirection(axis)) {
locations.unshift('start');
}
return locations;
}
function getPaddingAndBorder(node, location) {
return getPadding(node, location) + getBorder(node, location);
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 getTrailingPadding(node, axis) {
return getPadding(node, getTrailingLocations(axis));
}
function getBorder(node, locations) {
return getPositiveSpacing(node, 'border', 'Width', locations);
}
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) {
@@ -161,11 +246,46 @@ var computeLayout = (function() {
return 'stretch';
}
function resolveAxis(axis, direction) {
if (direction === CSS_DIRECTION_RTL) {
if (axis === CSS_FLEX_DIRECTION_ROW) {
return CSS_FLEX_DIRECTION_ROW_REVERSE;
} else if (axis === CSS_FLEX_DIRECTION_ROW_REVERSE) {
return CSS_FLEX_DIRECTION_ROW;
}
}
return axis;
}
function resolveDirection(node, parentDirection) {
var direction;
if ('direction' in node.style) {
direction = node.style.direction;
} else {
direction = CSS_DIRECTION_INHERIT;
}
if (direction === CSS_DIRECTION_INHERIT) {
direction = (parentDirection === undefined ? CSS_DIRECTION_LTR : parentDirection);
}
return direction;
}
function getFlexDirection(node) {
if ('flexDirection' in node.style) {
return node.style.flexDirection;
}
return 'column';
return CSS_FLEX_DIRECTION_COLUMN;
}
function getCrossFlexDirection(flexDirection, direction) {
if (isColumnDirection(flexDirection)) {
return resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);
} else {
return CSS_FLEX_DIRECTION_COLUMN;
}
}
function getPositionType(node) {
@@ -215,13 +335,17 @@ var computeLayout = (function() {
function boundAxis(node, axis, value) {
var min = {
row: node.style.minWidth,
column: node.style.minHeight
'row': node.style.minWidth,
'row-reverse': node.style.minWidth,
'column': node.style.minHeight,
'column-reverse': node.style.minHeight
}[axis];
var max = {
row: node.style.maxWidth,
column: node.style.maxHeight
'row': node.style.maxWidth,
'row-reverse': node.style.maxWidth,
'column': node.style.maxHeight,
'column-reverse': node.style.maxHeight
}[axis];
var boundValue = value;
@@ -259,6 +383,11 @@ var computeLayout = (function() {
);
}
function setTrailingPosition(node, child, axis) {
child.layout[trailing[axis]] = node.layout[dim[axis]] -
child.layout[dim[axis]] - child.layout[pos[axis]];
}
// If both left and right are defined, then use left. Otherwise return
// +left or -right depending on which is defined.
function getRelativePosition(node, axis) {
@@ -268,12 +397,11 @@ var computeLayout = (function() {
return -getPosition(node, trailing[axis]);
}
function layoutNode(node, parentMaxWidth) {
var/*css_flex_direction_t*/ mainAxis = getFlexDirection(node);
var/*css_flex_direction_t*/ crossAxis = mainAxis === CSS_FLEX_DIRECTION_ROW ?
CSS_FLEX_DIRECTION_COLUMN :
CSS_FLEX_DIRECTION_ROW;
function layoutNode(node, parentMaxWidth, /*css_direction_t*/parentDirection) {
var/*css_direction_t*/ direction = resolveDirection(node, parentDirection);
var/*css_flex_direction_t*/ mainAxis = resolveAxis(getFlexDirection(node), direction);
var/*css_flex_direction_t*/ crossAxis = getCrossFlexDirection(mainAxis, direction);
var/*css_flex_direction_t*/ resolvedRowAxis = resolveAxis(CSS_FLEX_DIRECTION_ROW, direction);
// Handle width and height style attributes
setDimensionFromStyle(node, mainAxis);
@@ -281,28 +409,32 @@ 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[leading[crossAxis]] += getMargin(node, leading[crossAxis]) +
node.layout[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) +
getRelativePosition(node, mainAxis);
node.layout[leading[crossAxis]] += getLeadingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis);
node.layout[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis);
if (isMeasureDefined(node)) {
var/*float*/ width = CSS_UNDEFINED;
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
if (isDimDefined(node, resolvedRowAxis)) {
width = node.style.width;
} else if (!isUndefined(node.layout[dim[CSS_FLEX_DIRECTION_ROW]])) {
width = node.layout[dim[CSS_FLEX_DIRECTION_ROW]];
} else if (!isUndefined(node.layout[dim[resolvedRowAxis]])) {
width = node.layout[dim[resolvedRowAxis]];
} else {
width = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW);
getMarginAxis(node, resolvedRowAxis);
}
width -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
width -= getPaddingAndBorderAxis(node, resolvedRowAxis);
// 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.
var/*bool*/ isRowUndefined = !isDimDefined(node, CSS_FLEX_DIRECTION_ROW) &&
isUndefined(node.layout[dim[CSS_FLEX_DIRECTION_ROW]]);
var/*bool*/ isRowUndefined = !isDimDefined(node, resolvedRowAxis) &&
isUndefined(node.layout[dim[resolvedRowAxis]]);
var/*bool*/ isColumnUndefined = !isDimDefined(node, CSS_FLEX_DIRECTION_COLUMN) &&
isUndefined(node.layout[dim[CSS_FLEX_DIRECTION_COLUMN]]);
@@ -315,14 +447,16 @@ var computeLayout = (function() {
);
if (isRowUndefined) {
node.layout.width = measureDim.width +
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
if (isColumnUndefined) {
node.layout.height = measureDim.height +
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
}
}
return;
if (node.children.length === 0) {
return;
}
}
var/*int*/ i;
@@ -419,20 +553,20 @@ var computeLayout = (function() {
} else {
maxWidth = CSS_UNDEFINED;
if (mainAxis !== CSS_FLEX_DIRECTION_ROW) {
if (!isRowDirection(mainAxis)) {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
getMarginAxis(node, resolvedRowAxis) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
maxWidth = node.layout[dim[CSS_FLEX_DIRECTION_ROW]] -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
if (isDimDefined(node, resolvedRowAxis)) {
maxWidth = node.layout[dim[resolvedRowAxis]] -
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
}
// This is the main recursive call. We layout non flexible children.
if (alreadyComputedNextLayout === 0) {
layoutNode(/*(java)!layoutContext, */child, maxWidth);
layoutNode(/*(java)!layoutContext, */child, maxWidth, direction);
}
// Absolute positioned elements do not take part of the layout, so we
@@ -451,6 +585,7 @@ var computeLayout = (function() {
// If there's only one element, then it's bigger than the content
// and needs its own line
i !== startLine) {
nonFlexibleChildrenCount--;
alreadyComputedNextLayout = 1;
break;
}
@@ -518,17 +653,17 @@ var computeLayout = (function() {
);
maxWidth = CSS_UNDEFINED;
if (isDimDefined(node, CSS_FLEX_DIRECTION_ROW)) {
maxWidth = node.layout[dim[CSS_FLEX_DIRECTION_ROW]] -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
} else if (mainAxis !== CSS_FLEX_DIRECTION_ROW) {
if (isDimDefined(node, resolvedRowAxis)) {
maxWidth = node.layout[dim[resolvedRowAxis]] -
getPaddingAndBorderAxis(node, resolvedRowAxis);
} else if (!isRowDirection(mainAxis)) {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSS_FLEX_DIRECTION_ROW) -
getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_ROW);
getMarginAxis(node, resolvedRowAxis) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
// And we recursively call the layout algorithm for this child
layoutNode(/*(java)!layoutContext, */child, maxWidth);
layoutNode(/*(java)!layoutContext, */child, maxWidth, direction);
}
}
@@ -564,7 +699,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];
@@ -576,12 +711,17 @@ 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.
child.layout[pos[mainAxis]] += mainDim;
// Define the trailing position accordingly.
if (!isUndefined(node.layout[dim[mainAxis]])) {
setTrailingPosition(node, child, mainAxis);
}
}
// Now that we placed the element, we need to update the variables
@@ -609,7 +749,6 @@ var computeLayout = (function() {
}
// <Loop D> Position elements in the cross axis
for (i = startLine; i < endLine; ++i) {
child = node.children[i];
@@ -619,11 +758,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
@@ -658,6 +797,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);
}
}
}
@@ -684,19 +828,19 @@ var computeLayout = (function() {
!isUndefined(node.layout[dim[crossAxis]])) {
var/*float*/ nodeCrossAxisInnerSize = node.layout[dim[crossAxis]] -
getPaddingAndBorderAxis(node, crossAxis);
var/*float*/ remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim;
var/*float*/ remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim;
var/*float*/ crossDimLead = 0;
var/*float*/ currentLead = getPaddingAndBorder(node, leading[crossAxis]);
var/*float*/ currentLead = getLeadingPaddingAndBorder(node, crossAxis);
var/*css_align_t*/ alignContent = getAlignContent(node);
if (alignContent === CSS_ALIGN_FLEX_END) {
currentLead += remainingCrossDim;
currentLead += remainingAlignContentDim;
} else if (alignContent === CSS_ALIGN_CENTER) {
currentLead += remainingCrossDim / 2;
currentLead += remainingAlignContentDim / 2;
} else if (alignContent === CSS_ALIGN_STRETCH) {
if (nodeCrossAxisInnerSize > linesCrossDim) {
crossDimLead = (remainingCrossDim / linesCount);
crossDimLead = (remainingAlignContentDim / linesCount);
}
}
@@ -730,16 +874,16 @@ var computeLayout = (function() {
continue;
}
var/*css_align_t*/ alignItem = getAlignItem(node, child);
if (alignItem === CSS_ALIGN_FLEX_START) {
child.layout[pos[crossAxis]] = currentLead + getMargin(child, leading[crossAxis]);
} else if (alignItem === CSS_ALIGN_FLEX_END) {
child.layout[pos[crossAxis]] = currentLead + lineHeight - getMargin(child,trailing[crossAxis]) - child.layout[dim[crossAxis]];
} else if (alignItem === CSS_ALIGN_CENTER) {
var/*css_align_t*/ alignContentAlignItem = getAlignItem(node, child);
if (alignContentAlignItem === CSS_ALIGN_FLEX_START) {
child.layout[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);
} else if (alignContentAlignItem === CSS_ALIGN_FLEX_END) {
child.layout[pos[crossAxis]] = currentLead + lineHeight - getTrailingMargin(child, crossAxis) - child.layout[dim[crossAxis]];
} else if (alignContentAlignItem === CSS_ALIGN_CENTER) {
var/*float*/ childHeight = child.layout[dim[crossAxis]];
child.layout[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2;
} else if (alignItem === CSS_ALIGN_STRETCH) {
child.layout[pos[crossAxis]] = currentLead + getMargin(child, leading[crossAxis]);
} else if (alignContentAlignItem === CSS_ALIGN_STRETCH) {
child.layout[pos[crossAxis]] = currentLead + getLeadingMargin(child, crossAxis);
// TODO(prenaux): Correctly set the height of items with undefined
// (auto) crossAxis dimension.
}
@@ -749,16 +893,21 @@ var computeLayout = (function() {
}
}
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)
);
needsMainTrailingPos = true;
}
if (isUndefined(node.layout[dim[crossAxis]])) {
@@ -769,9 +918,26 @@ var computeLayout = (function() {
boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)),
getPaddingAndBorderAxis(node, crossAxis)
);
needsCrossTrailingPos = true;
}
// <Loop F> Calculate dimensions for absolutely positioned elements
// <Loop F> 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);
}
}
}
// <Loop G> Calculate dimensions for absolutely positioned elements
for (i = 0; i < node.children.length; ++i) {
child = node.children[i];
if (getPositionType(child) === CSS_POSITION_ABSOLUTE) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.csslayout;
public enum CSSDirection {
INHERIT,
LTR,
RTL,
}

View File

@@ -10,5 +10,7 @@ package com.facebook.csslayout;
public enum CSSFlexDirection {
COLUMN,
COLUMN_REVERSE,
ROW,
ROW_REVERSE
}

View File

@@ -13,8 +13,10 @@ package com.facebook.csslayout;
*/
public class CSSLayout {
public float x;
public float y;
public float top;
public float left;
public float right;
public float bottom;
public float width = CSSConstants.UNDEFINED;
public float height = CSSConstants.UNDEFINED;
@@ -22,15 +24,19 @@ public class CSSLayout {
* This should always get called before calling {@link LayoutEngine#layoutNode(CSSNode, float)}
*/
public void resetResult() {
x = 0;
y = 0;
left = 0;
top = 0;
right = 0;
bottom = 0;
width = CSSConstants.UNDEFINED;
height = CSSConstants.UNDEFINED;
}
public void copy(CSSLayout layout) {
x = layout.x;
y = layout.y;
left = layout.left;
top = layout.top;
right = layout.right;
bottom = layout.bottom;
width = layout.width;
height = layout.height;
}
@@ -38,8 +44,8 @@ public class CSSLayout {
@Override
public String toString() {
return "layout: {" +
"x: " + x + ", " +
"y: " + y + ", " +
"left: " + left + ", " +
"top: " + top + ", " +
"width: " + width + ", " +
"height: " + height +
"}";

View File

@@ -49,10 +49,6 @@ public class CSSNode {
public void measure(CSSNode node, float width, MeasureOutput measureOutput);
}
private final float[] mMargin = Spacing.newFullSpacingArray();
private final float[] mPadding = Spacing.newFullSpacingArray();
private final float[] mBorder = Spacing.newFullSpacingArray();
// VisibleForTesting
/*package*/ final CSSStyle style = new CSSStyle();
/*package*/ final CSSLayout layout = new CSSLayout();
@@ -127,7 +123,7 @@ public class CSSNode {
*/
public void calculateLayout(CSSLayoutContext layoutContext) {
layout.resetResult();
LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED);
LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, null);
}
/**
@@ -265,24 +261,19 @@ public class CSSNode {
}
public void setMargin(int spacingType, float margin) {
setSpacing(mMargin, style.margin, spacingType, margin);
if (style.margin.set(spacingType, margin)) {
dirty();
}
}
public void setPadding(int spacingType, float padding) {
setSpacing(mPadding, style.padding, spacingType, padding);
if (style.padding.set(spacingType, padding)) {
dirty();
}
}
public void setBorder(int spacingType, float border) {
setSpacing(mBorder, style.border, spacingType, border);
}
protected void setSpacing(
float[] spacingDef,
float[] cssStyle,
int spacingType,
float spacing) {
if (!valuesEqual(spacingDef[spacingType], spacing)) {
Spacing.updateSpacing(spacingDef, cssStyle, spacingType, spacing, 0);
if (style.border.set(spacingType, border)) {
dirty();
}
}
@@ -330,11 +321,11 @@ public class CSSNode {
}
public float getLayoutX() {
return layout.x;
return layout.left;
}
public float getLayoutY() {
return layout.y;
return layout.top;
}
public float getLayoutWidth() {
@@ -344,4 +335,34 @@ public class CSSNode {
public float getLayoutHeight() {
return layout.height;
}
/**
* Get this node's padding, as defined by style + default padding.
*/
public Spacing getStylePadding() {
return style.padding;
}
/**
* Get this node's width, as defined in the style.
*/
public float getStyleWidth() {
return style.width;
}
/**
* Get this node's height, as defined in the style.
*/
public float getStyleHeight() {
return style.height;
}
/**
* Set a default padding (left/top/right/bottom) for this node.
*/
public void setDefaultPadding(int spacingType, float padding) {
if (style.padding.setDefault(spacingType, padding)) {
dirty();
}
}
}

View File

@@ -13,6 +13,7 @@ package com.facebook.csslayout;
*/
public class CSSStyle {
public CSSDirection direction = CSSDirection.INHERIT;
public CSSFlexDirection flexDirection = CSSFlexDirection.COLUMN;
public CSSJustify justifyContent = CSSJustify.FLEX_START;
public CSSAlign alignContent = CSSAlign.FLEX_START;
@@ -22,9 +23,9 @@ public class CSSStyle {
public CSSWrap flexWrap = CSSWrap.NOWRAP;
public float flex;
public float[] margin = Spacing.newSpacingResultArray();
public float[] padding = Spacing.newSpacingResultArray();
public float[] border = Spacing.newSpacingResultArray();
public Spacing margin = new Spacing();
public Spacing padding = new Spacing();
public Spacing border = new Spacing();
public float positionTop = CSSConstants.UNDEFINED;
public float positionBottom = CSSConstants.UNDEFINED;

View File

@@ -18,6 +18,8 @@ public class LayoutEngine {
LEFT,
BOTTOM,
RIGHT,
START,
END,
}
private static enum DimensionIndex {
@@ -28,24 +30,34 @@ public class LayoutEngine {
private static void setLayoutPosition(CSSNode node, PositionIndex position, float value) {
switch (position) {
case TOP:
node.layout.y = value;
node.layout.top = value;
break;
case LEFT:
node.layout.x = value;
node.layout.left = value;
break;
case RIGHT:
node.layout.right = value;
break;
case BOTTOM:
node.layout.bottom = value;
break;
default:
throw new RuntimeException("Didn't get TOP or LEFT!");
throw new RuntimeException("Didn't get TOP, LEFT, RIGHT, or BOTTOM!");
}
}
private static float getLayoutPosition(CSSNode node, PositionIndex position) {
switch (position) {
case TOP:
return node.layout.y;
return node.layout.top;
case LEFT:
return node.layout.x;
return node.layout.left;
case RIGHT:
return node.layout.right;
case BOTTOM:
return node.layout.bottom;
default:
throw new RuntimeException("Didn't get TOP or LEFT!");
throw new RuntimeException("Didn't get TOP, LEFT, RIGHT, or BOTTOM!");
}
}
@@ -100,19 +112,61 @@ public class LayoutEngine {
}
private static PositionIndex getLeading(CSSFlexDirection axis) {
return axis == CSSFlexDirection.COLUMN ? PositionIndex.TOP : PositionIndex.LEFT;
switch (axis) {
case COLUMN:
return PositionIndex.TOP;
case COLUMN_REVERSE:
return PositionIndex.BOTTOM;
case ROW:
return PositionIndex.LEFT;
case ROW_REVERSE:
return PositionIndex.RIGHT;
default:
throw new RuntimeException("Didn't get TOP, LEFT, RIGHT, or BOTTOM!");
}
}
private static PositionIndex getTrailing(CSSFlexDirection axis) {
return axis == CSSFlexDirection.COLUMN ? PositionIndex.BOTTOM : PositionIndex.RIGHT;
switch (axis) {
case COLUMN:
return PositionIndex.BOTTOM;
case COLUMN_REVERSE:
return PositionIndex.TOP;
case ROW:
return PositionIndex.RIGHT;
case ROW_REVERSE:
return PositionIndex.LEFT;
default:
throw new RuntimeException("Didn't get COLUMN, COLUMN_REVERSE, ROW, or ROW_REVERSE!");
}
}
private static PositionIndex getPos(CSSFlexDirection axis) {
return axis == CSSFlexDirection.COLUMN ? PositionIndex.TOP : PositionIndex.LEFT;
switch (axis) {
case COLUMN:
return PositionIndex.TOP;
case COLUMN_REVERSE:
return PositionIndex.BOTTOM;
case ROW:
return PositionIndex.LEFT;
case ROW_REVERSE:
return PositionIndex.RIGHT;
default:
throw new RuntimeException("Didn't get COLUMN, COLUMN_REVERSE, ROW, or ROW_REVERSE!");
}
}
private static DimensionIndex getDim(CSSFlexDirection axis) {
return axis == CSSFlexDirection.COLUMN ? DimensionIndex.HEIGHT : DimensionIndex.WIDTH;
switch (axis) {
case COLUMN:
case COLUMN_REVERSE:
return DimensionIndex.HEIGHT;
case ROW:
case ROW_REVERSE:
return DimensionIndex.WIDTH;
default:
throw new RuntimeException("Didn't get COLUMN, COLUMN_REVERSE, ROW, or ROW_REVERSE!");
}
}
private static boolean isDimDefined(CSSNode node, CSSFlexDirection axis) {
@@ -132,74 +186,154 @@ public class LayoutEngine {
private static float getMargin(CSSNode node, PositionIndex position) {
switch (position) {
case TOP:
return node.style.margin[Spacing.TOP];
return node.style.margin.get(Spacing.TOP);
case BOTTOM:
return node.style.margin[Spacing.BOTTOM];
return node.style.margin.get(Spacing.BOTTOM);
case LEFT:
return node.style.margin[Spacing.LEFT];
return node.style.margin.get(Spacing.LEFT);
case RIGHT:
return node.style.margin[Spacing.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:
return node.style.padding[Spacing.TOP];
return node.style.padding.get(Spacing.TOP);
case BOTTOM:
return node.style.padding[Spacing.BOTTOM];
return node.style.padding.get(Spacing.BOTTOM);
case LEFT:
return node.style.padding[Spacing.LEFT];
return node.style.padding.get(Spacing.LEFT);
case RIGHT:
return node.style.padding[Spacing.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:
return node.style.border[Spacing.TOP];
return node.style.border.get(Spacing.TOP);
case BOTTOM:
return node.style.border[Spacing.BOTTOM];
return node.style.border.get(Spacing.BOTTOM);
case LEFT:
return node.style.border[Spacing.LEFT];
return node.style.border.get(Spacing.LEFT);
case RIGHT:
return node.style.border[Spacing.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) {
float min = CSSConstants.UNDEFINED;
float max = CSSConstants.UNDEFINED;
if (axis == CSSFlexDirection.COLUMN) {
if (isColumnDirection(axis)) {
min = node.style.minHeight;
max = node.style.maxHeight;
} else if (axis == CSSFlexDirection.ROW) {
} else if (isRowDirection(axis)) {
min = node.style.minWidth;
max = node.style.maxWidth;
}
@@ -233,6 +367,18 @@ public class LayoutEngine {
setLayoutDimension(node, getDim(axis), maxLayoutDimension);
}
private static void setTrailingPosition(
CSSNode node,
CSSNode child,
CSSFlexDirection axis) {
setLayoutPosition(
child,
getTrailing(axis),
getLayoutDimension(node, getDim(axis)) -
getLayoutDimension(child, getDim(axis)) -
getLayoutPosition(child, getPos(axis)));
}
private static float getRelativePosition(CSSNode node, CSSFlexDirection axis) {
float lead = getStylePosition(node, getLeading(axis));
if (!CSSConstants.isUndefined(lead)) {
@@ -245,10 +391,53 @@ public class LayoutEngine {
return node.style.flex;
}
private static boolean isRowDirection(CSSFlexDirection flexDirection) {
return flexDirection == CSSFlexDirection.ROW ||
flexDirection == CSSFlexDirection.ROW_REVERSE;
}
private static boolean isColumnDirection(CSSFlexDirection flexDirection) {
return flexDirection == CSSFlexDirection.COLUMN ||
flexDirection == CSSFlexDirection.COLUMN_REVERSE;
}
private static CSSFlexDirection resolveAxis(
CSSFlexDirection axis,
CSSDirection direction) {
if (direction == CSSDirection.RTL) {
if (axis == CSSFlexDirection.ROW) {
return CSSFlexDirection.ROW_REVERSE;
} else if (axis == CSSFlexDirection.ROW_REVERSE) {
return CSSFlexDirection.ROW;
}
}
return axis;
}
private static CSSDirection resolveDirection(CSSNode node, CSSDirection parentDirection) {
CSSDirection direction = node.style.direction;
if (direction == CSSDirection.INHERIT) {
direction = (parentDirection == null ? CSSDirection.LTR : parentDirection);
}
return direction;
}
private static CSSFlexDirection getFlexDirection(CSSNode node) {
return node.style.flexDirection;
}
private static CSSFlexDirection getCrossFlexDirection(
CSSFlexDirection flexDirection,
CSSDirection direction) {
if (isColumnDirection(flexDirection)) {
return resolveAxis(CSSFlexDirection.ROW, direction);
} else {
return CSSFlexDirection.COLUMN;
}
}
private static CSSPositionType getPositionType(CSSNode node) {
return node.style.positionType;
}
@@ -282,8 +471,8 @@ public class LayoutEngine {
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) {
@@ -296,13 +485,14 @@ public class LayoutEngine {
/*package*/ static void layoutNode(
CSSLayoutContext layoutContext,
CSSNode node,
float parentMaxWidth) {
float parentMaxWidth,
CSSDirection parentDirection) {
if (needsRelayout(node, parentMaxWidth)) {
node.lastLayout.requestedWidth = node.layout.width;
node.lastLayout.requestedHeight = node.layout.height;
node.lastLayout.parentMaxWidth = parentMaxWidth;
layoutNodeImpl(layoutContext, node, parentMaxWidth);
layoutNodeImpl(layoutContext, node, parentMaxWidth, parentDirection);
node.lastLayout.copy(node.layout);
} else {
node.layout.copy(node.lastLayout);
@@ -314,18 +504,18 @@ public class LayoutEngine {
private static void layoutNodeImpl(
CSSLayoutContext layoutContext,
CSSNode node,
float parentMaxWidth) {
float parentMaxWidth,
CSSDirection parentDirection) {
for (int i = 0; i < node.getChildCount(); i++) {
node.getChildAt(i).layout.resetResult();
}
/** START_GENERATED **/
CSSFlexDirection mainAxis = getFlexDirection(node);
CSSFlexDirection crossAxis = mainAxis == CSSFlexDirection.ROW ?
CSSFlexDirection.COLUMN :
CSSFlexDirection.ROW;
CSSDirection direction = resolveDirection(node, parentDirection);
CSSFlexDirection mainAxis = resolveAxis(getFlexDirection(node), direction);
CSSFlexDirection crossAxis = getCrossFlexDirection(mainAxis, direction);
CSSFlexDirection resolvedRowAxis = resolveAxis(CSSFlexDirection.ROW, direction);
// Handle width and height style attributes
setDimensionFromStyle(node, mainAxis);
@@ -333,28 +523,32 @@ public class LayoutEngine {
// 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, getLeading(crossAxis), getLayoutPosition(node, getLeading(crossAxis)) + getMargin(node, getLeading(crossAxis)) +
setLayoutPosition(node, getTrailing(mainAxis), getLayoutPosition(node, getTrailing(mainAxis)) + getTrailingMargin(node, mainAxis) +
getRelativePosition(node, mainAxis));
setLayoutPosition(node, getLeading(crossAxis), getLayoutPosition(node, getLeading(crossAxis)) + getLeadingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis));
setLayoutPosition(node, getTrailing(crossAxis), getLayoutPosition(node, getTrailing(crossAxis)) + getTrailingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis));
if (isMeasureDefined(node)) {
float width = CSSConstants.UNDEFINED;
if (isDimDefined(node, CSSFlexDirection.ROW)) {
if (isDimDefined(node, resolvedRowAxis)) {
width = node.style.width;
} else if (!CSSConstants.isUndefined(getLayoutDimension(node, getDim(CSSFlexDirection.ROW)))) {
width = getLayoutDimension(node, getDim(CSSFlexDirection.ROW));
} else if (!CSSConstants.isUndefined(getLayoutDimension(node, getDim(resolvedRowAxis)))) {
width = getLayoutDimension(node, getDim(resolvedRowAxis));
} else {
width = parentMaxWidth -
getMarginAxis(node, CSSFlexDirection.ROW);
getMarginAxis(node, resolvedRowAxis);
}
width -= getPaddingAndBorderAxis(node, CSSFlexDirection.ROW);
width -= getPaddingAndBorderAxis(node, resolvedRowAxis);
// 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) &&
CSSConstants.isUndefined(getLayoutDimension(node, getDim(CSSFlexDirection.ROW)));
boolean isRowUndefined = !isDimDefined(node, resolvedRowAxis) &&
CSSConstants.isUndefined(getLayoutDimension(node, getDim(resolvedRowAxis)));
boolean isColumnUndefined = !isDimDefined(node, CSSFlexDirection.COLUMN) &&
CSSConstants.isUndefined(getLayoutDimension(node, getDim(CSSFlexDirection.COLUMN)));
@@ -366,14 +560,16 @@ public class LayoutEngine {
);
if (isRowUndefined) {
node.layout.width = measureDim.width +
getPaddingAndBorderAxis(node, CSSFlexDirection.ROW);
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
if (isColumnUndefined) {
node.layout.height = measureDim.height +
getPaddingAndBorderAxis(node, CSSFlexDirection.COLUMN);
}
}
return;
if (node.getChildCount() == 0) {
return;
}
}
int i;
@@ -470,20 +666,20 @@ public class LayoutEngine {
} else {
maxWidth = CSSConstants.UNDEFINED;
if (mainAxis != CSSFlexDirection.ROW) {
if (!isRowDirection(mainAxis)) {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSSFlexDirection.ROW) -
getPaddingAndBorderAxis(node, CSSFlexDirection.ROW);
getMarginAxis(node, resolvedRowAxis) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
if (isDimDefined(node, CSSFlexDirection.ROW)) {
maxWidth = getLayoutDimension(node, getDim(CSSFlexDirection.ROW)) -
getPaddingAndBorderAxis(node, CSSFlexDirection.ROW);
if (isDimDefined(node, resolvedRowAxis)) {
maxWidth = getLayoutDimension(node, getDim(resolvedRowAxis)) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
}
// This is the main recursive call. We layout non flexible children.
if (alreadyComputedNextLayout == 0) {
layoutNode(layoutContext, child, maxWidth);
layoutNode(layoutContext, child, maxWidth, direction);
}
// Absolute positioned elements do not take part of the layout, so we
@@ -502,6 +698,7 @@ public class LayoutEngine {
// If there's only one element, then it's bigger than the content
// and needs its own line
i != startLine) {
nonFlexibleChildrenCount--;
alreadyComputedNextLayout = 1;
break;
}
@@ -569,17 +766,17 @@ public class LayoutEngine {
));
maxWidth = CSSConstants.UNDEFINED;
if (isDimDefined(node, CSSFlexDirection.ROW)) {
maxWidth = getLayoutDimension(node, getDim(CSSFlexDirection.ROW)) -
getPaddingAndBorderAxis(node, CSSFlexDirection.ROW);
} else if (mainAxis != CSSFlexDirection.ROW) {
if (isDimDefined(node, resolvedRowAxis)) {
maxWidth = getLayoutDimension(node, getDim(resolvedRowAxis)) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
} else if (!isRowDirection(mainAxis)) {
maxWidth = parentMaxWidth -
getMarginAxis(node, CSSFlexDirection.ROW) -
getPaddingAndBorderAxis(node, CSSFlexDirection.ROW);
getMarginAxis(node, resolvedRowAxis) -
getPaddingAndBorderAxis(node, resolvedRowAxis);
}
// And we recursively call the layout algorithm for this child
layoutNode(layoutContext, child, maxWidth);
layoutNode(layoutContext, child, maxWidth, direction);
}
}
@@ -615,7 +812,7 @@ public class LayoutEngine {
// container!
float crossDim = 0;
float mainDim = leadingMainDim +
getPaddingAndBorder(node, getLeading(mainAxis));
getLeadingPaddingAndBorder(node, mainAxis);
for (i = startLine; i < endLine; ++i) {
child = node.getChildAt(i);
@@ -627,12 +824,17 @@ public class LayoutEngine {
// 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.
setLayoutPosition(child, getPos(mainAxis), getLayoutPosition(child, getPos(mainAxis)) + mainDim);
// Define the trailing position accordingly.
if (!CSSConstants.isUndefined(getLayoutDimension(node, getDim(mainAxis)))) {
setTrailingPosition(node, child, mainAxis);
}
}
// Now that we placed the element, we need to update the variables
@@ -660,7 +862,6 @@ public class LayoutEngine {
}
// <Loop D> Position elements in the cross axis
for (i = startLine; i < endLine; ++i) {
child = node.getChildAt(i);
@@ -670,11 +871,11 @@ public class LayoutEngine {
// 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
@@ -709,6 +910,11 @@ public class LayoutEngine {
// 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);
}
}
}
@@ -735,19 +941,19 @@ public class LayoutEngine {
!CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis)))) {
float nodeCrossAxisInnerSize = getLayoutDimension(node, getDim(crossAxis)) -
getPaddingAndBorderAxis(node, crossAxis);
float remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim;
float remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim;
float crossDimLead = 0;
float currentLead = getPaddingAndBorder(node, getLeading(crossAxis));
float currentLead = getLeadingPaddingAndBorder(node, crossAxis);
CSSAlign alignContent = getAlignContent(node);
if (alignContent == CSSAlign.FLEX_END) {
currentLead = currentLead + remainingCrossDim;
currentLead = currentLead + remainingAlignContentDim;
} else if (alignContent == CSSAlign.CENTER) {
currentLead = currentLead + remainingCrossDim / 2;
currentLead = currentLead + remainingAlignContentDim / 2;
} else if (alignContent == CSSAlign.STRETCH) {
if (nodeCrossAxisInnerSize > linesCrossDim) {
crossDimLead = (remainingCrossDim / linesCount);
crossDimLead = (remainingAlignContentDim / linesCount);
}
}
@@ -781,16 +987,16 @@ public class LayoutEngine {
continue;
}
CSSAlign alignItem = getAlignItem(node, child);
if (alignItem == CSSAlign.FLEX_START) {
setLayoutPosition(child, getPos(crossAxis), currentLead + getMargin(child, getLeading(crossAxis)));
} else if (alignItem == CSSAlign.FLEX_END) {
setLayoutPosition(child, getPos(crossAxis), currentLead + lineHeight - getMargin(child,getTrailing(crossAxis)) - getLayoutDimension(child, getDim(crossAxis)));
} else if (alignItem == CSSAlign.CENTER) {
CSSAlign alignContentAlignItem = getAlignItem(node, child);
if (alignContentAlignItem == CSSAlign.FLEX_START) {
setLayoutPosition(child, getPos(crossAxis), currentLead + getLeadingMargin(child, crossAxis));
} else if (alignContentAlignItem == CSSAlign.FLEX_END) {
setLayoutPosition(child, getPos(crossAxis), currentLead + lineHeight - getTrailingMargin(child, crossAxis) - getLayoutDimension(child, getDim(crossAxis)));
} else if (alignContentAlignItem == CSSAlign.CENTER) {
float childHeight = getLayoutDimension(child, getDim(crossAxis));
setLayoutPosition(child, getPos(crossAxis), currentLead + (lineHeight - childHeight) / 2);
} else if (alignItem == CSSAlign.STRETCH) {
setLayoutPosition(child, getPos(crossAxis), currentLead + getMargin(child, getLeading(crossAxis)));
} else if (alignContentAlignItem == CSSAlign.STRETCH) {
setLayoutPosition(child, getPos(crossAxis), currentLead + getLeadingMargin(child, crossAxis));
// TODO(prenaux): Correctly set the height of items with undefined
// (auto) crossAxis dimension.
}
@@ -800,16 +1006,21 @@ public class LayoutEngine {
}
}
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)
));
needsMainTrailingPos = true;
}
if (CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis)))) {
@@ -820,9 +1031,26 @@ public class LayoutEngine {
boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)),
getPaddingAndBorderAxis(node, crossAxis)
));
needsCrossTrailingPos = true;
}
// <Loop F> Calculate dimensions for absolutely positioned elements
// <Loop F> 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);
}
}
}
// <Loop G> Calculate dimensions for absolutely positioned elements
for (i = 0; i < node.getChildCount(); ++i) {
child = node.getChildAt(i);
if (getPositionType(child) == CSSPositionType.ABSOLUTE) {

View File

@@ -8,28 +8,124 @@
*/
package com.facebook.csslayout;
import javax.annotation.Nullable;
/**
* Utility class for handling CSS spacing (padding, margin, and borders). This is mostly necessary
* to properly implement interactions and updates for properties like margin, marginLeft, and
* marginHorizontal. This is not a great API and should probably be updated to use actual objects
* for type safety, defaults safety, and simplicity.
* Class representing CSS spacing (padding, margin, and borders). This is mostly necessary to
* properly implement interactions and updates for properties like margin, marginLeft, and
* marginHorizontal.
*/
public class Spacing {
// Indices into FullSpacingArray and SpacingResultArray
/**
* Spacing type that represents the left direction. E.g. {@code marginLeft}.
*/
public static final int LEFT = 0;
/**
* Spacing type that represents the top direction. E.g. {@code marginTop}.
*/
public static final int TOP = 1;
/**
* Spacing type that represents the right direction. E.g. {@code marginRight}.
*/
public static final int RIGHT = 2;
/**
* Spacing type that represents the bottom direction. E.g. {@code marginBottom}.
*/
public static final int BOTTOM = 3;
/**
* Spacing type that represents vertical direction (top and bottom). E.g. {@code marginVertical}.
*/
public static final int VERTICAL = 4;
/**
* Spacing type that represents horizontal direction (left and right). E.g.
* {@code marginHorizontal}.
*/
public static final int HORIZONTAL = 5;
public static final int ALL = 6;
/**
* 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 = 8;
private final float[] mSpacing = newFullSpacingArray();
@Nullable private float[] mDefaultSpacing = null;
/**
* @return an instance of an array that can be used with {@link #updateSpacing}. Stores
* the value for each spacing type or NaN if it hasn't been explicitly set.
* Set a spacing value.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM},
* {@link #VERTICAL}, {@link #HORIZONTAL}, {@link #ALL}
* @param value the value for this direction
* @return {@code true} if the spacing has changed, or {@code false} if the same value was already
* set
*/
public static float[] newFullSpacingArray() {
public boolean set(int spacingType, float value) {
if (!FloatUtil.floatsEqual(mSpacing[spacingType], value)) {
mSpacing[spacingType] = value;
return true;
}
return false;
}
/**
* Set a default spacing value. This is used as a fallback when no spacing has been set for a
* particular direction.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM}
* @param value the default value for this direction
* @return
*/
public boolean setDefault(int spacingType, float value) {
if (mDefaultSpacing == null) {
mDefaultSpacing = newSpacingResultArray();
}
if (!FloatUtil.floatsEqual(mDefaultSpacing[spacingType], value)) {
mDefaultSpacing[spacingType] = value;
return true;
}
return false;
}
/**
* Get the spacing for a direction. This takes into account any default values that have been set.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM}
*/
public float get(int spacingType) {
int secondType = spacingType == TOP || spacingType == BOTTOM ? VERTICAL : HORIZONTAL;
float defaultValue = spacingType == START || spacingType == END ? CSSConstants.UNDEFINED : 0;
return
!CSSConstants.isUndefined(mSpacing[spacingType])
? mSpacing[spacingType]
: !CSSConstants.isUndefined(mSpacing[secondType])
? mSpacing[secondType]
: !CSSConstants.isUndefined(mSpacing[ALL])
? mSpacing[ALL]
: mDefaultSpacing != null
? mDefaultSpacing[spacingType]
: defaultValue;
}
/**
* Get the raw value (that was set using {@link #set(int, float)}), without taking into account
* any default values.
*
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM},
* {@link #VERTICAL}, {@link #HORIZONTAL}, {@link #ALL}
*/
public float getRaw(int spacingType) {
return mSpacing[spacingType];
}
private static float[] newFullSpacingArray() {
return new float[] {
CSSConstants.UNDEFINED,
CSSConstants.UNDEFINED,
@@ -39,65 +135,25 @@ public class Spacing {
CSSConstants.UNDEFINED,
CSSConstants.UNDEFINED,
CSSConstants.UNDEFINED,
CSSConstants.UNDEFINED,
};
}
/**
* @return {@link #newSpacingResultArray} filled with zero.
*/
public static float[] newSpacingResultArray() {
private static float[] newSpacingResultArray() {
return newSpacingResultArray(0);
}
/**
* @return an instance of an array used to store the end result of the interactions between the
* values in a full spacing array. Use {@link #TOP}, etc to access result values.
*/
public static float[] newSpacingResultArray(float defaultValue) {
private static float[] newSpacingResultArray(float defaultValue) {
return new float[] {
defaultValue,
defaultValue,
defaultValue,
defaultValue,
defaultValue,
defaultValue,
CSSConstants.UNDEFINED,
CSSConstants.UNDEFINED,
defaultValue,
};
}
/**
* Given the fullSpacing from {@link #newFullSpacingArray()} and the spacingResult from
* {@link #newSpacingResultArray()} from a View, update them both to reflect a new value for the
* given spacingType (e.g. {@link #TOP}). defaultValue specifies the result value that should be
* used whenever a spacing property hasn't been set.
*/
public static void updateSpacing(
float[] fullSpacing,
float[] spacingResult,
int spacingType,
float value,
float defaultValue) {
fullSpacing[spacingType] = value;
spacingResult[Spacing.TOP] =
!CSSConstants.isUndefined(fullSpacing[Spacing.TOP]) ? fullSpacing[Spacing.TOP]
: !CSSConstants.isUndefined(fullSpacing[Spacing.VERTICAL]) ?
fullSpacing[Spacing.VERTICAL]
: !CSSConstants.isUndefined(fullSpacing[Spacing.ALL]) ? fullSpacing[Spacing.ALL]
: defaultValue;
spacingResult[Spacing.BOTTOM] =
!CSSConstants.isUndefined(fullSpacing[Spacing.BOTTOM]) ? fullSpacing[Spacing.BOTTOM]
: !CSSConstants.isUndefined(fullSpacing[Spacing.VERTICAL]) ?
fullSpacing[Spacing.VERTICAL]
: !CSSConstants.isUndefined(fullSpacing[Spacing.ALL]) ? fullSpacing[Spacing.ALL]
: defaultValue;
spacingResult[Spacing.LEFT] =
!CSSConstants.isUndefined(fullSpacing[Spacing.LEFT]) ? fullSpacing[Spacing.LEFT]
: !CSSConstants.isUndefined(fullSpacing[Spacing.HORIZONTAL]) ?
fullSpacing[Spacing.HORIZONTAL]
: !CSSConstants.isUndefined(fullSpacing[Spacing.ALL]) ? fullSpacing[Spacing.ALL]
: defaultValue;
spacingResult[Spacing.RIGHT] =
!CSSConstants.isUndefined(fullSpacing[Spacing.RIGHT]) ? fullSpacing[Spacing.RIGHT]
: !CSSConstants.isUndefined(fullSpacing[Spacing.HORIZONTAL]) ?
fullSpacing[Spacing.HORIZONTAL]
: !CSSConstants.isUndefined(fullSpacing[Spacing.ALL]) ? fullSpacing[Spacing.ALL]
: defaultValue;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -100,11 +100,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) {
@@ -114,9 +118,15 @@ function printLayout(test) {
}
}
addEnum(node, 'direction', 'direction', {
'ltr': 'CSS_DIRECTION_LTR',
'rtl': 'CSS_DIRECTION_RTL'
});
addEnum(node, 'flexDirection', 'flex_direction', {
'row': 'CSS_FLEX_DIRECTION_ROW',
'column': 'CSS_FLEX_DIRECTION_COLUMN'
'row-reverse': 'CSS_FLEX_DIRECTION_ROW_REVERSE',
'column': 'CSS_FLEX_DIRECTION_COLUMN',
'column-reverse': 'CSS_FLEX_DIRECTION_COLUMN_REVERSE'
});
addEnum(node, 'justifyContent', 'justify_content', {
'flex-start': 'CSS_JUSTIFY_FLEX_START',
@@ -244,6 +254,7 @@ function transpileAnnotatedJStoC(jsCode) {
.replace(/layout\[dim/g, 'layout.dimensions[dim')
.replace(/layout\[pos/g, 'layout.position[pos')
.replace(/layout\[leading/g, 'layout.position[leading')
.replace(/layout\[trailing/g, 'layout.position[trailing')
.replace(/style\[dim/g, 'style.dimensions[dim')
.replace(/node.children\[i\]/g, 'node->get_child(node->context, i)')
.replace(/node.children\[ii\]/g, 'node->get_child(node->context, ii)')