Skip to content

Commit

Permalink
Implement (padding|border|margin)-(start|end) support
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasr committed May 14, 2015
1 parent c3a2ddc commit 03dfe7b
Show file tree
Hide file tree
Showing 11 changed files with 1,372 additions and 132 deletions.
6 changes: 3 additions & 3 deletions src/JavaTranspiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ function __transpileSingleTestToJava(code) {
return 'style.' + match1 + match2[0] + match2.substring(1).toLowerCase();
})
.replace( // style.margin[CSS_TOP] = 12.3 => style.margin[Spacing.TOP].set(12.3)
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT)\]\s+=\s+(-?[\.\d]+)/g,
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]\s+=\s+(-?[\.\d]+)/g,
function (str, match1, match2, match3) {
var propertyCap = match1.charAt(0).toUpperCase() + match1.slice(1);
return 'set' + propertyCap + '(Spacing.' + match2 + ', ' + match3 + ')';
})
.replace( // style.margin[CSS_TOP] => style.margin.get(Spacing.TOP)
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT)\]/g,
.replace( // style.margin[CSS_TOP] => style.margin[Spacing.TOP]
/style\.(margin|border|padding)\[CSS_(TOP|BOTTOM|LEFT|RIGHT|START|END)\]/g,
function (str, match1, match2) {
return 'style.' + match1 + '.get(Spacing.' + match2 + ')';
})
Expand Down
12 changes: 10 additions & 2 deletions src/Layout-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ var layoutTestUtils = (function() {
return layout;
}

function capitalizeFirst(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}

function computeCSSLayout(rootNode) {
fillNodes(rootNode);
realComputeLayout(rootNode);
Expand All @@ -155,8 +159,10 @@ var layoutTestUtils = (function() {

function transfer(div, node, name, ext) {
if (name in node.style) {
div.style['-webkit-' + name] = node.style[name] + (ext || '');
div.style[name] = node.style[name] + (ext || '');
var value = node.style[name] + (ext || '');
div.style['-webkit-' + name] = value;
div.style['webkit' + capitalizeFirst(name)] = value;
div.style[name] = value;
}
}

Expand All @@ -166,6 +172,8 @@ var layoutTestUtils = (function() {
transfer(div, node, type + 'Top' + suffix, 'px');
transfer(div, node, type + 'Bottom' + suffix, 'px');
transfer(div, node, type + 'Right' + suffix, 'px');
transfer(div, node, type + 'Start' + suffix, 'px');
transfer(div, node, type + 'End' + suffix, 'px');
}

function renderNode(parent, node) {
Expand Down
176 changes: 134 additions & 42 deletions src/Layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ void init_css_node(css_node_t *node) {
node->style.position[CSS_RIGHT] = CSS_UNDEFINED;
node->style.position[CSS_BOTTOM] = CSS_UNDEFINED;

node->style.margin[CSS_START] = CSS_UNDEFINED;
node->style.margin[CSS_END] = CSS_UNDEFINED;
node->style.padding[CSS_START] = CSS_UNDEFINED;
node->style.padding[CSS_END] = CSS_UNDEFINED;
node->style.border[CSS_START] = CSS_UNDEFINED;
node->style.border[CSS_END] = CSS_UNDEFINED;

node->layout.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
node->layout.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;

Expand Down Expand Up @@ -170,6 +177,8 @@ static void print_css_node_rec(
print_number_0("marginRight", node->style.margin[CSS_RIGHT]);
print_number_0("marginTop", node->style.margin[CSS_TOP]);
print_number_0("marginBottom", node->style.margin[CSS_BOTTOM]);
print_number_0("marginStart", node->style.margin[CSS_START]);
print_number_0("marginEnd", node->style.margin[CSS_END]);
}

if (four_equal(node->style.padding)) {
Expand All @@ -179,6 +188,8 @@ static void print_css_node_rec(
print_number_0("paddingRight", node->style.padding[CSS_RIGHT]);
print_number_0("paddingTop", node->style.padding[CSS_TOP]);
print_number_0("paddingBottom", node->style.padding[CSS_BOTTOM]);
print_number_0("paddingStart", node->style.padding[CSS_START]);
print_number_0("paddingEnd", node->style.padding[CSS_END]);
}

if (four_equal(node->style.border)) {
Expand All @@ -188,6 +199,8 @@ static void print_css_node_rec(
print_number_0("borderRightWidth", node->style.border[CSS_RIGHT]);
print_number_0("borderTopWidth", node->style.border[CSS_TOP]);
print_number_0("borderBottomWidth", node->style.border[CSS_BOTTOM]);
print_number_0("borderStartWidth", node->style.border[CSS_START]);
print_number_0("borderEndWidth", node->style.border[CSS_END]);
}

print_number_nan("width", node->style.dimensions[CSS_WIDTH]);
Expand Down Expand Up @@ -245,39 +258,106 @@ static css_dimension_t dim[4] = {
/* CSS_FLEX_DIRECTION_ROW_REVERSE = */ CSS_WIDTH
};

static bool isRowDirection(css_flex_direction_t flex_direction) {
return flex_direction == CSS_FLEX_DIRECTION_ROW ||
flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE;
}

static float getMargin(css_node_t *node, int location) {
return node->style.margin[location];
static bool isColumnDirection(css_flex_direction_t flex_direction) {
return flex_direction == CSS_FLEX_DIRECTION_COLUMN ||
flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE;
}

static float getPadding(css_node_t *node, int location) {
if (node->style.padding[location] >= 0) {
return node->style.padding[location];
static float getLeadingMargin(css_node_t *node, css_flex_direction_t axis) {
if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_START])) {
return node->style.margin[CSS_START];
}

return node->style.margin[leading[axis]];
}

static float getTrailingMargin(css_node_t *node, css_flex_direction_t axis) {
if (isRowDirection(axis) && !isUndefined(node->style.margin[CSS_END])) {
return node->style.margin[CSS_END];
}

return node->style.margin[trailing[axis]];
}

static float getLeadingPadding(css_node_t *node, css_flex_direction_t axis) {
if (isRowDirection(axis) &&
!isUndefined(node->style.padding[CSS_START]) &&
node->style.padding[CSS_START] >= 0) {
return node->style.padding[CSS_START];
}

if (node->style.padding[leading[axis]] >= 0) {
return node->style.padding[leading[axis]];
}

return 0;
}

static float getBorder(css_node_t *node, int location) {
if (node->style.border[location] >= 0) {
return node->style.border[location];
static float getTrailingPadding(css_node_t *node, css_flex_direction_t axis) {
if (isRowDirection(axis) &&
!isUndefined(node->style.padding[CSS_END]) &&
node->style.padding[CSS_END] >= 0) {
return node->style.padding[CSS_END];
}

if (node->style.padding[trailing[axis]] >= 0) {
return node->style.padding[trailing[axis]];
}

return 0;
}

static float getPaddingAndBorder(css_node_t *node, int location) {
return getPadding(node, location) + getBorder(node, location);
static float getLeadingBorder(css_node_t *node, css_flex_direction_t axis) {
if (isRowDirection(axis) &&
!isUndefined(node->style.border[CSS_START]) &&
node->style.border[CSS_START] >= 0) {
return node->style.border[CSS_START];
}

if (node->style.border[leading[axis]] >= 0) {
return node->style.border[leading[axis]];
}

return 0;
}

static float getTrailingBorder(css_node_t *node, css_flex_direction_t axis) {
if (isRowDirection(axis) &&
!isUndefined(node->style.border[CSS_END]) &&
node->style.border[CSS_END] >= 0) {
return node->style.border[CSS_END];
}

if (node->style.border[trailing[axis]] >= 0) {
return node->style.border[trailing[axis]];
}

return 0;
}

static float getLeadingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) {
return getLeadingPadding(node, axis) + getLeadingBorder(node, axis);
}

static float getTrailingPaddingAndBorder(css_node_t *node, css_flex_direction_t axis) {
return getTrailingPadding(node, axis) + getTrailingBorder(node, axis);
}

static float getBorderAxis(css_node_t *node, css_flex_direction_t axis) {
return getBorder(node, leading[axis]) + getBorder(node, trailing[axis]);
return getLeadingBorder(node, axis) + getTrailingBorder(node, axis);
}

static float getMarginAxis(css_node_t *node, css_flex_direction_t axis) {
return getMargin(node, leading[axis]) + getMargin(node, trailing[axis]);
return getLeadingMargin(node, axis) + getTrailingMargin(node, axis);
}

static float getPaddingAndBorderAxis(css_node_t *node, css_flex_direction_t axis) {
return getPaddingAndBorder(node, leading[axis]) + getPaddingAndBorder(node, trailing[axis]);
return getLeadingPaddingAndBorder(node, axis) + getTrailingPaddingAndBorder(node, axis);
}

static css_position_type_t getPositionType(css_node_t *node) {
Expand All @@ -295,16 +375,6 @@ static css_align_t getAlignItem(css_node_t *node, css_node_t *child) {
return node->style.align_items;
}

static bool isRowDirection(css_flex_direction_t flex_direction) {
return flex_direction == CSS_FLEX_DIRECTION_ROW ||
flex_direction == CSS_FLEX_DIRECTION_ROW_REVERSE;
}

static bool isColumnDirection(css_flex_direction_t flex_direction) {
return flex_direction == CSS_FLEX_DIRECTION_COLUMN ||
flex_direction == CSS_FLEX_DIRECTION_COLUMN_REVERSE;
}

static css_direction_t resolveDirection(css_node_t *node, css_direction_t parentDirection) {
css_direction_t direction = node->style.direction;

Expand Down Expand Up @@ -356,8 +426,8 @@ static bool isFlexWrap(css_node_t *node) {

static float getDimWithMargin(css_node_t *node, css_flex_direction_t axis) {
return node->layout.dimensions[dim[axis]] +
getMargin(node, leading[axis]) +
getMargin(node, trailing[axis]);
getLeadingMargin(node, axis) +
getTrailingMargin(node, axis);
}

static bool isDimDefined(css_node_t *node, css_flex_direction_t axis) {
Expand Down Expand Up @@ -451,13 +521,13 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction

// The position is set by the parent, but we need to complete it with a
// delta composed of the margin and left/top/right/bottom
node->layout.position[leading[mainAxis]] += getMargin(node, leading[mainAxis]) +
node->layout.position[leading[mainAxis]] += getLeadingMargin(node, mainAxis) +
getRelativePosition(node, mainAxis);
node->layout.position[trailing[mainAxis]] += getMargin(node, trailing[mainAxis]) +
node->layout.position[trailing[mainAxis]] += getTrailingMargin(node, mainAxis) +
getRelativePosition(node, mainAxis);
node->layout.position[leading[crossAxis]] += getMargin(node, leading[crossAxis]) +
node->layout.position[leading[crossAxis]] += getLeadingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis);
node->layout.position[trailing[crossAxis]] += getMargin(node, trailing[crossAxis]) +
node->layout.position[trailing[crossAxis]] += getTrailingMargin(node, crossAxis) +
getRelativePosition(node, crossAxis);

if (isMeasureDefined(node)) {
Expand Down Expand Up @@ -740,7 +810,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
// container!
float crossDim = 0;
float mainDim = leadingMainDim +
getPaddingAndBorder(node, leading[mainAxis]);
getLeadingPaddingAndBorder(node, mainAxis);

for (i = startLine; i < endLine; ++i) {
child = node->get_child(node->context, i);
Expand All @@ -751,8 +821,8 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
// defined, we override the position to whatever the user said
// (and margin/border).
child->layout.position[pos[mainAxis]] = getPosition(child, leading[mainAxis]) +
getBorder(node, leading[mainAxis]) +
getMargin(child, leading[mainAxis]);
getLeadingBorder(node, mainAxis) +
getLeadingMargin(child, mainAxis);
} else {
// If the child is position absolute (without top/left) or relative,
// we put it at the current accumulated offset.
Expand Down Expand Up @@ -799,11 +869,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
// top/left/bottom/right being set, we override all the previously
// computed positions to set it correctly.
child->layout.position[pos[crossAxis]] = getPosition(child, leading[crossAxis]) +
getBorder(node, leading[crossAxis]) +
getMargin(child, leading[crossAxis]);
getLeadingBorder(node, crossAxis) +
getLeadingMargin(child, crossAxis);

} else {
float leadingCrossDim = getPaddingAndBorder(node, leading[crossAxis]);
float leadingCrossDim = getLeadingPaddingAndBorder(node, crossAxis);

// For a relative children, we're either using alignItems (parent) or
// alignSelf (child) in order to determine the position in the cross axis
Expand Down Expand Up @@ -838,6 +908,11 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction

// And we apply the position
child->layout.position[pos[crossAxis]] += linesCrossDim + leadingCrossDim;

// Define the trailing position accordingly.
if (!isUndefined(node->layout.dimensions[dim[crossAxis]])) {
setTrailingPosition(node, child, crossAxis);
}
}
}

Expand All @@ -846,22 +921,21 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
startLine = endLine;
}

bool needsMainTrailingPos = false;
bool needsCrossTrailingPos = false;

// If the user didn't specify a width or height, and it has not been set
// by the container, then we set it via the children.
if (isUndefined(node->layout.dimensions[dim[mainAxis]])) {
node->layout.dimensions[dim[mainAxis]] = fmaxf(
// We're missing the last padding at this point to get the final
// dimension
boundAxis(node, mainAxis, linesMainDim + getPaddingAndBorder(node, trailing[mainAxis])),
boundAxis(node, mainAxis, linesMainDim + getTrailingPaddingAndBorder(node, mainAxis)),
// We can never assign a width smaller than the padding and borders
getPaddingAndBorderAxis(node, mainAxis)
);

// Now that the width is defined, we should update the trailing
// positions for the children.
for (i = 0; i < node->children_count; ++i) {
setTrailingPosition(node, node->get_child(node->context, i), mainAxis);
}
needsMainTrailingPos = true;
}

if (isUndefined(node->layout.dimensions[dim[crossAxis]])) {
Expand All @@ -872,9 +946,27 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, css_direction
boundAxis(node, crossAxis, linesCrossDim + getPaddingAndBorderAxis(node, crossAxis)),
getPaddingAndBorderAxis(node, crossAxis)
);

needsCrossTrailingPos = true;
}

// <Loop E> 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 E> Calculate dimensions for absolutely positioned elements
// <Loop F> Calculate dimensions for absolutely positioned elements

for (i = 0; i < node->children_count; ++i) {
child = node->get_child(node->context, i);
Expand Down
8 changes: 5 additions & 3 deletions src/Layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ typedef enum {
CSS_TOP,
CSS_RIGHT,
CSS_BOTTOM,
CSS_START,
CSS_END,
CSS_POSITION_COUNT
} css_position_t;

Expand Down Expand Up @@ -106,7 +108,7 @@ typedef struct {
css_position_type_t position_type;
css_wrap_type_t flex_wrap;
float flex;
float margin[4];
float margin[6];
float position[4];
/**
* You should skip all the rules that contain negative values for the
Expand All @@ -118,8 +120,8 @@ typedef struct {
* {left: -5 ...}
* {left: 0 ...}
*/
float padding[4];
float border[4];
float padding[6];
float border[6];
float dimensions[2];
float minDimensions[2];
float maxDimensions[2];
Expand Down
Loading

0 comments on commit 03dfe7b

Please sign in to comment.