Merge pull request #79 from prenaux/master

[Issue facebook/css-layout#78]: Implemented alignContent ;
This commit is contained in:
Christopher Chedeau
2015-05-17 08:58:05 -07:00
17 changed files with 1078 additions and 94 deletions

View File

@@ -54,6 +54,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<CSSNode> mChildren = new ArrayList<CSSNode>(4);

View File

@@ -16,6 +16,7 @@ public class CSSStyle {
public CSSDirection direction = CSSDirection.INHERIT;
public CSSFlexDirection flexDirection = CSSFlexDirection.COLUMN;
public CSSJustify justifyContent = CSSJustify.FLEX_START;
public CSSAlign alignContent = CSSAlign.FLEX_START;
public CSSAlign alignItems = CSSAlign.STRETCH;
public CSSAlign alignSelf = CSSAlign.AUTO;
public CSSPositionType positionType = CSSPositionType.RELATIVE;

View File

@@ -449,6 +449,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;
}
@@ -626,6 +630,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()) {
// <Loop A> Layout non flexible children and count children by type
@@ -811,6 +816,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))) {
@@ -856,7 +862,6 @@ public class LayoutEngine {
}
// <Loop D> Position elements in the cross axis
for (i = startLine; i < endLine; ++i) {
child = node.getChildAt(i);
@@ -915,9 +920,92 @@ public class LayoutEngine {
linesCrossDim = linesCrossDim + crossDim;
linesMainDim = Math.max(linesMainDim, mainDim);
linesCount = linesCount + 1;
startLine = endLine;
}
// <Loop E>
//
// Note(prenaux): More than one line, we need to layout the crossAxis
// according to alignContent.
//
// Note that we could probably remove <Loop D> 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 remainingAlignContentDim = nodeCrossAxisInnerSize - linesCrossDim;
float crossDimLead = 0;
float currentLead = getLeadingPaddingAndBorder(node, crossAxis);
CSSAlign alignContent = getAlignContent(node);
if (alignContent == CSSAlign.FLEX_END) {
currentLead = currentLead + remainingAlignContentDim;
} else if (alignContent == CSSAlign.CENTER) {
currentLead = currentLead + remainingAlignContentDim / 2;
} else if (alignContent == CSSAlign.STRETCH) {
if (nodeCrossAxisInnerSize > linesCrossDim) {
crossDimLead = (remainingAlignContentDim / linesCount);
}
}
int endIndex = 0;
for (i = 0; i < linesCount; ++i) {
int startIndex = endIndex;
// 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 != i) {
break;
}
if (!CSSConstants.isUndefined(getLayoutDimension(child, getDim(crossAxis)))) {
lineHeight = Math.max(
lineHeight,
getLayoutDimension(child, getDim(crossAxis)) + getMarginAxis(child, crossAxis)
);
}
}
endIndex = ii;
lineHeight = lineHeight + crossDimLead;
for (ii = startIndex; ii < endIndex; ++ii) {
child = node.getChildAt(ii);
if (getPositionType(child) != CSSPositionType.RELATIVE) {
continue;
}
CSSAlign alignContentAlignItem = getAlignItem(node, child);
if (alignContentAlignItem == CSSAlign.FLEX_START) {
setLayoutPosition(child, getPos(crossAxis), currentLead + getLeadingMargin(child, crossAxis));
} else if (alignContentAlignItem == CSSAlign.FLEX_END) {
setLayoutPosition(child, getPos(crossAxis), currentLead + lineHeight - getTrailingMargin(child, crossAxis) - getLayoutDimension(child, getDim(crossAxis)));
} else if (alignContentAlignItem == CSSAlign.CENTER) {
float childHeight = getLayoutDimension(child, getDim(crossAxis));
setLayoutPosition(child, getPos(crossAxis), currentLead + (lineHeight - childHeight) / 2);
} else if (alignContentAlignItem == CSSAlign.STRETCH) {
setLayoutPosition(child, getPos(crossAxis), currentLead + getLeadingMargin(child, crossAxis));
// TODO(prenaux): Correctly set the height of items with undefined
// (auto) crossAxis dimension.
}
}
currentLead = currentLead + lineHeight;
}
}
boolean needsMainTrailingPos = false;
boolean needsCrossTrailingPos = false;
@@ -947,8 +1035,7 @@ public class LayoutEngine {
needsCrossTrailingPos = true;
}
// <Loop E> Set trailing position if necessary
// <Loop F> Set trailing position if necessary
if (needsMainTrailingPos || needsCrossTrailingPos) {
for (i = 0; i < node.getChildCount(); ++i) {
child = node.getChildAt(i);
@@ -963,8 +1050,7 @@ public class LayoutEngine {
}
}
// <Loop F> Calculate dimensions for absolutely positioned elements
// <Loop G> Calculate dimensions for absolutely positioned elements
for (i = 0; i < node.getChildCount(); ++i) {
child = node.getChildAt(i);
if (getPositionType(child) == CSSPositionType.ABSOLUTE) {

View File

@@ -4230,7 +4230,7 @@ public class LayoutEngineTest {
TestCSSNode node_0 = root_layout;
node_0.layout.top = 0;
node_0.layout.left = 0;
node_0.layout.width = 34.671875f;
node_0.layout.width = 35;
node_0.layout.height = 18;
}
@@ -4275,7 +4275,7 @@ public class LayoutEngineTest {
TestCSSNode node_0 = root_layout;
node_0.layout.top = 0;
node_0.layout.left = 0;
node_0.layout.width = 172.421875f;
node_0.layout.width = 172;
node_0.layout.height = 18;
}
@@ -4469,7 +4469,7 @@ public class LayoutEngineTest {
node_0.layout.top = 0;
node_0.layout.left = 0;
node_0.layout.width = 130;
node_0.layout.height = 36;
node_0.layout.height = 37;
addChildren(node_0, 1);
{
TestCSSNode node_1;
@@ -4477,7 +4477,7 @@ public class LayoutEngineTest {
node_1.layout.top = 0;
node_1.layout.left = 0;
node_1.layout.width = 130;
node_1.layout.height = 36;
node_1.layout.height = 37;
addChildren(node_1, 1);
{
TestCSSNode node_2;
@@ -4485,7 +4485,7 @@ public class LayoutEngineTest {
node_2.layout.top = 0;
node_2.layout.left = 0;
node_2.layout.width = 130;
node_2.layout.height = 36;
node_2.layout.height = 37;
}
}
}
@@ -4523,7 +4523,7 @@ public class LayoutEngineTest {
node_0.layout.top = 0;
node_0.layout.left = 0;
node_0.layout.width = 200;
node_0.layout.height = 36;
node_0.layout.height = 37;
addChildren(node_0, 1);
{
TestCSSNode node_1;
@@ -4531,7 +4531,7 @@ public class LayoutEngineTest {
node_1.layout.top = 0;
node_1.layout.left = 0;
node_1.layout.width = 200;
node_1.layout.height = 36;
node_1.layout.height = 37;
addChildren(node_1, 1);
{
TestCSSNode node_2;
@@ -4539,7 +4539,7 @@ public class LayoutEngineTest {
node_2.layout.top = 0;
node_2.layout.left = 0;
node_2.layout.width = 130;
node_2.layout.height = 36;
node_2.layout.height = 37;
}
}
}
@@ -4571,15 +4571,15 @@ public class LayoutEngineTest {
node_0.layout.top = 0;
node_0.layout.left = 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.top = 0;
node_1.layout.left = 0;
node_1.layout.width = 100.4375f;
node_1.layout.height = 36;
node_1.layout.width = 100;
node_1.layout.height = 37;
}
}
@@ -4627,23 +4627,23 @@ public class LayoutEngineTest {
node_0.layout.top = 0;
node_0.layout.left = 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.top = 20;
node_1.layout.left = 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.top = 0;
node_2.layout.left = 0;
node_2.layout.width = 100.4375f;
node_2.layout.height = 36;
node_2.layout.width = 100;
node_2.layout.height = 37;
}
}
}
@@ -4864,7 +4864,7 @@ public class LayoutEngineTest {
node_2 = node_1.getChildAt(0);
node_2.layout.top = 20;
node_2.layout.left = 20;
node_2.layout.width = 172.421875f;
node_2.layout.width = 172;
node_2.layout.height = 18;
}
}
@@ -4922,8 +4922,8 @@ public class LayoutEngineTest {
TestCSSNode node_2;
node_2 = node_1.getChildAt(0);
node_2.layout.top = 20;
node_2.layout.left = 7.578125f;
node_2.layout.width = 172.421875f;
node_2.layout.left = 8;
node_2.layout.width = 172;
node_2.layout.height = 18;
}
}
@@ -4965,7 +4965,7 @@ public class LayoutEngineTest {
node_0.layout.top = 0;
node_0.layout.left = 0;
node_0.layout.width = 200;
node_0.layout.height = 76;
node_0.layout.height = 77;
addChildren(node_0, 1);
{
TestCSSNode node_1;
@@ -4973,7 +4973,7 @@ public class LayoutEngineTest {
node_1.layout.top = 0;
node_1.layout.left = 0;
node_1.layout.width = 200;
node_1.layout.height = 76;
node_1.layout.height = 77;
addChildren(node_1, 1);
{
TestCSSNode node_2;
@@ -4981,7 +4981,7 @@ public class LayoutEngineTest {
node_2.layout.top = 20;
node_2.layout.left = 20;
node_2.layout.width = 160;
node_2.layout.height = 36;
node_2.layout.height = 37;
}
}
}
@@ -7896,5 +7896,252 @@ public class LayoutEngineTest {
test("should layout node with correct start/end border in rtl", root_node, root_layout);
}
@Test
public void testCase177()
{
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.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(1);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(2);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(3);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(4);
node_1.style.width = 50;
node_1.style.height = 100;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
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.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(6);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(7);
node_1.style.width = 50;
node_1.style.height = 100;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(8);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(9);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
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.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(11);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(12);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
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.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
node_1 = node_0.getChildAt(14);
node_1.style.width = 50;
node_1.style.height = 50;
node_1.setMargin(Spacing.LEFT, 10);
node_1.setMargin(Spacing.TOP, 10);
node_1.setMargin(Spacing.RIGHT, 10);
node_1.setMargin(Spacing.BOTTOM, 10);
node_1.setMargin(Spacing.START, 10);
node_1.setMargin(Spacing.END, 10);
}
}
TestCSSNode root_layout = new TestCSSNode();
{
TestCSSNode node_0 = root_layout;
node_0.layout.top = 0;
node_0.layout.left = 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.top = 10;
node_1.layout.left = 10;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(1);
node_1.layout.top = 10;
node_1.layout.left = 80;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(2);
node_1.layout.top = 10;
node_1.layout.left = 150;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(3);
node_1.layout.top = 10;
node_1.layout.left = 220;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(4);
node_1.layout.top = 92.5f;
node_1.layout.left = 10;
node_1.layout.width = 50;
node_1.layout.height = 100;
node_1 = node_0.getChildAt(5);
node_1.layout.top = 92.5f;
node_1.layout.left = 80;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(6);
node_1.layout.top = 92.5f;
node_1.layout.left = 150;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(7);
node_1.layout.top = 92.5f;
node_1.layout.left = 220;
node_1.layout.width = 50;
node_1.layout.height = 100;
node_1 = node_0.getChildAt(8);
node_1.layout.top = 225;
node_1.layout.left = 10;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(9);
node_1.layout.top = 225;
node_1.layout.left = 80;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(10);
node_1.layout.top = 225;
node_1.layout.left = 150;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(11);
node_1.layout.top = 225;
node_1.layout.left = 220;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(12);
node_1.layout.top = 307.5f;
node_1.layout.left = 10;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(13);
node_1.layout.top = 307.5f;
node_1.layout.left = 80;
node_1.layout.width = 50;
node_1.layout.height = 50;
node_1 = node_0.getChildAt(14);
node_1.layout.top = 307.5f;
node_1.layout.left = 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 **/
}

View File

@@ -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 **/