Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -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')
|
||||
|
@@ -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");
|
||||
|
@@ -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');
|
||||
|
338
src/Layout.c
338
src/Layout.c
@@ -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];
|
||||
|
25
src/Layout.h
25
src/Layout.h
@@ -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
|
||||
|
354
src/Layout.js
354
src/Layout.js
@@ -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
15
src/java/src/com/facebook/csslayout/CSSDirection.java
Normal file
15
src/java/src/com/facebook/csslayout/CSSDirection.java
Normal 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,
|
||||
}
|
@@ -10,5 +10,7 @@ package com.facebook.csslayout;
|
||||
|
||||
public enum CSSFlexDirection {
|
||||
COLUMN,
|
||||
COLUMN_REVERSE,
|
||||
ROW,
|
||||
ROW_REVERSE
|
||||
}
|
||||
|
@@ -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 +
|
||||
"}";
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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) {
|
||||
|
@@ -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
@@ -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)')
|
||||
|
Reference in New Issue
Block a user