From 998fa1d6ba6da0ea04d21742bc43ad31789f657f Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Wed, 6 May 2015 15:14:57 +0800 Subject: [PATCH 01/14] [Issue facebook/css-layout#78]: Implemented alignContent ; --- src/JavaTranspiler.js | 1 + src/Layout.c | 110 +++++++++++++++++ src/Layout.h | 3 + src/Layout.js | 112 ++++++++++++++++++ .../src/com/facebook/csslayout/CSSNode.java | 2 + .../src/com/facebook/csslayout/CSSStyle.java | 1 + .../com/facebook/csslayout/LayoutEngine.java | 109 +++++++++++++++++ src/transpile.js | 8 ++ 8 files changed, 346 insertions(+) diff --git a/src/JavaTranspiler.js b/src/JavaTranspiler.js index 56ce90fd..a1bef154 100644 --- a/src/JavaTranspiler.js +++ b/src/JavaTranspiler.js @@ -103,6 +103,7 @@ var JavaTranspiler = { .replace('node.style.measure', 'node.measure') .replace(/\.children\.length/g, '.getChildCount()') .replace(/node.children\[i\]/g, 'node.getChildAt(i)') + .replace(/node.children\[ii\]/g, 'node.getChildAt(ii)') .replace(/fmaxf/g, 'Math.max') .replace(/\/\*\([^\/]+\*\/\n/g, '') // remove comments for other languages .replace(/var\/\*([^\/]+)\*\//g, '$1') diff --git a/src/Layout.c b/src/Layout.c index cbbb4c32..72b89936 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -35,6 +35,7 @@ static bool eq(float a, float b) { void init_css_node(css_node_t *node) { node->style.align_items = CSS_ALIGN_STRETCH; + node->style.align_content = CSS_ALIGN_STRETCH; // Some of the fields default to undefined and not 0 node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED; @@ -271,6 +272,10 @@ static css_justify_t getJustifyContent(css_node_t *node) { return node->style.justify_content; } +static css_align_t getAlignContent(css_node_t *node) { + return node->style.align_content; +} + static css_align_t getAlignItem(css_node_t *node, css_node_t *child) { if (child->style.align_self != CSS_ALIGN_AUTO) { return child->style.align_self; @@ -492,6 +497,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // We aggregate the total dimensions of the container in those two variables float linesCrossDim = 0; float linesMainDim = 0; + int linesCount = 0; while (endLine < node->children_count) { // Layout non flexible children and count children by type @@ -676,6 +682,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { for (i = startLine; i < endLine; ++i) { child = node->get_child(node->context, i); + child->line_index = linesCount; if (getPositionType(child) == CSS_POSITION_ABSOLUTE && isPosDefined(child, leading[mainAxis])) { @@ -770,9 +777,112 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { linesCrossDim += crossDim; linesMainDim = fmaxf(linesMainDim, mainDim); + linesCount += 1; startLine = endLine; } + // + // + // PIERRE: More than one line, we need to layout the crossAxis according to + // alignContent. + // + // Note that we could probably remove and handle the one line case + // here too, but for the moment this is safer since it won't interfere with + // previously working code. + // + // See specs: + // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm + // section 9.4 + // + if (linesCount > 1 && + (!isUndefined(node->layout.dimensions[dim[crossAxis]]))) + { + float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] - + getPaddingAndBorderAxis(node, crossAxis); + float remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim; + + float crossDimAdd = 0; + float currentLead = getPaddingAndBorder(node, leading[crossAxis]); + + css_align_t alignContent = getAlignContent(node); + if (alignContent == CSS_ALIGN_FLEX_END) { + currentLead += remainingCrossDim; + } + else if (alignContent == CSS_ALIGN_CENTER) { + currentLead += remainingCrossDim / 2; + } + else if (alignContent == CSS_ALIGN_STRETCH) { + if (nodeCrossAxisInnerSize > linesCrossDim) { + crossDimAdd = (remainingCrossDim / linesCount); + } + } + + // find the first node on the first line + for (i = 0; i < node->children_count; ) { + int startIndex = i; + int lineIndex = -1; + + // get the first child on the current line + { + child = node->get_child(node->context, i); + if (getPositionType(child) != CSS_POSITION_RELATIVE) { + ++i; + continue; + } + lineIndex = child->line_index; + } + + // compute the line's height and find the endIndex + float lineHeight = 0; + for (ii = startIndex; ii < node->children_count; ++ii) { + child = node->get_child(node->context, ii); + if (getPositionType(child) != CSS_POSITION_RELATIVE) { + continue; + } + if (child->line_index != lineIndex) { + break; + } + if (!isUndefined(child->layout.dimensions[dim[crossAxis]])) { + lineHeight = fmaxf(lineHeight,child->layout.dimensions[dim[crossAxis]] + + getMarginAxis(child,crossAxis)); + } + } + int endIndex = ii; + lineHeight += crossDimAdd; + + for (ii = startIndex; ii < endIndex; ++ii) { + child = node->get_child(node->context, ii); + if (getPositionType(child) != CSS_POSITION_RELATIVE) { + continue; + } + + css_align_t alignItem = getAlignItem(node, child); + float crossPosition = child->layout.position[pos[crossAxis]]; // preserve current position if someting goes wrong with alignItem? + if (alignItem == CSS_ALIGN_FLEX_START) { + crossPosition = currentLead + getMargin(child,leading[crossAxis]); + } + else if (alignItem == CSS_ALIGN_FLEX_END) { + crossPosition = currentLead + lineHeight - + getMargin(child,trailing[crossAxis]) - + child->layout.dimensions[dim[crossAxis]]; + } + else if (alignItem == CSS_ALIGN_CENTER) { + float childHeight = child->layout.dimensions[dim[crossAxis]]; + crossPosition = currentLead + ((lineHeight - childHeight)/2); + } + else if (alignItem == CSS_ALIGN_STRETCH) { + crossPosition = currentLead + getMargin(child,leading[crossAxis]); + // TODO: Correctly set the height of items with undefined (auto) + // crossAxis dimension. + } + child->layout.position[pos[crossAxis]] = crossPosition; + } + + currentLead += lineHeight; + i = endIndex; + } + } + // 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]])) { diff --git a/src/Layout.h b/src/Layout.h index a75232d6..7ad7d4c0 100644 --- a/src/Layout.h +++ b/src/Layout.h @@ -82,6 +82,7 @@ typedef struct { float last_parent_max_width; float last_dimensions[2]; float last_position[2]; + } css_layout_t; typedef struct { @@ -91,6 +92,7 @@ typedef struct { typedef struct { css_flex_direction_t flex_direction; css_justify_t justify_content; + css_align_t align_content; css_align_t align_items; css_align_t align_self; css_position_type_t position_type; @@ -119,6 +121,7 @@ typedef struct css_node { css_style_t style; css_layout_t layout; int children_count; + int line_index; css_dim_t (*measure)(void *context, float width); void (*print)(void *context); diff --git a/src/Layout.js b/src/Layout.js index fd39b4fb..b44cd4c0 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -144,6 +144,13 @@ var computeLayout = (function() { return 'flex-start'; } + function getAlignContent(node) { + if ('alignContent' in node.style) { + return node.style.alignContent; + } + return 'stretch'; + } + function getAlignItem(node, child) { if ('alignSelf' in child.style) { return child.style.alignSelf; @@ -376,6 +383,7 @@ var computeLayout = (function() { // We aggregate the total dimensions of the container in those two variables var/*float*/ linesCrossDim = 0; var/*float*/ linesMainDim = 0; + var/*int*/ linesCount = 0; while (endLine < node.children.length) { // Layout non flexible children and count children by type @@ -560,6 +568,7 @@ var computeLayout = (function() { for (i = startLine; i < endLine; ++i) { child = node.children[i]; + child.lineIndex = linesCount; if (getPositionType(child) === CSS_POSITION_ABSOLUTE && isPosDefined(child, leading[mainAxis])) { @@ -654,9 +663,112 @@ var computeLayout = (function() { linesCrossDim += crossDim; linesMainDim = fmaxf(linesMainDim, mainDim); + linesCount += 1; startLine = endLine; } + // + // + // PIERRE: More than one line, we need to layout the crossAxis according to + // alignContent. + // + // Note that we could probably remove and handle the one line case + // here too, but for the moment this is safer since it won't interfere with + // previously working code. + // + // See specs: + // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm + // section 9.4 + // + if (linesCount > 1 && + (!isUndefined(node.layout[dim[crossAxis]]))) + { + var/*float*/ nodeCrossAxisInnerSize = node.layout[dim[crossAxis]] - + getPaddingAndBorderAxis(node, crossAxis); + var/*float*/ remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim; + + var/*float*/ crossDimAdd = 0; + var/*float*/ currentLead = getPaddingAndBorder(node, leading[crossAxis]); + + var/*css_align_t*/ alignContent = getAlignContent(node); + if (alignContent == CSS_ALIGN_FLEX_END) { + currentLead += remainingCrossDim; + } + else if (alignContent == CSS_ALIGN_CENTER) { + currentLead += remainingCrossDim / 2; + } + else if (alignContent == CSS_ALIGN_STRETCH) { + if (nodeCrossAxisInnerSize > linesCrossDim) { + crossDimAdd = (remainingCrossDim / linesCount); + } + } + + // find the first node on the first line + for (i = 0; i < node.children.length; ) { + var/*int*/ startIndex = i; + var/*int*/ lineIndex = -1; + + // get the first child on the current line + { + child = node.children[i]; + if (getPositionType(child) != CSS_POSITION_RELATIVE) { + ++i; + continue; + } + lineIndex = child.lineIndex; + } + + // compute the line's height and find the endIndex + var/*float*/ lineHeight = 0; + for (ii = startIndex; ii < node.children.length; ++ii) { + child = node.children[ii]; + if (getPositionType(child) != CSS_POSITION_RELATIVE) { + continue; + } + if (child.lineIndex != lineIndex) { + break; + } + if (!isUndefined(child.layout[dim[crossAxis]])) { + lineHeight = fmaxf(lineHeight,child.layout[dim[crossAxis]] + + getMarginAxis(child,crossAxis)); + } + } + var/*int*/ endIndex = ii; + lineHeight += crossDimAdd; + + for (ii = startIndex; ii < endIndex; ++ii) { + child = node.children[ii]; + if (getPositionType(child) != CSS_POSITION_RELATIVE) { + continue; + } + + var/*css_align_t*/ alignItem = getAlignItem(node, child); + var/*float*/ crossPosition = child.layout[pos[crossAxis]]; // preserve current position if someting goes wrong with alignItem? + if (alignItem == CSS_ALIGN_FLEX_START) { + crossPosition = currentLead + getMargin(child,leading[crossAxis]); + } + else if (alignItem == CSS_ALIGN_FLEX_END) { + crossPosition = currentLead + lineHeight - + getMargin(child,trailing[crossAxis]) - + child.layout[dim[crossAxis]]; + } + else if (alignItem == CSS_ALIGN_CENTER) { + var/*float*/ childHeight = child.layout[dim[crossAxis]]; + crossPosition = currentLead + ((lineHeight - childHeight)/2); + } + else if (alignItem == CSS_ALIGN_STRETCH) { + crossPosition = currentLead + getMargin(child,leading[crossAxis]); + // TODO: Correctly set the height of items with undefined (auto) + // crossAxis dimension. + } + child.layout[pos[crossAxis]] = crossPosition; + } + + currentLead += lineHeight; + i = endIndex; + } + } + // 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]])) { diff --git a/src/java/src/com/facebook/csslayout/CSSNode.java b/src/java/src/com/facebook/csslayout/CSSNode.java index df8c3c63..0dfa6b54 100644 --- a/src/java/src/com/facebook/csslayout/CSSNode.java +++ b/src/java/src/com/facebook/csslayout/CSSNode.java @@ -58,6 +58,8 @@ public class CSSNode { /*package*/ final CSSLayout layout = new CSSLayout(); /*package*/ final CachedCSSLayout lastLayout = new CachedCSSLayout(); + public int lineIndex = 0; + // 4 is kinda arbitrary, but the default of 10 seems really high for an average View. private final ArrayList mChildren = new ArrayList(4); diff --git a/src/java/src/com/facebook/csslayout/CSSStyle.java b/src/java/src/com/facebook/csslayout/CSSStyle.java index 602de3ed..64c67fc2 100644 --- a/src/java/src/com/facebook/csslayout/CSSStyle.java +++ b/src/java/src/com/facebook/csslayout/CSSStyle.java @@ -15,6 +15,7 @@ public class CSSStyle { public CSSFlexDirection flexDirection = CSSFlexDirection.COLUMN; public CSSJustify justifyContent = CSSJustify.FLEX_START; + public CSSAlign alignContent = CSSAlign.STRETCH; public CSSAlign alignItems = CSSAlign.STRETCH; public CSSAlign alignSelf = CSSAlign.AUTO; public CSSPositionType positionType = CSSPositionType.RELATIVE; diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java index 01ee44d0..28d32c02 100644 --- a/src/java/src/com/facebook/csslayout/LayoutEngine.java +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -260,6 +260,10 @@ public class LayoutEngine { return node.style.alignItems; } + private static CSSAlign getAlignContent(CSSNode node) { + return node.style.alignContent; + } + private static CSSJustify getJustifyContent(CSSNode node) { return node.style.justifyContent; } @@ -430,6 +434,7 @@ public class LayoutEngine { // We aggregate the total dimensions of the container in those two variables float linesCrossDim = 0; float linesMainDim = 0; + int linesCount = 0; while (endLine < node.getChildCount()) { // Layout non flexible children and count children by type @@ -614,6 +619,7 @@ public class LayoutEngine { for (i = startLine; i < endLine; ++i) { child = node.getChildAt(i); + child.lineIndex = linesCount; if (getPositionType(child) == CSSPositionType.ABSOLUTE && isPosDefined(child, getLeading(mainAxis))) { @@ -708,9 +714,112 @@ public class LayoutEngine { linesCrossDim = linesCrossDim + crossDim; linesMainDim = Math.max(linesMainDim, mainDim); + linesCount = linesCount + 1; startLine = endLine; } + // + // + // PIERRE: More than one line, we need to layout the crossAxis according to + // alignContent. + // + // Note that we could probably remove and handle the one line case + // here too, but for the moment this is safer since it won't interfere with + // previously working code. + // + // See specs: + // http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#layout-algorithm + // section 9.4 + // + if (linesCount > 1 && + (!CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis))))) + { + float nodeCrossAxisInnerSize = getLayoutDimension(node, getDim(crossAxis)) - + getPaddingAndBorderAxis(node, crossAxis); + float remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim; + + float crossDimAdd = 0; + float currentLead = getPaddingAndBorder(node, getLeading(crossAxis)); + + CSSAlign alignContent = getAlignContent(node); + if (alignContent == CSSAlign.FLEX_END) { + currentLead = currentLead + remainingCrossDim; + } + else if (alignContent == CSSAlign.CENTER) { + currentLead = currentLead + remainingCrossDim / 2; + } + else if (alignContent == CSSAlign.STRETCH) { + if (nodeCrossAxisInnerSize > linesCrossDim) { + crossDimAdd = (remainingCrossDim / linesCount); + } + } + + // find the first node on the first line + for (i = 0; i < node.getChildCount(); ) { + int startIndex = i; + int lineIndex = -1; + + // get the first child on the current line + { + child = node.getChildAt(i); + if (getPositionType(child) != CSSPositionType.RELATIVE) { + ++i; + continue; + } + lineIndex = child.lineIndex; + } + + // compute the line's height and find the endIndex + float lineHeight = 0; + for (ii = startIndex; ii < node.getChildCount(); ++ii) { + child = node.getChildAt(ii); + if (getPositionType(child) != CSSPositionType.RELATIVE) { + continue; + } + if (child.lineIndex != lineIndex) { + break; + } + if (!CSSConstants.isUndefined(getLayoutDimension(child, getDim(crossAxis)))) { + lineHeight = Math.max(lineHeight,getLayoutDimension(child, getDim(crossAxis)) + + getMarginAxis(child,crossAxis)); + } + } + int endIndex = ii; + lineHeight = lineHeight + crossDimAdd; + + for (ii = startIndex; ii < endIndex; ++ii) { + child = node.getChildAt(ii); + if (getPositionType(child) != CSSPositionType.RELATIVE) { + continue; + } + + CSSAlign alignItem = getAlignItem(node, child); + float crossPosition = getLayoutPosition(child, getPos(crossAxis)); // preserve current position if someting goes wrong with alignItem? + if (alignItem == CSSAlign.FLEX_START) { + crossPosition = currentLead + getMargin(child,getLeading(crossAxis)); + } + else if (alignItem == CSSAlign.FLEX_END) { + crossPosition = currentLead + lineHeight - + getMargin(child,getTrailing(crossAxis)) - + getLayoutDimension(child, getDim(crossAxis)); + } + else if (alignItem == CSSAlign.CENTER) { + float childHeight = getLayoutDimension(child, getDim(crossAxis)); + crossPosition = currentLead + ((lineHeight - childHeight)/2); + } + else if (alignItem == CSSAlign.STRETCH) { + crossPosition = currentLead + getMargin(child,getLeading(crossAxis)); + // TODO: Correctly set the height of items with undefined (auto) + // crossAxis dimension. + } + setLayoutPosition(child, getPos(crossAxis), crossPosition); + } + + currentLead = currentLead + lineHeight; + i = endIndex; + } + } + // 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)))) { diff --git a/src/transpile.js b/src/transpile.js index 193631dc..b12c07e8 100644 --- a/src/transpile.js +++ b/src/transpile.js @@ -122,6 +122,12 @@ function printLayout(test) { 'space-between': 'CSS_JUSTIFY_SPACE_BETWEEN', 'space-around': 'CSS_JUSTIFY_SPACE_AROUND' }); + addEnum(node, 'alignContent', 'align_content', { + 'flex-start': 'CSS_ALIGN_FLEX_START', + 'center': 'CSS_ALIGN_CENTER', + 'flex-end': 'CSS_ALIGN_FLEX_END', + 'stretch': 'CSS_ALIGN_STRETCH' + }); addEnum(node, 'alignItems', 'align_items', { 'flex-start': 'CSS_ALIGN_FLEX_START', 'center': 'CSS_ALIGN_CENTER', @@ -231,11 +237,13 @@ function transpileAnnotatedJStoC(jsCode) { .replace(/\.maxHeight/g, '.maxDimensions[CSS_HEIGHT]') .replace(/\.minWidth/g, '.minDimensions[CSS_WIDTH]') .replace(/\.minHeight/g, '.minDimensions[CSS_HEIGHT]') + .replace(/\.lineIndex/g, '.line_index') .replace(/layout\[dim/g, 'layout.dimensions[dim') .replace(/layout\[pos/g, 'layout.position[pos') .replace(/layout\[leading/g, 'layout.position[leading') .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)') .replace(/node\./g, 'node->') .replace(/child\./g, 'child->') .replace(/parent\./g, 'parent->') From f4226d3ff509be6059574fd88f57304e0a030ab6 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Fri, 8 May 2015 14:51:05 +0800 Subject: [PATCH 02/14] [src/Layout-test-utils.js]: Added testMeasurePrecision and inplaceRoundNumbersInObject which snap the numbers to pixels so that we don't have to re-adjust for each browser version (Chrome 42 changed their computation, it can output floating point values for dom elements) ; --- src/Layout-test-utils.js | 41 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index 3e1efaaa..f58dcf67 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -10,6 +10,18 @@ var layoutTestUtils = (function() { + // + // Sets the test cases precision, by default set to 1.0, aka pixel precision + // (assuming the browser does pixel snapping - and that we're ok with being + // 'only' pixel perfect). + // + // Set it to '10' for .1 precision, etc... in theory the browser is doing + // 'pixel' snapping so 1.0 should do, the code is left for clarity... + // + // Set it to undefined to disable and use full precision. + // + var testMeasurePrecision = 1.0; + if (typeof jasmine !== 'undefined') { jasmine.matchersUtil.buildFailureMessage = function () { var args = Array.prototype.slice.call(arguments, 0), @@ -227,11 +239,33 @@ var layoutTestUtils = (function() { return layout; } + function inplaceRoundNumbersInObject(aObj) { + if (!testMeasurePrecision) // undefined/0, disables rounding + return; + + for (var key in aObj) { + if (!aObj.hasOwnProperty(key)) + continue; + var val = aObj[key]; + switch (typeof(val)) { + case 'number': { + aObj[key] = Math.floor((val*testMeasurePrecision)+0.5)/testMeasurePrecision; + break; + } + case 'object': { + inplaceRoundNumbersInObject(val); + break; + } + } + } + } + function nameLayout(name, layout) { var namedLayout = {name: name}; for (var key in layout) { namedLayout[key] = layout[key]; } + inplaceRoundNumbersInObject(namedLayout); return namedLayout; } @@ -363,7 +397,7 @@ var layoutTestUtils = (function() { smallWidth: 34.671875, smallHeight: 18, bigWidth: 172.421875, - bigHeight: 36, + bigHeight: 37, bigMinWidth: 100.4375 }; @@ -380,6 +414,11 @@ var layoutTestUtils = (function() { }; } + // round the text sizes so that we dont have to update it for every browser + // update, assumes we're ok with pixel precision + inplaceRoundNumbersInObject(preDefinedTextSizes); + inplaceRoundNumbersInObject(textSizes); + return { texts: texts, textSizes: textSizes, From 68d029e4600a29a7ba01a9d864396fb26bb70497 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Fri, 8 May 2015 14:52:11 +0800 Subject: [PATCH 03/14] [src/__tests__/Layout-test.js]: Added 16 test cases for each alignContent / alignItems combination - also includes alignSelf testing within the test data ; --- src/Layout-test-utils.js | 5 +++ src/Layout.js | 2 +- src/__tests__/Layout-test.js | 74 ++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index f58dcf67..8848e770 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -429,6 +429,11 @@ var layoutTestUtils = (function() { testNamedLayout('expected-dom', expectedLayout, domLayout); testNamedLayout('layout-dom', layout, domLayout); }, + testLayoutAgainstDomOnly: function(node, expectedLayout) { + var layout = computeCSSLayout(node); + var domLayout = computeDOMLayout(node); + testNamedLayout('layout-dom', layout, domLayout); + }, testFillNodes: testFillNodes, testExtractNodes: testExtractNodes, testRandomLayout: function(node) { diff --git a/src/Layout.js b/src/Layout.js index b44cd4c0..8172ffe2 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -22,7 +22,7 @@ var computeLayout = (function() { var CSS_ALIGN_FLEX_START = 'flex-start'; var CSS_ALIGN_CENTER = 'center'; - // var CSS_ALIGN_FLEX_END = 'flex-end'; + var CSS_ALIGN_FLEX_END = 'flex-end'; var CSS_ALIGN_STRETCH = 'stretch'; var CSS_POSITION_RELATIVE = 'relative'; diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index f0bb41e4..6ba84cdb 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -9,6 +9,7 @@ /* globals layoutTestUtils */ var testLayout = layoutTestUtils.testLayout; +var testLayoutAgainstDomOnly = layoutTestUtils.testLayoutAgainstDomOnly; var testFillNodes = layoutTestUtils.testFillNodes; var testExtractNodes = layoutTestUtils.testExtractNodes; var text = layoutTestUtils.text; @@ -1586,5 +1587,78 @@ describe('Layout', function() { ); }); +}); + +describe('Layout alignContent', function() { + + var alignContentData = { + style: {width: 300, height: 380, flexDirection: 'row', flexWrap: 'wrap'}, + children: [ + /* 0 */ { style: {width: 50, height: 50, margin: 10} }, + /* 1 */ { style: {width: 50, height: 50, margin: 10} }, + /* 2 */ { style: {width: 50, height: 50, margin: 10} }, + /* 3 */ { style: {width: 50, height: 50, margin: 10} }, + /* 4 */ { style: {width: 50, height: 100, margin: 10} }, + /* 5 */ { style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'} }, + /* 6 */ { style: {width: 50, height: 50, margin: 10} }, + /* 7 */ { style: {width: 50, height: 100, margin: 10} }, + /* 8 */ { style: {width: 50, height: 50, margin: 10} }, + /* 9 */ { style: {width: 50, height: 50, margin: 10} }, + /* 10 */ { style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start' } }, + /* 11 */ { style: {width: 50, height: 50, margin: 10} }, + /* 12 */ { style: {width: 50, height: 50, margin: 10} }, + /* 13 */ { style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'} }, + /* 14 */ { style: {width: 50, height: 50, margin: 10} }, + ], + }; + + it('should layout with alignContent: stretch, and alignItems: flex-start', function() { + testLayout( + alignContentData, + { width:300,height:380,top:0,left:0, children:[ + {width:50,height:50,top:10,left:10}, + {width:50,height:50,top:10,left:80}, + {width:50,height:50,top:10,left:150}, + {width:50,height:50,top:10,left:220}, + {width:50,height:100,top:92.5,left:10}, + {width:50,height:50,top:92.5,left:80}, + {width:50,height:50,top:92.5,left:150}, + {width:50,height:100,top:92.5,left:220}, + {width:50,height:50,top:225,left:10}, + {width:50,height:50,top:225,left:80}, + {width:50,height:50,top:225,left:150}, + {width:50,height:50,top:225,left:220}, + {width:50,height:50,top:307.5,left:10}, + {width:50,height:50,top:307.5,left:80}, + {width:50,height:50,top:307.5,left:150} + ]} + ); + }); + + function testAlignContent(aAlignContent, aAlignItems) { + it('should layout with alignContent: '+aAlignContent+', and alignItems: '+aAlignItems, function() { + testLayoutAgainstDomOnly(alignContentData); + }); + } + + // testAlignContent('stretch', 'flex-start'); // above with expected value data + testAlignContent('stretch', 'center'); + testAlignContent('stretch', 'flex-end'); + testAlignContent('stretch', 'stretch'); + + testAlignContent('flex-start', 'flex-start'); + testAlignContent('flex-start', 'center'); + testAlignContent('flex-start', 'flex-end'); + testAlignContent('flex-start', 'stretch'); + + testAlignContent('center', 'flex-start'); + testAlignContent('center', 'center'); + testAlignContent('center', 'flex-end'); + testAlignContent('center', 'stretch'); + + testAlignContent('flex-end', 'flex-start'); + testAlignContent('flex-end', 'center'); + testAlignContent('flex-end', 'flex-end'); + testAlignContent('flex-end', 'stretch'); }); From 15a8430be9264d3d7f08706552a2b297309f731e Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Fri, 8 May 2015 15:10:28 +0800 Subject: [PATCH 04/14] [src/Layout-test-utils.js]: Added inplaceRoundNumbersInObject to testRandomLayout so that much less random tests fail ; Moved inplaceRoundNumbersInObject in the main functions instead of having it in nameLayout ; --- src/Layout-test-utils.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index 8848e770..4cf21d37 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -265,7 +265,6 @@ var layoutTestUtils = (function() { for (var key in layout) { namedLayout[key] = layout[key]; } - inplaceRoundNumbersInObject(namedLayout); return namedLayout; } @@ -426,19 +425,28 @@ var layoutTestUtils = (function() { testLayout: function(node, expectedLayout) { var layout = computeCSSLayout(node); var domLayout = computeDOMLayout(node); + inplaceRoundNumbersInObject(layout); + inplaceRoundNumbersInObject(domLayout); + inplaceRoundNumbersInObject(expectedLayout); testNamedLayout('expected-dom', expectedLayout, domLayout); testNamedLayout('layout-dom', layout, domLayout); }, testLayoutAgainstDomOnly: function(node, expectedLayout) { var layout = computeCSSLayout(node); var domLayout = computeDOMLayout(node); + inplaceRoundNumbersInObject(layout); + inplaceRoundNumbersInObject(domLayout); testNamedLayout('layout-dom', layout, domLayout); }, testFillNodes: testFillNodes, testExtractNodes: testExtractNodes, testRandomLayout: function(node) { - expect({node: node, layout: computeCSSLayout(node)}) - .toEqual({node: node, layout: computeDOMLayout(node)}); + var layout = computeCSSLayout(node); + var domLayout = computeDOMLayout(node); + inplaceRoundNumbersInObject(layout); + inplaceRoundNumbersInObject(domLayout); + expect({node: node, layout: layout}) + .toEqual({node: node, layout: domLayout}); }, testsFinished: function() { console.log('tests finished!'); From 7679ed77d969dd1f9977eb4d762d656fda17be7f Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Fri, 8 May 2015 15:12:17 +0800 Subject: [PATCH 05/14] Updated generated C & Java code ; --- src/Layout-test-utils.c | 8 ++-- src/__tests__/Layout-test.c | 40 +++++++++---------- .../facebook/csslayout/LayoutEngineTest.java | 40 +++++++++---------- .../com/facebook/csslayout/TestConstants.java | 8 ++-- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/Layout-test-utils.c b/src/Layout-test-utils.c index de88514a..6a28f1f4 100644 --- a/src/Layout-test-utils.c +++ b/src/Layout-test-utils.c @@ -11,11 +11,11 @@ #include /** START_GENERATED **/ -#define SMALL_WIDTH 34.671875 +#define SMALL_WIDTH 35 #define SMALL_HEIGHT 18 -#define BIG_WIDTH 172.421875 -#define BIG_HEIGHT 36 -#define BIG_MIN_WIDTH 100.4375 +#define BIG_WIDTH 172 +#define BIG_HEIGHT 37 +#define BIG_MIN_WIDTH 100 #define SMALL_TEXT "small" #define LONG_TEXT "loooooooooong with space" /** END_GENERATED **/ diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c index c1bb8ff5..16e7ea65 100644 --- a/src/__tests__/Layout-test.c +++ b/src/__tests__/Layout-test.c @@ -2483,7 +2483,7 @@ int main() css_node_t *node_0 = root_layout; node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_LEFT] = 0; - node_0->layout.dimensions[CSS_WIDTH] = 34.671875; + node_0->layout.dimensions[CSS_WIDTH] = 35; node_0->layout.dimensions[CSS_HEIGHT] = 18; } @@ -2524,7 +2524,7 @@ int main() css_node_t *node_0 = root_layout; node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_LEFT] = 0; - node_0->layout.dimensions[CSS_WIDTH] = 172.421875; + node_0->layout.dimensions[CSS_WIDTH] = 172; node_0->layout.dimensions[CSS_HEIGHT] = 18; } @@ -2658,7 +2658,7 @@ int main() node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_LEFT] = 0; node_0->layout.dimensions[CSS_WIDTH] = 130; - node_0->layout.dimensions[CSS_HEIGHT] = 36; + node_0->layout.dimensions[CSS_HEIGHT] = 37; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -2666,7 +2666,7 @@ int main() node_1->layout.position[CSS_TOP] = 0; node_1->layout.position[CSS_LEFT] = 0; node_1->layout.dimensions[CSS_WIDTH] = 130; - node_1->layout.dimensions[CSS_HEIGHT] = 36; + node_1->layout.dimensions[CSS_HEIGHT] = 37; init_css_node_children(node_1, 1); { css_node_t *node_2; @@ -2674,7 +2674,7 @@ int main() node_2->layout.position[CSS_TOP] = 0; node_2->layout.position[CSS_LEFT] = 0; node_2->layout.dimensions[CSS_WIDTH] = 130; - node_2->layout.dimensions[CSS_HEIGHT] = 36; + node_2->layout.dimensions[CSS_HEIGHT] = 37; } } } @@ -2710,7 +2710,7 @@ int main() node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_LEFT] = 0; node_0->layout.dimensions[CSS_WIDTH] = 200; - node_0->layout.dimensions[CSS_HEIGHT] = 36; + node_0->layout.dimensions[CSS_HEIGHT] = 37; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -2718,7 +2718,7 @@ int main() node_1->layout.position[CSS_TOP] = 0; node_1->layout.position[CSS_LEFT] = 0; node_1->layout.dimensions[CSS_WIDTH] = 200; - node_1->layout.dimensions[CSS_HEIGHT] = 36; + node_1->layout.dimensions[CSS_HEIGHT] = 37; init_css_node_children(node_1, 1); { css_node_t *node_2; @@ -2726,7 +2726,7 @@ int main() node_2->layout.position[CSS_TOP] = 0; node_2->layout.position[CSS_LEFT] = 0; node_2->layout.dimensions[CSS_WIDTH] = 130; - node_2->layout.dimensions[CSS_HEIGHT] = 36; + node_2->layout.dimensions[CSS_HEIGHT] = 37; } } } @@ -2756,15 +2756,15 @@ int main() node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_LEFT] = 0; node_0->layout.dimensions[CSS_WIDTH] = 100; - node_0->layout.dimensions[CSS_HEIGHT] = 36; + node_0->layout.dimensions[CSS_HEIGHT] = 37; init_css_node_children(node_0, 1); { css_node_t *node_1; node_1 = node_0->get_child(node_0->context, 0); node_1->layout.position[CSS_TOP] = 0; node_1->layout.position[CSS_LEFT] = 0; - node_1->layout.dimensions[CSS_WIDTH] = 100.4375; - node_1->layout.dimensions[CSS_HEIGHT] = 36; + node_1->layout.dimensions[CSS_WIDTH] = 100; + node_1->layout.dimensions[CSS_HEIGHT] = 37; } } @@ -2806,23 +2806,23 @@ int main() node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_LEFT] = 0; node_0->layout.dimensions[CSS_WIDTH] = 100; - node_0->layout.dimensions[CSS_HEIGHT] = 76; + node_0->layout.dimensions[CSS_HEIGHT] = 77; init_css_node_children(node_0, 1); { css_node_t *node_1; node_1 = node_0->get_child(node_0->context, 0); node_1->layout.position[CSS_TOP] = 20; node_1->layout.position[CSS_LEFT] = 20; - node_1->layout.dimensions[CSS_WIDTH] = 100.4375; - node_1->layout.dimensions[CSS_HEIGHT] = 36; + node_1->layout.dimensions[CSS_WIDTH] = 100; + node_1->layout.dimensions[CSS_HEIGHT] = 37; init_css_node_children(node_1, 1); { css_node_t *node_2; node_2 = node_1->get_child(node_1->context, 0); node_2->layout.position[CSS_TOP] = 0; node_2->layout.position[CSS_LEFT] = 0; - node_2->layout.dimensions[CSS_WIDTH] = 100.4375; - node_2->layout.dimensions[CSS_HEIGHT] = 36; + node_2->layout.dimensions[CSS_WIDTH] = 100; + node_2->layout.dimensions[CSS_HEIGHT] = 37; } } } @@ -2952,7 +2952,7 @@ int main() node_2 = node_1->get_child(node_1->context, 0); node_2->layout.position[CSS_TOP] = 20; node_2->layout.position[CSS_LEFT] = 20; - node_2->layout.dimensions[CSS_WIDTH] = 172.421875; + node_2->layout.dimensions[CSS_WIDTH] = 172; node_2->layout.dimensions[CSS_HEIGHT] = 18; } } @@ -2990,7 +2990,7 @@ int main() node_0->layout.position[CSS_TOP] = 0; node_0->layout.position[CSS_LEFT] = 0; node_0->layout.dimensions[CSS_WIDTH] = 200; - node_0->layout.dimensions[CSS_HEIGHT] = 76; + node_0->layout.dimensions[CSS_HEIGHT] = 77; init_css_node_children(node_0, 1); { css_node_t *node_1; @@ -2998,7 +2998,7 @@ int main() node_1->layout.position[CSS_TOP] = 0; node_1->layout.position[CSS_LEFT] = 0; node_1->layout.dimensions[CSS_WIDTH] = 200; - node_1->layout.dimensions[CSS_HEIGHT] = 76; + node_1->layout.dimensions[CSS_HEIGHT] = 77; init_css_node_children(node_1, 1); { css_node_t *node_2; @@ -3006,7 +3006,7 @@ int main() node_2->layout.position[CSS_TOP] = 20; node_2->layout.position[CSS_LEFT] = 20; node_2->layout.dimensions[CSS_WIDTH] = 160; - node_2->layout.dimensions[CSS_HEIGHT] = 36; + node_2->layout.dimensions[CSS_HEIGHT] = 37; } } } diff --git a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java index ce0e890c..296fa608 100644 --- a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -2686,7 +2686,7 @@ public class LayoutEngineTest { TestCSSNode node_0 = root_layout; node_0.layout.y = 0; node_0.layout.x = 0; - node_0.layout.width = 34.671875f; + node_0.layout.width = 35; node_0.layout.height = 18; } @@ -2731,7 +2731,7 @@ public class LayoutEngineTest { TestCSSNode node_0 = root_layout; node_0.layout.y = 0; node_0.layout.x = 0; - node_0.layout.width = 172.421875f; + node_0.layout.width = 172; node_0.layout.height = 18; } @@ -2871,7 +2871,7 @@ public class LayoutEngineTest { node_0.layout.y = 0; node_0.layout.x = 0; node_0.layout.width = 130; - node_0.layout.height = 36; + node_0.layout.height = 37; addChildren(node_0, 1); { TestCSSNode node_1; @@ -2879,7 +2879,7 @@ public class LayoutEngineTest { node_1.layout.y = 0; node_1.layout.x = 0; node_1.layout.width = 130; - node_1.layout.height = 36; + node_1.layout.height = 37; addChildren(node_1, 1); { TestCSSNode node_2; @@ -2887,7 +2887,7 @@ public class LayoutEngineTest { node_2.layout.y = 0; node_2.layout.x = 0; node_2.layout.width = 130; - node_2.layout.height = 36; + node_2.layout.height = 37; } } } @@ -2925,7 +2925,7 @@ public class LayoutEngineTest { node_0.layout.y = 0; node_0.layout.x = 0; node_0.layout.width = 200; - node_0.layout.height = 36; + node_0.layout.height = 37; addChildren(node_0, 1); { TestCSSNode node_1; @@ -2933,7 +2933,7 @@ public class LayoutEngineTest { node_1.layout.y = 0; node_1.layout.x = 0; node_1.layout.width = 200; - node_1.layout.height = 36; + node_1.layout.height = 37; addChildren(node_1, 1); { TestCSSNode node_2; @@ -2941,7 +2941,7 @@ public class LayoutEngineTest { node_2.layout.y = 0; node_2.layout.x = 0; node_2.layout.width = 130; - node_2.layout.height = 36; + node_2.layout.height = 37; } } } @@ -2973,15 +2973,15 @@ public class LayoutEngineTest { node_0.layout.y = 0; node_0.layout.x = 0; node_0.layout.width = 100; - node_0.layout.height = 36; + node_0.layout.height = 37; addChildren(node_0, 1); { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.layout.y = 0; node_1.layout.x = 0; - node_1.layout.width = 100.4375f; - node_1.layout.height = 36; + node_1.layout.width = 100; + node_1.layout.height = 37; } } @@ -3025,23 +3025,23 @@ public class LayoutEngineTest { node_0.layout.y = 0; node_0.layout.x = 0; node_0.layout.width = 100; - node_0.layout.height = 76; + node_0.layout.height = 77; addChildren(node_0, 1); { TestCSSNode node_1; node_1 = node_0.getChildAt(0); node_1.layout.y = 20; node_1.layout.x = 20; - node_1.layout.width = 100.4375f; - node_1.layout.height = 36; + node_1.layout.width = 100; + node_1.layout.height = 37; addChildren(node_1, 1); { TestCSSNode node_2; node_2 = node_1.getChildAt(0); node_2.layout.y = 0; node_2.layout.x = 0; - node_2.layout.width = 100.4375f; - node_2.layout.height = 36; + node_2.layout.width = 100; + node_2.layout.height = 37; } } } @@ -3177,7 +3177,7 @@ public class LayoutEngineTest { node_2 = node_1.getChildAt(0); node_2.layout.y = 20; node_2.layout.x = 20; - node_2.layout.width = 172.421875f; + node_2.layout.width = 172; node_2.layout.height = 18; } } @@ -3217,7 +3217,7 @@ public class LayoutEngineTest { node_0.layout.y = 0; node_0.layout.x = 0; node_0.layout.width = 200; - node_0.layout.height = 76; + node_0.layout.height = 77; addChildren(node_0, 1); { TestCSSNode node_1; @@ -3225,7 +3225,7 @@ public class LayoutEngineTest { node_1.layout.y = 0; node_1.layout.x = 0; node_1.layout.width = 200; - node_1.layout.height = 76; + node_1.layout.height = 77; addChildren(node_1, 1); { TestCSSNode node_2; @@ -3233,7 +3233,7 @@ public class LayoutEngineTest { node_2.layout.y = 20; node_2.layout.x = 20; node_2.layout.width = 160; - node_2.layout.height = 36; + node_2.layout.height = 37; } } } diff --git a/src/java/tests/com/facebook/csslayout/TestConstants.java b/src/java/tests/com/facebook/csslayout/TestConstants.java index 3332e1e6..6ca0d1b3 100644 --- a/src/java/tests/com/facebook/csslayout/TestConstants.java +++ b/src/java/tests/com/facebook/csslayout/TestConstants.java @@ -14,11 +14,11 @@ package com.facebook.csslayout; public class TestConstants { /** START_GENERATED **/ - public static final float SMALL_WIDTH = 34.671875f; + public static final float SMALL_WIDTH = 35f; public static final float SMALL_HEIGHT = 18f; - public static final float BIG_WIDTH = 172.421875f; - public static final float BIG_HEIGHT = 36f; - public static final float BIG_MIN_WIDTH = 100.4375f; + public static final float BIG_WIDTH = 172f; + public static final float BIG_HEIGHT = 37f; + public static final float BIG_MIN_WIDTH = 100f; public static final String SMALL_TEXT = "small"; public static final String LONG_TEXT = "loooooooooong with space"; /** END_GENERATED **/ From 9ca681ff28f253307ff10411cdcea1716a491e0b Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Fri, 8 May 2015 15:18:38 +0800 Subject: [PATCH 06/14] [src/__tests__/Layout-random-test.js]: Added alignContent in the list of random permutations ; --- src/Layout-test-utils.js | 3 +++ src/__tests__/Layout-random-test.js | 1 + 2 files changed, 4 insertions(+) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index 4cf21d37..3861c149 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -201,6 +201,7 @@ var layoutTestUtils = (function() { transfer(div, node, 'justifyContent'); transfer(div, node, 'alignSelf'); transfer(div, node, 'alignItems'); + transfer(div, node, 'alignContent'); transfer(div, node, 'position'); parent.appendChild(div); (node.children || []).forEach(function(child) { @@ -370,11 +371,13 @@ var layoutTestUtils = (function() { div.style.display = 'flex'; div.style.flexDirection = 'column'; div.style.alignItems = 'flex-start'; + div.style.alignContent = 'stretch'; var span = document.createElement('span'); span.style.display = 'flex'; span.style.flexDirection = 'column'; span.style.alignItems = 'flex-start'; + span.style.alignContent = 'stretch'; span.innerText = text; div.appendChild(span); diff --git a/src/__tests__/Layout-random-test.js b/src/__tests__/Layout-random-test.js index e552cdbe..e974ef19 100644 --- a/src/__tests__/Layout-random-test.js +++ b/src/__tests__/Layout-random-test.js @@ -65,6 +65,7 @@ describe('Random layout', function() { randEnum(node, 0.5, 'justifyContent', ['flex-start', 'center', 'flex-end', 'space-between', 'space-around']); randEnum(node, 0.5, 'alignItems', ['flex-start', 'center', 'flex-end', 'stretch']); randEnum(node, 0.5, 'alignSelf', ['flex-start', 'center', 'flex-end', 'stretch']); + randEnum(node, 0.5, 'alignContent', ['flex-start', 'center', 'flex-end', 'stretch']); randEnum(node, 0.5, 'position', ['relative', 'absolute']); randEnum(node, 0.5, 'flexWrap', ['nowrap', 'wrap']); //randEnum(node, 0.5, 'measure', [text(texts.small), text(texts.big)]); From cc5f772bff3c9ed4fb12829c90c839e851611fa6 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 11:46:28 +0800 Subject: [PATCH 07/14] Style fixes ; --- src/Layout-test-utils.js | 24 +++--- src/Layout.c | 67 +++++++--------- src/Layout.js | 77 ++++++++----------- src/__tests__/Layout-test.js | 66 ++++++++-------- .../com/facebook/csslayout/LayoutEngine.java | 67 +++++++--------- 5 files changed, 134 insertions(+), 167 deletions(-) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index 3861c149..96df2fcf 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -240,23 +240,23 @@ var layoutTestUtils = (function() { return layout; } - function inplaceRoundNumbersInObject(aObj) { - if (!testMeasurePrecision) // undefined/0, disables rounding + function inplaceRoundNumbersInObject(obj) { + if (!testMeasurePrecision) { + // undefined/0, disables rounding return; + } - for (var key in aObj) { - if (!aObj.hasOwnProperty(key)) + for (var key in obj) { + if (!obj.hasOwnProperty(key)) { continue; - var val = aObj[key]; - switch (typeof(val)) { - case 'number': { - aObj[key] = Math.floor((val*testMeasurePrecision)+0.5)/testMeasurePrecision; - break; } - case 'object': { + + var val = obj[key]; + if (typeof val === 'number') { + obj[key] = Math.floor((val * testMeasurePrecision) + 0.5) /testMeasurePrecision; + } + else if (typeof val === 'object') { inplaceRoundNumbersInObject(val); - break; - } } } } diff --git a/src/Layout.c b/src/Layout.c index 72b89936..de0788f9 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -781,10 +781,10 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { startLine = endLine; } - // + // // - // PIERRE: More than one line, we need to layout the crossAxis according to - // alignContent. + // Note(prenaux): More than one line, we need to layout the crossAxis + // according to alignContent. // // Note that we could probably remove and handle the one line case // here too, but for the moment this is safer since it won't interfere with @@ -795,25 +795,22 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { // section 9.4 // if (linesCount > 1 && - (!isUndefined(node->layout.dimensions[dim[crossAxis]]))) - { + !isUndefined(node->layout.dimensions[dim[crossAxis]])) { float nodeCrossAxisInnerSize = node->layout.dimensions[dim[crossAxis]] - getPaddingAndBorderAxis(node, crossAxis); float remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim; - float crossDimAdd = 0; + float crossDimLead = 0; float currentLead = getPaddingAndBorder(node, leading[crossAxis]); css_align_t alignContent = getAlignContent(node); if (alignContent == CSS_ALIGN_FLEX_END) { currentLead += remainingCrossDim; - } - else if (alignContent == CSS_ALIGN_CENTER) { + } else if (alignContent == CSS_ALIGN_CENTER) { currentLead += remainingCrossDim / 2; - } - else if (alignContent == CSS_ALIGN_STRETCH) { + } else if (alignContent == CSS_ALIGN_STRETCH) { if (nodeCrossAxisInnerSize > linesCrossDim) { - crossDimAdd = (remainingCrossDim / linesCount); + crossDimLead = (remainingCrossDim / linesCount); } } @@ -823,14 +820,12 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { int lineIndex = -1; // get the first child on the current line - { - child = node->get_child(node->context, i); - if (getPositionType(child) != CSS_POSITION_RELATIVE) { - ++i; - continue; - } - lineIndex = child->line_index; + child = node->get_child(node->context, i); + if (getPositionType(child) != CSS_POSITION_RELATIVE) { + ++i; + continue; } + lineIndex = child->line_index; // compute the line's height and find the endIndex float lineHeight = 0; @@ -843,12 +838,14 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { break; } if (!isUndefined(child->layout.dimensions[dim[crossAxis]])) { - lineHeight = fmaxf(lineHeight,child->layout.dimensions[dim[crossAxis]] + - getMarginAxis(child,crossAxis)); + lineHeight = fmaxf( + lineHeight, + child->layout.dimensions[dim[crossAxis]] + getMarginAxis(child, crossAxis) + ); } } int endIndex = ii; - lineHeight += crossDimAdd; + lineHeight += crossDimLead; for (ii = startIndex; ii < endIndex; ++ii) { child = node->get_child(node->context, ii); @@ -857,25 +854,18 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { } css_align_t alignItem = getAlignItem(node, child); - float crossPosition = child->layout.position[pos[crossAxis]]; // preserve current position if someting goes wrong with alignItem? if (alignItem == CSS_ALIGN_FLEX_START) { - crossPosition = currentLead + getMargin(child,leading[crossAxis]); - } - else if (alignItem == CSS_ALIGN_FLEX_END) { - crossPosition = currentLead + lineHeight - - getMargin(child,trailing[crossAxis]) - - child->layout.dimensions[dim[crossAxis]]; - } - else if (alignItem == CSS_ALIGN_CENTER) { + 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) { float childHeight = child->layout.dimensions[dim[crossAxis]]; - crossPosition = currentLead + ((lineHeight - childHeight)/2); + 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]); + // TODO(prenaux): Correctly set the height of items with undefined + // (auto) crossAxis dimension. } - else if (alignItem == CSS_ALIGN_STRETCH) { - crossPosition = currentLead + getMargin(child,leading[crossAxis]); - // TODO: Correctly set the height of items with undefined (auto) - // crossAxis dimension. - } - child->layout.position[pos[crossAxis]] = crossPosition; } currentLead += lineHeight; @@ -905,8 +895,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { ); } - // Calculate dimensions for absolutely positioned elements - + // Calculate dimensions for absolutely positioned elements for (i = 0; i < node->children_count; ++i) { child = node->get_child(node->context, i); if (getPositionType(child) == CSS_POSITION_ABSOLUTE) { diff --git a/src/Layout.js b/src/Layout.js index 8172ffe2..42c3657d 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -667,10 +667,10 @@ var computeLayout = (function() { startLine = endLine; } - // + // // - // PIERRE: More than one line, we need to layout the crossAxis according to - // alignContent. + // Note(prenaux): More than one line, we need to layout the crossAxis + // according to alignContent. // // Note that we could probably remove and handle the one line case // here too, but for the moment this is safer since it won't interfere with @@ -681,25 +681,22 @@ var computeLayout = (function() { // section 9.4 // if (linesCount > 1 && - (!isUndefined(node.layout[dim[crossAxis]]))) - { + !isUndefined(node.layout[dim[crossAxis]])) { var/*float*/ nodeCrossAxisInnerSize = node.layout[dim[crossAxis]] - getPaddingAndBorderAxis(node, crossAxis); var/*float*/ remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim; - var/*float*/ crossDimAdd = 0; + var/*float*/ crossDimLead = 0; var/*float*/ currentLead = getPaddingAndBorder(node, leading[crossAxis]); var/*css_align_t*/ alignContent = getAlignContent(node); - if (alignContent == CSS_ALIGN_FLEX_END) { + if (alignContent === CSS_ALIGN_FLEX_END) { currentLead += remainingCrossDim; - } - else if (alignContent == CSS_ALIGN_CENTER) { + } else if (alignContent === CSS_ALIGN_CENTER) { currentLead += remainingCrossDim / 2; - } - else if (alignContent == CSS_ALIGN_STRETCH) { + } else if (alignContent === CSS_ALIGN_STRETCH) { if (nodeCrossAxisInnerSize > linesCrossDim) { - crossDimAdd = (remainingCrossDim / linesCount); + crossDimLead = (remainingCrossDim / linesCount); } } @@ -709,59 +706,52 @@ var computeLayout = (function() { var/*int*/ lineIndex = -1; // get the first child on the current line - { - child = node.children[i]; - if (getPositionType(child) != CSS_POSITION_RELATIVE) { - ++i; - continue; - } - lineIndex = child.lineIndex; + child = node.children[i]; + if (getPositionType(child) !== CSS_POSITION_RELATIVE) { + ++i; + continue; } + lineIndex = child.lineIndex; // compute the line's height and find the endIndex var/*float*/ lineHeight = 0; for (ii = startIndex; ii < node.children.length; ++ii) { child = node.children[ii]; - if (getPositionType(child) != CSS_POSITION_RELATIVE) { + if (getPositionType(child) !== CSS_POSITION_RELATIVE) { continue; } - if (child.lineIndex != lineIndex) { + if (child.lineIndex !== lineIndex) { break; } if (!isUndefined(child.layout[dim[crossAxis]])) { - lineHeight = fmaxf(lineHeight,child.layout[dim[crossAxis]] + - getMarginAxis(child,crossAxis)); + lineHeight = fmaxf( + lineHeight, + child.layout[dim[crossAxis]] + getMarginAxis(child, crossAxis) + ); } } var/*int*/ endIndex = ii; - lineHeight += crossDimAdd; + lineHeight += crossDimLead; for (ii = startIndex; ii < endIndex; ++ii) { child = node.children[ii]; - if (getPositionType(child) != CSS_POSITION_RELATIVE) { + if (getPositionType(child) !== CSS_POSITION_RELATIVE) { continue; } var/*css_align_t*/ alignItem = getAlignItem(node, child); - var/*float*/ crossPosition = child.layout[pos[crossAxis]]; // preserve current position if someting goes wrong with alignItem? - if (alignItem == CSS_ALIGN_FLEX_START) { - crossPosition = currentLead + getMargin(child,leading[crossAxis]); - } - else if (alignItem == CSS_ALIGN_FLEX_END) { - crossPosition = currentLead + lineHeight - - getMargin(child,trailing[crossAxis]) - - child.layout[dim[crossAxis]]; - } - else if (alignItem == CSS_ALIGN_CENTER) { + 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/*float*/ childHeight = child.layout[dim[crossAxis]]; - crossPosition = currentLead + ((lineHeight - childHeight)/2); + child.layout[pos[crossAxis]] = currentLead + (lineHeight - childHeight) / 2; + } else if (alignItem === CSS_ALIGN_STRETCH) { + child.layout[pos[crossAxis]] = currentLead + getMargin(child, leading[crossAxis]); + // TODO(prenaux): Correctly set the height of items with undefined + // (auto) crossAxis dimension. } - else if (alignItem == CSS_ALIGN_STRETCH) { - crossPosition = currentLead + getMargin(child,leading[crossAxis]); - // TODO: Correctly set the height of items with undefined (auto) - // crossAxis dimension. - } - child.layout[pos[crossAxis]] = crossPosition; } currentLead += lineHeight; @@ -791,8 +781,7 @@ var computeLayout = (function() { ); } - // Calculate dimensions for absolutely positioned elements - + // Calculate dimensions for absolutely positioned elements for (i = 0; i < node.children.length; ++i) { child = node.children[i]; if (getPositionType(child) === CSS_POSITION_ABSOLUTE) { diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index 6ba84cdb..b084b434 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -1594,49 +1594,49 @@ describe('Layout alignContent', function() { var alignContentData = { style: {width: 300, height: 380, flexDirection: 'row', flexWrap: 'wrap'}, children: [ - /* 0 */ { style: {width: 50, height: 50, margin: 10} }, - /* 1 */ { style: {width: 50, height: 50, margin: 10} }, - /* 2 */ { style: {width: 50, height: 50, margin: 10} }, - /* 3 */ { style: {width: 50, height: 50, margin: 10} }, - /* 4 */ { style: {width: 50, height: 100, margin: 10} }, - /* 5 */ { style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'} }, - /* 6 */ { style: {width: 50, height: 50, margin: 10} }, - /* 7 */ { style: {width: 50, height: 100, margin: 10} }, - /* 8 */ { style: {width: 50, height: 50, margin: 10} }, - /* 9 */ { style: {width: 50, height: 50, margin: 10} }, - /* 10 */ { style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start' } }, - /* 11 */ { style: {width: 50, height: 50, margin: 10} }, - /* 12 */ { style: {width: 50, height: 50, margin: 10} }, - /* 13 */ { style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'} }, - /* 14 */ { style: {width: 50, height: 50, margin: 10} }, + /* 0 */ {style: {width: 50, height: 50, margin: 10}}, + /* 1 */ {style: {width: 50, height: 50, margin: 10}}, + /* 2 */ {style: {width: 50, height: 50, margin: 10}}, + /* 3 */ {style: {width: 50, height: 50, margin: 10}}, + /* 4 */ {style: {width: 50, height: 100, margin: 10}}, + /* 5 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, + /* 6 */ {style: {width: 50, height: 50, margin: 10}}, + /* 7 */ {style: {width: 50, height: 100, margin: 10}}, + /* 8 */ {style: {width: 50, height: 50, margin: 10}}, + /* 9 */ {style: {width: 50, height: 50, margin: 10}}, + /* 10 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start' }}, + /* 11 */ {style: {width: 50, height: 50, margin: 10}}, + /* 12 */ {style: {width: 50, height: 50, margin: 10}}, + /* 13 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, + /* 14 */ {style: {width: 50, height: 50, margin: 10}}, ], }; it('should layout with alignContent: stretch, and alignItems: flex-start', function() { testLayout( alignContentData, - { width:300,height:380,top:0,left:0, children:[ - {width:50,height:50,top:10,left:10}, - {width:50,height:50,top:10,left:80}, - {width:50,height:50,top:10,left:150}, - {width:50,height:50,top:10,left:220}, - {width:50,height:100,top:92.5,left:10}, - {width:50,height:50,top:92.5,left:80}, - {width:50,height:50,top:92.5,left:150}, - {width:50,height:100,top:92.5,left:220}, - {width:50,height:50,top:225,left:10}, - {width:50,height:50,top:225,left:80}, - {width:50,height:50,top:225,left:150}, - {width:50,height:50,top:225,left:220}, - {width:50,height:50,top:307.5,left:10}, - {width:50,height:50,top:307.5,left:80}, - {width:50,height:50,top:307.5,left:150} + {width: 300, height: 380, top: 0, left: 0, children: [ + {width: 50, height: 50, top: 10, left: 10}, + {width: 50, height: 50, top: 10, left: 80}, + {width: 50, height: 50, top: 10, left: 150}, + {width: 50, height: 50, top: 10, left: 220}, + {width: 50, height: 100, top: 92.5, left: 10}, + {width: 50, height: 50, top: 92.5, left: 80}, + {width: 50, height: 50, top: 92.5, left: 150}, + {width: 50, height: 100, top: 92.5, left: 220}, + {width: 50, height: 50, top: 225, left: 10}, + {width: 50, height: 50, top: 225, left: 80}, + {width: 50, height: 50, top: 225, left: 150}, + {width: 50, height: 50, top: 225, left: 220}, + {width: 50, height: 50, top: 307.5, left: 10}, + {width: 50, height: 50, top: 307.5, left: 80}, + {width: 50, height: 50, top: 307.5, left: 150} ]} ); }); - function testAlignContent(aAlignContent, aAlignItems) { - it('should layout with alignContent: '+aAlignContent+', and alignItems: '+aAlignItems, function() { + function testAlignContent(alignContent, alignItems) { + it('should layout with alignContent: ' + alignContent + ', and alignItems: ' + alignItems, function() { testLayoutAgainstDomOnly(alignContentData); }); } diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java index 28d32c02..197d353e 100644 --- a/src/java/src/com/facebook/csslayout/LayoutEngine.java +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -718,10 +718,10 @@ public class LayoutEngine { startLine = endLine; } - // + // // - // PIERRE: More than one line, we need to layout the crossAxis according to - // alignContent. + // Note(prenaux): More than one line, we need to layout the crossAxis + // according to alignContent. // // Note that we could probably remove and handle the one line case // here too, but for the moment this is safer since it won't interfere with @@ -732,25 +732,22 @@ public class LayoutEngine { // section 9.4 // if (linesCount > 1 && - (!CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis))))) - { + !CSSConstants.isUndefined(getLayoutDimension(node, getDim(crossAxis)))) { float nodeCrossAxisInnerSize = getLayoutDimension(node, getDim(crossAxis)) - getPaddingAndBorderAxis(node, crossAxis); float remainingCrossDim = nodeCrossAxisInnerSize - linesCrossDim; - float crossDimAdd = 0; + float crossDimLead = 0; float currentLead = getPaddingAndBorder(node, getLeading(crossAxis)); CSSAlign alignContent = getAlignContent(node); if (alignContent == CSSAlign.FLEX_END) { currentLead = currentLead + remainingCrossDim; - } - else if (alignContent == CSSAlign.CENTER) { + } else if (alignContent == CSSAlign.CENTER) { currentLead = currentLead + remainingCrossDim / 2; - } - else if (alignContent == CSSAlign.STRETCH) { + } else if (alignContent == CSSAlign.STRETCH) { if (nodeCrossAxisInnerSize > linesCrossDim) { - crossDimAdd = (remainingCrossDim / linesCount); + crossDimLead = (remainingCrossDim / linesCount); } } @@ -760,14 +757,12 @@ public class LayoutEngine { int lineIndex = -1; // get the first child on the current line - { - child = node.getChildAt(i); - if (getPositionType(child) != CSSPositionType.RELATIVE) { - ++i; - continue; - } - lineIndex = child.lineIndex; + child = node.getChildAt(i); + if (getPositionType(child) != CSSPositionType.RELATIVE) { + ++i; + continue; } + lineIndex = child.lineIndex; // compute the line's height and find the endIndex float lineHeight = 0; @@ -780,12 +775,14 @@ public class LayoutEngine { break; } if (!CSSConstants.isUndefined(getLayoutDimension(child, getDim(crossAxis)))) { - lineHeight = Math.max(lineHeight,getLayoutDimension(child, getDim(crossAxis)) + - getMarginAxis(child,crossAxis)); + lineHeight = Math.max( + lineHeight, + getLayoutDimension(child, getDim(crossAxis)) + getMarginAxis(child, crossAxis) + ); } } int endIndex = ii; - lineHeight = lineHeight + crossDimAdd; + lineHeight = lineHeight + crossDimLead; for (ii = startIndex; ii < endIndex; ++ii) { child = node.getChildAt(ii); @@ -794,25 +791,18 @@ public class LayoutEngine { } CSSAlign alignItem = getAlignItem(node, child); - float crossPosition = getLayoutPosition(child, getPos(crossAxis)); // preserve current position if someting goes wrong with alignItem? if (alignItem == CSSAlign.FLEX_START) { - crossPosition = currentLead + getMargin(child,getLeading(crossAxis)); - } - else if (alignItem == CSSAlign.FLEX_END) { - crossPosition = currentLead + lineHeight - - getMargin(child,getTrailing(crossAxis)) - - getLayoutDimension(child, getDim(crossAxis)); - } - else if (alignItem == CSSAlign.CENTER) { + 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) { float childHeight = getLayoutDimension(child, getDim(crossAxis)); - crossPosition = currentLead + ((lineHeight - childHeight)/2); + setLayoutPosition(child, getPos(crossAxis), currentLead + (lineHeight - childHeight) / 2); + } else if (alignItem == CSSAlign.STRETCH) { + setLayoutPosition(child, getPos(crossAxis), currentLead + getMargin(child, getLeading(crossAxis))); + // TODO(prenaux): Correctly set the height of items with undefined + // (auto) crossAxis dimension. } - else if (alignItem == CSSAlign.STRETCH) { - crossPosition = currentLead + getMargin(child,getLeading(crossAxis)); - // TODO: Correctly set the height of items with undefined (auto) - // crossAxis dimension. - } - setLayoutPosition(child, getPos(crossAxis), crossPosition); } currentLead = currentLead + lineHeight; @@ -842,8 +832,7 @@ public class LayoutEngine { )); } - // Calculate dimensions for absolutely positioned elements - + // Calculate dimensions for absolutely positioned elements for (i = 0; i < node.getChildCount(); ++i) { child = node.getChildAt(i); if (getPositionType(child) == CSSPositionType.ABSOLUTE) { From 84937899897042f41f3237aa788ccacbbab75653 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 11:47:27 +0800 Subject: [PATCH 08/14] [src/Layout-test-utils.js]: Fix so that RunLayoutTests.html works on Chrome for Windows ; --- src/Layout-test-utils.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index 96df2fcf..7edf6905 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -403,6 +403,13 @@ var layoutTestUtils = (function() { bigMinWidth: 100.4375 }; + // Note(prenaux): Clearly not what I would like, but it seems to be the only + // way :( My guess is that since the font on Windows is + // different than on OSX it has a different size. + if (typeof navigator !== 'undefined' && navigator.userAgent.indexOf("Windows NT") > -1) { + preDefinedTextSizes.bigHeight = 36; + } + var textSizes; if (typeof require === 'function') { textSizes = preDefinedTextSizes; From b6de3e600eba5ee06485226f7570b2dc9ec7b874 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 11:49:17 +0800 Subject: [PATCH 09/14] [Makefile]: Updated so that it works on OSX & Windows - for Windows it requires GCC, make 3.82 & wget to be on PATH ; --- Makefile | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index f40b9264..b3f66362 100644 --- a/Makefile +++ b/Makefile @@ -6,23 +6,45 @@ # of patent rights can be found in the PATENTS file in the same directory. FILES=src/__tests__/Layout-test.c src/Layout.c src/Layout-test-utils.c +JAVA_LIB_DIR=lib + +ifeq ($(OS),Windows_NT) + C_TEST_EXE=./c_test.exe + ENVSEP=";" + WGET=wget --no-check-certificate + LLDB=gdb +else + C_TEST_EXE=./c_test + ENVSEP=":" + WGET=wget + LLDB=lldb +endif all: c c_test java java_test c: transpile_all c_test: c - @gcc -std=c99 -Werror -Wno-padded $(FILES) -lm && ./a.out - @rm a.out + @gcc -std=c99 -Werror -Wno-padded $(FILES) -lm -o "$(C_TEST_EXE)" && "$(C_TEST_EXE)" + @rm "$(C_TEST_EXE)" -java: transpile_all src/java - @if [ ! -f lib/junit4.jar ]; then mkdir lib/; wget -O lib/junit4.jar http://search.maven.org/remotecontent?filepath=junit/junit/4.10/junit-4.10.jar; fi - @if [ ! -f lib/jsr305.jar ]; then mkdir lib/; wget -O lib/jsr305.jar http://search.maven.org/remotecontent?filepath=net/sourceforge/findbugs/jsr305/1.3.7/jsr305-1.3.7.jar; fi - @if [ ! -f lib/infer-annotations-1.4.jar ]; then mkdir lib/; wget -O lib/infer-annotations-1.4.jar https://github.com/facebook/buck/raw/027ffe2b230c08cad7b340646c6f801bd6dabc78/third-party/java/infer-annotations/infer-annotations-1.4.jar; fi - @javac -cp ./lib/junit4.jar:./lib/jsr305.jar:./lib/infer-annotations-1.4.jar -sourcepath ./src/java/src:./src/java/tests src/java/tests/com/facebook/csslayout/*.java +$(JAVA_LIB_DIR): + mkdir $(JAVA_LIB_DIR) + +$(JAVA_LIB_DIR)/junit4.jar: | $(JAVA_LIB_DIR) + $(WGET) -O $(JAVA_LIB_DIR)/junit4.jar http://search.maven.org/remotecontent?filepath=junit/junit/4.10/junit-4.10.jar + +$(JAVA_LIB_DIR)/jsr305.jar: | $(JAVA_LIB_DIR) + $(WGET) -O $(JAVA_LIB_DIR)/jsr305.jar http://search.maven.org/remotecontent?filepath=net/sourceforge/findbugs/jsr305/1.3.7/jsr305-1.3.7.jar + +$(JAVA_LIB_DIR)/infer-annotations-1.4.jar: | $(JAVA_LIB_DIR) + $(WGET) -O $(JAVA_LIB_DIR)/infer-annotations-1.4.jar https://github.com/facebook/buck/raw/027ffe2b230c08cad7b340646c6f801bd6dabc78/third-party/java/infer-annotations/infer-annotations-1.4.jar + +java: transpile_all src/java | $(JAVA_LIB_DIR)/junit4.jar $(JAVA_LIB_DIR)/jsr305.jar $(JAVA_LIB_DIR)/infer-annotations-1.4.jar + @javac -cp ./$(JAVA_LIB_DIR)/junit4.jar$(ENVSEP)./$(JAVA_LIB_DIR)/jsr305.jar$(ENVSEP)./$(JAVA_LIB_DIR)/infer-annotations-1.4.jar -sourcepath ./src/java/src$(ENVSEP)./src/java/tests src/java/tests/com/facebook/csslayout/*.java java_test: java - @java -cp ./src/java/src:./src/java/tests:./lib/junit4.jar:./lib/infer-annotations-1.4.jar org.junit.runner.JUnitCore \ + @java -cp ./src/java/src$(ENVSEP)./src/java/tests$(ENVSEP)./$(JAVA_LIB_DIR)/junit4.jar$(ENVSEP)./$(JAVA_LIB_DIR)/infer-annotations-1.4.jar org.junit.runner.JUnitCore \ com.facebook.csslayout.LayoutEngineTest \ com.facebook.csslayout.LayoutCachingTest \ com.facebook.csslayout.CSSNodeTest @@ -31,5 +53,5 @@ transpile_all: ./src/transpile.js @node ./src/transpile.js debug: - @gcc -ggdb $(FILES) -lm && lldb ./a.out - @rm a.out + @gcc -std=c99 -ggdb $(FILES) -lm -o $(C_TEST_EXE) && $(LLDB) $(C_TEST_EXE) + @rm $(C_TEST_EXE) From c7fbf44474a08b7343817d20a01a84cc80fe2526 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 11:58:02 +0800 Subject: [PATCH 10/14] 'alignContent' defaults to 'flex-start' instead of 'stretch' ; --- src/Layout-test-utils.js | 4 ++-- src/Layout.c | 2 +- src/Layout.js | 2 +- src/java/src/com/facebook/csslayout/CSSStyle.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index 7edf6905..2eaa18e6 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -371,13 +371,13 @@ var layoutTestUtils = (function() { div.style.display = 'flex'; div.style.flexDirection = 'column'; div.style.alignItems = 'flex-start'; - div.style.alignContent = 'stretch'; + div.style.alignContent = 'flex-start'; var span = document.createElement('span'); span.style.display = 'flex'; span.style.flexDirection = 'column'; span.style.alignItems = 'flex-start'; - span.style.alignContent = 'stretch'; + span.style.alignContent = 'flex-start'; span.innerText = text; div.appendChild(span); diff --git a/src/Layout.c b/src/Layout.c index de0788f9..7694aed1 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -35,7 +35,7 @@ static bool eq(float a, float b) { void init_css_node(css_node_t *node) { node->style.align_items = CSS_ALIGN_STRETCH; - node->style.align_content = CSS_ALIGN_STRETCH; + node->style.align_content = CSS_ALIGN_FLEX_START; // Some of the fields default to undefined and not 0 node->style.dimensions[CSS_WIDTH] = CSS_UNDEFINED; diff --git a/src/Layout.js b/src/Layout.js index 42c3657d..099ba315 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -148,7 +148,7 @@ var computeLayout = (function() { if ('alignContent' in node.style) { return node.style.alignContent; } - return 'stretch'; + return 'flex-start'; } function getAlignItem(node, child) { diff --git a/src/java/src/com/facebook/csslayout/CSSStyle.java b/src/java/src/com/facebook/csslayout/CSSStyle.java index 64c67fc2..72e807bc 100644 --- a/src/java/src/com/facebook/csslayout/CSSStyle.java +++ b/src/java/src/com/facebook/csslayout/CSSStyle.java @@ -15,7 +15,7 @@ public class CSSStyle { public CSSFlexDirection flexDirection = CSSFlexDirection.COLUMN; public CSSJustify justifyContent = CSSJustify.FLEX_START; - public CSSAlign alignContent = CSSAlign.STRETCH; + public CSSAlign alignContent = CSSAlign.FLEX_START; public CSSAlign alignItems = CSSAlign.STRETCH; public CSSAlign alignSelf = CSSAlign.AUTO; public CSSPositionType positionType = CSSPositionType.RELATIVE; From 14e264f5bed214fcfb733b0c6949518ffaf21403 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 13:03:21 +0800 Subject: [PATCH 11/14] Made relevant JS tests transpile to C ; [src/Layout.c]: print_css_node_rec(): print alignContent ; [src/Layout-test-utils.c]: add_failed_test(): Sets failed_test->next to NULL, otherwise the test crashes if there's one and only one failure ; Added type casts so that it can be compiled as C++ by MSVC on Windows ; [Makefile]: Added c_test_msvc target when running in Windows so that the test executable can be built and debugged with Visual Studio on Windows ; --- Makefile | 6 + src/Layout-test-utils.c | 27 ++- src/Layout-test-utils.h | 1 - src/Layout-test-utils.js | 2 +- src/Layout.c | 8 + src/__tests__/Layout-test.c | 215 +++++++++++++++++ src/__tests__/Layout-test.js | 66 ++++-- .../facebook/csslayout/LayoutEngineTest.java | 217 ++++++++++++++++++ src/transpile.js | 5 +- 9 files changed, 513 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index b3f66362..7457d412 100644 --- a/Makefile +++ b/Makefile @@ -55,3 +55,9 @@ transpile_all: ./src/transpile.js debug: @gcc -std=c99 -ggdb $(FILES) -lm -o $(C_TEST_EXE) && $(LLDB) $(C_TEST_EXE) @rm $(C_TEST_EXE) + +ifeq ($(OS),Windows_NT) +c_test_msvc: c + @cl -nologo -Zi -Tpsrc/__tests__/Layout-test.c -Tpsrc/Layout.c -Tpsrc/Layout-test-utils.c -link -incremental:no -out:"$(C_TEST_EXE)" && "$(C_TEST_EXE)" + @rm "$(C_TEST_EXE)" ./*.obj ./*.pdb +endif diff --git a/src/Layout-test-utils.c b/src/Layout-test-utils.c index 6a28f1f4..0f89339a 100644 --- a/src/Layout-test-utils.c +++ b/src/Layout-test-utils.c @@ -10,6 +10,17 @@ #include "Layout-test-utils.h" #include +#ifdef _MSC_VER +#include +#define isnan _isnan +__forceinline const float fmaxf(const float a, const float b) { + return (a > b) ? a : b; +} +__forceinline const float fminf(const float a, const float b) { + return (a < b) ? a : b; +} +#endif + /** START_GENERATED **/ #define SMALL_WIDTH 35 #define SMALL_HEIGHT 18 @@ -30,7 +41,8 @@ typedef struct failed_test_t { static failed_test_t *failed_test_head = NULL; static failed_test_t *failed_test_tail = NULL; static void add_failed_test(const char *name, css_node_t *style, css_node_t *expected) { - failed_test_t *failed_test = malloc(sizeof(failed_test_t)); + failed_test_t *failed_test = (failed_test_t *)malloc(sizeof(failed_test_t)); + failed_test->next = NULL; failed_test->name = name; failed_test->style = style; failed_test->expected = expected; @@ -65,7 +77,7 @@ static bool are_layout_equal(css_node_t *a, css_node_t *b) { } css_dim_t measure(void *context, float width) { - const char *text = context; + const char *text = (const char *)context; css_dim_t dim; if (width != width) { width = 1000000; @@ -87,7 +99,10 @@ css_dim_t measure(void *context, float width) { return dim; } +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); if (!are_layout_equal(style, expected_layout)) { @@ -109,12 +124,12 @@ int tests_finished() { printf("%sFAIL%s %s\n", "\x1B[31m", "\x1B[0m", failed_test->name); printf("Input: "); - print_css_node(failed_test->style, CSS_PRINT_STYLE | CSS_PRINT_CHILDREN); + print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_STYLE | CSS_PRINT_CHILDREN)); printf("Output: "); - print_css_node(failed_test->style, CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN); + print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN)); printf("Expected: "); - print_css_node(failed_test->expected, CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN); + print_css_node(failed_test->expected, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN)); free_css_node(failed_test->style); free_css_node(failed_test->expected); @@ -131,7 +146,7 @@ int tests_finished() { printf("TESTS FAILED: %d\n", tests_failed); return 1; } else { - printf("ALL TESTS PASSED\n"); + printf("ALL TESTS PASSED: %d tests ran.\n", test_ran_count); return 0; } } diff --git a/src/Layout-test-utils.h b/src/Layout-test-utils.h index 7a04f5a3..73569cce 100644 --- a/src/Layout-test-utils.h +++ b/src/Layout-test-utils.h @@ -9,7 +9,6 @@ #include "Layout.h" #include -#include #include void test(const char *name, css_node_t *style, css_node_t *expected_layout); diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js index 2eaa18e6..d0e66b34 100644 --- a/src/Layout-test-utils.js +++ b/src/Layout-test-utils.js @@ -253,7 +253,7 @@ var layoutTestUtils = (function() { var val = obj[key]; if (typeof val === 'number') { - obj[key] = Math.floor((val * testMeasurePrecision) + 0.5) /testMeasurePrecision; + obj[key] = Math.floor((val * testMeasurePrecision) + 0.5) / testMeasurePrecision; } else if (typeof val === 'object') { inplaceRoundNumbersInObject(val); diff --git a/src/Layout.c b/src/Layout.c index 7694aed1..d44c6b8c 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -142,6 +142,14 @@ static void print_css_node_rec( printf("alignItems: 'stretch', "); } + if (node->style.align_content == CSS_ALIGN_CENTER) { + printf("alignContent: 'center', "); + } else if (node->style.align_content == CSS_ALIGN_FLEX_END) { + printf("alignContent: 'flex-end', "); + } else if (node->style.align_content == CSS_ALIGN_STRETCH) { + printf("alignContent: 'stretch', "); + } + if (node->style.align_self == CSS_ALIGN_FLEX_START) { printf("alignSelf: 'flex-start', "); } else if (node->style.align_self == CSS_ALIGN_CENTER) { diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c index 16e7ea65..269ce927 100644 --- a/src/__tests__/Layout-test.c +++ b/src/__tests__/Layout-test.c @@ -4873,6 +4873,221 @@ int main() test("should layout absolutely positioned node with padded flex 1 parent", root_node, root_layout); } + + { + css_node_t *root_node = new_test_css_node(); + { + css_node_t *node_0 = root_node; + node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW; + node_0->style.align_content = CSS_ALIGN_STRETCH; + node_0->style.align_items = CSS_ALIGN_FLEX_START; + node_0->style.flex_wrap = CSS_WRAP; + node_0->style.dimensions[CSS_WIDTH] = 300; + node_0->style.dimensions[CSS_HEIGHT] = 380; + init_css_node_children(node_0, 15); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 1); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 2); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 3); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 4); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 100; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 5); + node_1->style.align_self = CSS_ALIGN_FLEX_START; + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 6); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 7); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 100; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 8); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 9); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 10); + node_1->style.align_self = CSS_ALIGN_FLEX_START; + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 11); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 12); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 13); + node_1->style.align_self = CSS_ALIGN_FLEX_START; + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + node_1 = node_0->get_child(node_0->context, 14); + node_1->style.dimensions[CSS_WIDTH] = 50; + node_1->style.dimensions[CSS_HEIGHT] = 50; + node_1->style.margin[CSS_LEFT] = 10; + node_1->style.margin[CSS_TOP] = 10; + node_1->style.margin[CSS_RIGHT] = 10; + node_1->style.margin[CSS_BOTTOM] = 10; + } + } + + css_node_t *root_layout = new_test_css_node(); + { + css_node_t *node_0 = root_layout; + node_0->layout.position[CSS_TOP] = 0; + node_0->layout.position[CSS_LEFT] = 0; + node_0->layout.dimensions[CSS_WIDTH] = 300; + node_0->layout.dimensions[CSS_HEIGHT] = 380; + init_css_node_children(node_0, 15); + { + css_node_t *node_1; + node_1 = node_0->get_child(node_0->context, 0); + node_1->layout.position[CSS_TOP] = 10; + node_1->layout.position[CSS_LEFT] = 10; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 1); + node_1->layout.position[CSS_TOP] = 10; + node_1->layout.position[CSS_LEFT] = 80; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 2); + node_1->layout.position[CSS_TOP] = 10; + node_1->layout.position[CSS_LEFT] = 150; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 3); + node_1->layout.position[CSS_TOP] = 10; + node_1->layout.position[CSS_LEFT] = 220; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 4); + node_1->layout.position[CSS_TOP] = 92.5; + node_1->layout.position[CSS_LEFT] = 10; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 100; + node_1 = node_0->get_child(node_0->context, 5); + node_1->layout.position[CSS_TOP] = 92.5; + node_1->layout.position[CSS_LEFT] = 80; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 6); + node_1->layout.position[CSS_TOP] = 92.5; + node_1->layout.position[CSS_LEFT] = 150; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 7); + node_1->layout.position[CSS_TOP] = 92.5; + node_1->layout.position[CSS_LEFT] = 220; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 100; + node_1 = node_0->get_child(node_0->context, 8); + node_1->layout.position[CSS_TOP] = 225; + node_1->layout.position[CSS_LEFT] = 10; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 9); + node_1->layout.position[CSS_TOP] = 225; + node_1->layout.position[CSS_LEFT] = 80; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 10); + node_1->layout.position[CSS_TOP] = 225; + node_1->layout.position[CSS_LEFT] = 150; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 11); + node_1->layout.position[CSS_TOP] = 225; + node_1->layout.position[CSS_LEFT] = 220; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 12); + node_1->layout.position[CSS_TOP] = 307.5; + node_1->layout.position[CSS_LEFT] = 10; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 13); + node_1->layout.position[CSS_TOP] = 307.5; + node_1->layout.position[CSS_LEFT] = 80; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + node_1 = node_0->get_child(node_0->context, 14); + node_1->layout.position[CSS_TOP] = 307.5; + node_1->layout.position[CSS_LEFT] = 150; + node_1->layout.dimensions[CSS_WIDTH] = 50; + node_1->layout.dimensions[CSS_HEIGHT] = 50; + } + } + + test("should layout with alignContent: stretch, and alignItems: flex-start", root_node, root_layout); + } /** END_GENERATED **/ return tests_finished(); } diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index b084b434..6ff28331 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -1591,30 +1591,27 @@ describe('Layout', function() { describe('Layout alignContent', function() { - var alignContentData = { - style: {width: 300, height: 380, flexDirection: 'row', flexWrap: 'wrap'}, - children: [ - /* 0 */ {style: {width: 50, height: 50, margin: 10}}, - /* 1 */ {style: {width: 50, height: 50, margin: 10}}, - /* 2 */ {style: {width: 50, height: 50, margin: 10}}, - /* 3 */ {style: {width: 50, height: 50, margin: 10}}, - /* 4 */ {style: {width: 50, height: 100, margin: 10}}, - /* 5 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, - /* 6 */ {style: {width: 50, height: 50, margin: 10}}, - /* 7 */ {style: {width: 50, height: 100, margin: 10}}, - /* 8 */ {style: {width: 50, height: 50, margin: 10}}, - /* 9 */ {style: {width: 50, height: 50, margin: 10}}, - /* 10 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start' }}, - /* 11 */ {style: {width: 50, height: 50, margin: 10}}, - /* 12 */ {style: {width: 50, height: 50, margin: 10}}, - /* 13 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, - /* 14 */ {style: {width: 50, height: 50, margin: 10}}, - ], - }; - it('should layout with alignContent: stretch, and alignItems: flex-start', function() { testLayout( - alignContentData, + {style: {width: 300, height: 380, flexDirection: 'row', flexWrap: 'wrap', alignContent: 'stretch', alignItems: 'flex-start'}, + children: [ + /* 0 */ {style: {width: 50, height: 50, margin: 10}}, + /* 1 */ {style: {width: 50, height: 50, margin: 10}}, + /* 2 */ {style: {width: 50, height: 50, margin: 10}}, + /* 3 */ {style: {width: 50, height: 50, margin: 10}}, + /* 4 */ {style: {width: 50, height: 100, margin: 10}}, + /* 5 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, + /* 6 */ {style: {width: 50, height: 50, margin: 10}}, + /* 7 */ {style: {width: 50, height: 100, margin: 10}}, + /* 8 */ {style: {width: 50, height: 50, margin: 10}}, + /* 9 */ {style: {width: 50, height: 50, margin: 10}}, + /* 10 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start' }}, + /* 11 */ {style: {width: 50, height: 50, margin: 10}}, + /* 12 */ {style: {width: 50, height: 50, margin: 10}}, + /* 13 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, + /* 14 */ {style: {width: 50, height: 50, margin: 10}}, + ], + }, {width: 300, height: 380, top: 0, left: 0, children: [ {width: 50, height: 50, top: 10, left: 10}, {width: 50, height: 50, top: 10, left: 80}, @@ -1635,13 +1632,32 @@ describe('Layout alignContent', function() { ); }); + function testAlignContent(alignContent, alignItems) { it('should layout with alignContent: ' + alignContent + ', and alignItems: ' + alignItems, function() { - testLayoutAgainstDomOnly(alignContentData); + testLayoutAgainstDomOnly( + {style: {width: 300, height: 380, flexDirection: 'row', flexWrap: 'wrap', alignContent: alignContent, alignItems: alignItems}, + children: [ + /* 0 */ {style: {width: 50, height: 50, margin: 10}}, + /* 1 */ {style: {width: 50, height: 50, margin: 10}}, + /* 2 */ {style: {width: 50, height: 50, margin: 10}}, + /* 3 */ {style: {width: 50, height: 50, margin: 10}}, + /* 4 */ {style: {width: 50, height: 100, margin: 10}}, + /* 5 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, + /* 6 */ {style: {width: 50, height: 50, margin: 10}}, + /* 7 */ {style: {width: 50, height: 100, margin: 10}}, + /* 8 */ {style: {width: 50, height: 50, margin: 10}}, + /* 9 */ {style: {width: 50, height: 50, margin: 10}}, + /* 10 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start' }}, + /* 11 */ {style: {width: 50, height: 50, margin: 10}}, + /* 12 */ {style: {width: 50, height: 50, margin: 10}}, + /* 13 */ {style: {width: 50, height: 50, margin: 10, alignSelf: 'flex-start'}}, + /* 14 */ {style: {width: 50, height: 50, margin: 10}}, + ], + } + ); }); } - - // testAlignContent('stretch', 'flex-start'); // above with expected value data testAlignContent('stretch', 'center'); testAlignContent('stretch', 'flex-end'); testAlignContent('stretch', 'stretch'); diff --git a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java index 296fa608..0e1ee66c 100644 --- a/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java +++ b/src/java/tests/com/facebook/csslayout/LayoutEngineTest.java @@ -5194,5 +5194,222 @@ public class LayoutEngineTest { test("should layout absolutely positioned node with padded flex 1 parent", root_node, root_layout); } + + @Test + public void testCase123() + { + TestCSSNode root_node = new TestCSSNode(); + { + TestCSSNode node_0 = root_node; + node_0.style.flexDirection = CSSFlexDirection.ROW; + node_0.style.alignContent = CSSAlign.STRETCH; + node_0.style.alignItems = CSSAlign.FLEX_START; + node_0.style.flexWrap = CSSWrap.WRAP; + node_0.style.width = 300; + node_0.style.height = 380; + addChildren(node_0, 15); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(1); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(2); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(3); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(4); + node_1.style.width = 50; + node_1.style.height = 100; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(5); + node_1.style.alignSelf = CSSAlign.FLEX_START; + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(6); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(7); + node_1.style.width = 50; + node_1.style.height = 100; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(8); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(9); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(10); + node_1.style.alignSelf = CSSAlign.FLEX_START; + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(11); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(12); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(13); + node_1.style.alignSelf = CSSAlign.FLEX_START; + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + node_1 = node_0.getChildAt(14); + node_1.style.width = 50; + node_1.style.height = 50; + node_1.style.margin[Spacing.LEFT] = 10; + node_1.style.margin[Spacing.TOP] = 10; + node_1.style.margin[Spacing.RIGHT] = 10; + node_1.style.margin[Spacing.BOTTOM] = 10; + } + } + + TestCSSNode root_layout = new TestCSSNode(); + { + TestCSSNode node_0 = root_layout; + node_0.layout.y = 0; + node_0.layout.x = 0; + node_0.layout.width = 300; + node_0.layout.height = 380; + addChildren(node_0, 15); + { + TestCSSNode node_1; + node_1 = node_0.getChildAt(0); + node_1.layout.y = 10; + node_1.layout.x = 10; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(1); + node_1.layout.y = 10; + node_1.layout.x = 80; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(2); + node_1.layout.y = 10; + node_1.layout.x = 150; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(3); + node_1.layout.y = 10; + node_1.layout.x = 220; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(4); + node_1.layout.y = 92.5f; + node_1.layout.x = 10; + node_1.layout.width = 50; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(5); + node_1.layout.y = 92.5f; + node_1.layout.x = 80; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(6); + node_1.layout.y = 92.5f; + node_1.layout.x = 150; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(7); + node_1.layout.y = 92.5f; + node_1.layout.x = 220; + node_1.layout.width = 50; + node_1.layout.height = 100; + node_1 = node_0.getChildAt(8); + node_1.layout.y = 225; + node_1.layout.x = 10; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(9); + node_1.layout.y = 225; + node_1.layout.x = 80; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(10); + node_1.layout.y = 225; + node_1.layout.x = 150; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(11); + node_1.layout.y = 225; + node_1.layout.x = 220; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(12); + node_1.layout.y = 307.5f; + node_1.layout.x = 10; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(13); + node_1.layout.y = 307.5f; + node_1.layout.x = 80; + node_1.layout.width = 50; + node_1.layout.height = 50; + node_1 = node_0.getChildAt(14); + node_1.layout.y = 307.5f; + node_1.layout.x = 150; + node_1.layout.width = 50; + node_1.layout.height = 50; + } + } + + test("should layout with alignContent: stretch, and alignItems: flex-start", root_node, root_layout); + } /** END_GENERATED **/ } diff --git a/src/transpile.js b/src/transpile.js index b12c07e8..ab745dec 100644 --- a/src/transpile.js +++ b/src/transpile.js @@ -20,6 +20,8 @@ global.layoutTestUtils = { testLayout: function(node, expectedLayout) { allTests.push({name: currentTest, node: node, expectedLayout: expectedLayout}); }, + testLayoutAgainstDomOnly: function(node) { + }, testRandomLayout: function(node, i) { allTests.push({name: 'Random #' + i, node: node, expectedLayout: computeDOMLayout(node)}); }, @@ -31,7 +33,8 @@ global.layoutTestUtils = { }; global.describe = function(name, cb) { - if (name === 'Layout') { + if (name === 'Layout' || + name === 'Layout alignContent') { cb(); } }; From 09f0c12a8f0a3da86d8bacce1a4ffcb2b1f314d4 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 13:10:26 +0800 Subject: [PATCH 12/14] [src/Layout.js]: Cleaner line loop in (alignContent layout) ; --- src/Layout.c | 20 +++++-------------- src/Layout.js | 20 +++++-------------- .../com/facebook/csslayout/LayoutEngine.java | 20 +++++-------------- 3 files changed, 15 insertions(+), 45 deletions(-) diff --git a/src/Layout.c b/src/Layout.c index d44c6b8c..bc39dc0c 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -822,18 +822,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { } } - // find the first node on the first line - for (i = 0; i < node->children_count; ) { - int startIndex = i; - int lineIndex = -1; - - // get the first child on the current line - child = node->get_child(node->context, i); - if (getPositionType(child) != CSS_POSITION_RELATIVE) { - ++i; - continue; - } - lineIndex = child->line_index; + int endIndex = 0; + for (i = 0; i < linesCount; ++i) { + int startIndex = endIndex; // compute the line's height and find the endIndex float lineHeight = 0; @@ -842,7 +833,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { if (getPositionType(child) != CSS_POSITION_RELATIVE) { continue; } - if (child->line_index != lineIndex) { + if (child->line_index != i) { break; } if (!isUndefined(child->layout.dimensions[dim[crossAxis]])) { @@ -852,7 +843,7 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { ); } } - int endIndex = ii; + endIndex = ii; lineHeight += crossDimLead; for (ii = startIndex; ii < endIndex; ++ii) { @@ -877,7 +868,6 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth) { } currentLead += lineHeight; - i = endIndex; } } diff --git a/src/Layout.js b/src/Layout.js index 099ba315..d49c674e 100755 --- a/src/Layout.js +++ b/src/Layout.js @@ -700,18 +700,9 @@ var computeLayout = (function() { } } - // find the first node on the first line - for (i = 0; i < node.children.length; ) { - var/*int*/ startIndex = i; - var/*int*/ lineIndex = -1; - - // get the first child on the current line - child = node.children[i]; - if (getPositionType(child) !== CSS_POSITION_RELATIVE) { - ++i; - continue; - } - lineIndex = child.lineIndex; + var/*int*/ endIndex = 0; + for (i = 0; i < linesCount; ++i) { + var/*int*/ startIndex = endIndex; // compute the line's height and find the endIndex var/*float*/ lineHeight = 0; @@ -720,7 +711,7 @@ var computeLayout = (function() { if (getPositionType(child) !== CSS_POSITION_RELATIVE) { continue; } - if (child.lineIndex !== lineIndex) { + if (child.lineIndex !== i) { break; } if (!isUndefined(child.layout[dim[crossAxis]])) { @@ -730,7 +721,7 @@ var computeLayout = (function() { ); } } - var/*int*/ endIndex = ii; + endIndex = ii; lineHeight += crossDimLead; for (ii = startIndex; ii < endIndex; ++ii) { @@ -755,7 +746,6 @@ var computeLayout = (function() { } currentLead += lineHeight; - i = endIndex; } } diff --git a/src/java/src/com/facebook/csslayout/LayoutEngine.java b/src/java/src/com/facebook/csslayout/LayoutEngine.java index 197d353e..9a692f20 100644 --- a/src/java/src/com/facebook/csslayout/LayoutEngine.java +++ b/src/java/src/com/facebook/csslayout/LayoutEngine.java @@ -751,18 +751,9 @@ public class LayoutEngine { } } - // find the first node on the first line - for (i = 0; i < node.getChildCount(); ) { - int startIndex = i; - int lineIndex = -1; - - // get the first child on the current line - child = node.getChildAt(i); - if (getPositionType(child) != CSSPositionType.RELATIVE) { - ++i; - continue; - } - lineIndex = child.lineIndex; + int endIndex = 0; + for (i = 0; i < linesCount; ++i) { + int startIndex = endIndex; // compute the line's height and find the endIndex float lineHeight = 0; @@ -771,7 +762,7 @@ public class LayoutEngine { if (getPositionType(child) != CSSPositionType.RELATIVE) { continue; } - if (child.lineIndex != lineIndex) { + if (child.lineIndex != i) { break; } if (!CSSConstants.isUndefined(getLayoutDimension(child, getDim(crossAxis)))) { @@ -781,7 +772,7 @@ public class LayoutEngine { ); } } - int endIndex = ii; + endIndex = ii; lineHeight = lineHeight + crossDimLead; for (ii = startIndex; ii < endIndex; ++ii) { @@ -806,7 +797,6 @@ public class LayoutEngine { } currentLead = currentLead + lineHeight; - i = endIndex; } } From 176bb6097b5adb34066847136d00c929749f55f1 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 16:57:07 +0800 Subject: [PATCH 13/14] [Makefile]: Use cl (MSVC) on Windows ; --- Makefile | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 7457d412..736e8f27 100644 --- a/Makefile +++ b/Makefile @@ -24,10 +24,22 @@ all: c c_test java java_test c: transpile_all +ifeq ($(OS),Windows_NT) +c_test: c + @cl -nologo -Zi -Tpsrc/__tests__/Layout-test.c -Tpsrc/Layout.c -Tpsrc/Layout-test-utils.c -link -incremental:no -out:"$(C_TEST_EXE)" && "$(C_TEST_EXE)" + @rm "$(C_TEST_EXE)" ./*.obj ./*.pdb + +else c_test: c @gcc -std=c99 -Werror -Wno-padded $(FILES) -lm -o "$(C_TEST_EXE)" && "$(C_TEST_EXE)" @rm "$(C_TEST_EXE)" +debug: + @gcc -std=c99 -ggdb $(FILES) -lm -o $(C_TEST_EXE) && $(LLDB) $(C_TEST_EXE) + @rm $(C_TEST_EXE) + +endif + $(JAVA_LIB_DIR): mkdir $(JAVA_LIB_DIR) @@ -51,13 +63,3 @@ java_test: java transpile_all: ./src/transpile.js @node ./src/transpile.js - -debug: - @gcc -std=c99 -ggdb $(FILES) -lm -o $(C_TEST_EXE) && $(LLDB) $(C_TEST_EXE) - @rm $(C_TEST_EXE) - -ifeq ($(OS),Windows_NT) -c_test_msvc: c - @cl -nologo -Zi -Tpsrc/__tests__/Layout-test.c -Tpsrc/Layout.c -Tpsrc/Layout-test-utils.c -link -incremental:no -out:"$(C_TEST_EXE)" && "$(C_TEST_EXE)" - @rm "$(C_TEST_EXE)" ./*.obj ./*.pdb -endif From a91566d6dbad65d650f7e2a6bd00f3019a00f728 Mon Sep 17 00:00:00 2001 From: Pierre Renaux Date: Sat, 9 May 2015 17:30:03 +0800 Subject: [PATCH 14/14] [src/Layout.c & Layout-test-utils.c]: Don't define fmaxf/fminf if we're building with VC12+, its already declared from then on ; --- src/Layout-test-utils.c | 4 ++++ src/Layout.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Layout-test-utils.c b/src/Layout-test-utils.c index 0f89339a..30ea312b 100644 --- a/src/Layout-test-utils.c +++ b/src/Layout-test-utils.c @@ -13,12 +13,16 @@ #ifdef _MSC_VER #include #define isnan _isnan + +/* define fmaxf & fminf if < VC12 */ +#if _MSC_VER < 1800 __forceinline const float fmaxf(const float a, const float b) { return (a > b) ? a : b; } __forceinline const float fminf(const float a, const float b) { return (a < b) ? a : b; } +#endif #endif /** START_GENERATED **/ diff --git a/src/Layout.c b/src/Layout.c index bc39dc0c..8f0c14a1 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -17,10 +17,14 @@ #ifdef _MSC_VER #include #define isnan _isnan + +/* define fmaxf if < VC12 */ +#if _MSC_VER < 1800 __forceinline const float fmaxf(const float a, const float b) { return (a > b) ? a : b; } #endif +#endif bool isUndefined(float value) { return isnan(value);