Fix align-content strech with multiple lines

Summary: This is an update of facebook/yoga#368 which was reverted. It fixes support for align-content: strech with multiple lines. The problem with the last attempt at solving this was that align-items:stretch was interfering. We handle this now by detecting when the flex basis of the children hints at them overflowing. This is not 100% correct as the size of the items could change when remeasuring but it will work in 99% of cases.

Reviewed By: astreet

Differential Revision: D4551234

fbshipit-source-id: 2964f19cf415991dc55dfa2caa4868cb00c56bd0
This commit is contained in:
Emil Sjolander
2017-02-14 09:16:59 -08:00
committed by Facebook Github Bot
parent ad3963daa6
commit a1c75454e9
13 changed files with 5587 additions and 235 deletions

View File

@@ -26,7 +26,8 @@ typedef void (^YGLayoutConfigurationBlock)(YGLayout *);
to your code. If you plan on making multiple changes to YGLayout, it's more performant to your code. If you plan on making multiple changes to YGLayout, it's more performant
to use this method, which uses a single objc_msgSend call. to use this method, which uses a single objc_msgSend call.
*/ */
- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block NS_SWIFT_NAME(configureLayout(block:)); - (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block
NS_SWIFT_NAME(configureLayout(block:));
@end @end

View File

@@ -92,7 +92,8 @@
Perform a layout calculation and update the frames of the views in the hierarchy with the results. Perform a layout calculation and update the frames of the views in the hierarchy with the results.
If the origin is not preserved, the root view's layout results will applied from {0,0}. If the origin is not preserved, the root view's layout results will applied from {0,0}.
*/ */
- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin NS_SWIFT_NAME(applyLayout(preservingOrigin:)); - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin
NS_SWIFT_NAME(applyLayout(preservingOrigin:));
/** /**
Returns the size of the view if no constraints were given. This could equivalent to calling [self Returns the size of the view if no constraints were given. This could equivalent to calling [self

File diff suppressed because it is too large Load Diff

View File

@@ -410,5 +410,139 @@ namespace Facebook.Yoga
Assert.AreEqual(50f, root_child1.LayoutHeight); Assert.AreEqual(50f, root_child1.LayoutHeight);
} }
[Test]
public void Test_flex_wrap_wrap_to_child_height()
{
YogaNode root = new YogaNode();
YogaNode root_child0 = new YogaNode();
root_child0.FlexDirection = YogaFlexDirection.Row;
root_child0.AlignItems = YogaAlign.FlexStart;
root_child0.Wrap = YogaWrap.Wrap;
root.Insert(0, root_child0);
YogaNode root_child0_child0 = new YogaNode();
root_child0_child0.Width = 100;
root_child0.Insert(0, root_child0_child0);
YogaNode root_child0_child0_child0 = new YogaNode();
root_child0_child0_child0.Width = 100;
root_child0_child0_child0.Height = 100;
root_child0_child0.Insert(0, root_child0_child0_child0);
YogaNode root_child1 = new YogaNode();
root_child1.Width = 100;
root_child1.Height = 100;
root.Insert(1, root_child1);
root.StyleDirection = YogaDirection.LTR;
root.CalculateLayout();
Assert.AreEqual(0f, root.LayoutX);
Assert.AreEqual(0f, root.LayoutY);
Assert.AreEqual(100f, root.LayoutWidth);
Assert.AreEqual(200f, root.LayoutHeight);
Assert.AreEqual(0f, root_child0.LayoutX);
Assert.AreEqual(0f, root_child0.LayoutY);
Assert.AreEqual(100f, root_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0.LayoutHeight);
Assert.AreEqual(0f, root_child0_child0.LayoutX);
Assert.AreEqual(0f, root_child0_child0.LayoutY);
Assert.AreEqual(100f, root_child0_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0_child0.LayoutHeight);
Assert.AreEqual(0f, root_child0_child0_child0.LayoutX);
Assert.AreEqual(0f, root_child0_child0_child0.LayoutY);
Assert.AreEqual(100f, root_child0_child0_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0_child0_child0.LayoutHeight);
Assert.AreEqual(0f, root_child1.LayoutX);
Assert.AreEqual(100f, root_child1.LayoutY);
Assert.AreEqual(100f, root_child1.LayoutWidth);
Assert.AreEqual(100f, root_child1.LayoutHeight);
root.StyleDirection = YogaDirection.RTL;
root.CalculateLayout();
Assert.AreEqual(0f, root.LayoutX);
Assert.AreEqual(0f, root.LayoutY);
Assert.AreEqual(100f, root.LayoutWidth);
Assert.AreEqual(200f, root.LayoutHeight);
Assert.AreEqual(0f, root_child0.LayoutX);
Assert.AreEqual(0f, root_child0.LayoutY);
Assert.AreEqual(100f, root_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0.LayoutHeight);
Assert.AreEqual(0f, root_child0_child0.LayoutX);
Assert.AreEqual(0f, root_child0_child0.LayoutY);
Assert.AreEqual(100f, root_child0_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0_child0.LayoutHeight);
Assert.AreEqual(0f, root_child0_child0_child0.LayoutX);
Assert.AreEqual(0f, root_child0_child0_child0.LayoutY);
Assert.AreEqual(100f, root_child0_child0_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0_child0_child0.LayoutHeight);
Assert.AreEqual(0f, root_child1.LayoutX);
Assert.AreEqual(100f, root_child1.LayoutY);
Assert.AreEqual(100f, root_child1.LayoutWidth);
Assert.AreEqual(100f, root_child1.LayoutHeight);
}
[Test]
public void Test_flex_wrap_align_stretch_fits_one_row()
{
YogaNode root = new YogaNode();
root.FlexDirection = YogaFlexDirection.Row;
root.Wrap = YogaWrap.Wrap;
root.Width = 150;
root.Height = 100;
YogaNode root_child0 = new YogaNode();
root_child0.Width = 50;
root.Insert(0, root_child0);
YogaNode root_child1 = new YogaNode();
root_child1.Width = 50;
root.Insert(1, root_child1);
root.StyleDirection = YogaDirection.LTR;
root.CalculateLayout();
Assert.AreEqual(0f, root.LayoutX);
Assert.AreEqual(0f, root.LayoutY);
Assert.AreEqual(150f, root.LayoutWidth);
Assert.AreEqual(100f, root.LayoutHeight);
Assert.AreEqual(0f, root_child0.LayoutX);
Assert.AreEqual(0f, root_child0.LayoutY);
Assert.AreEqual(50f, root_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0.LayoutHeight);
Assert.AreEqual(50f, root_child1.LayoutX);
Assert.AreEqual(0f, root_child1.LayoutY);
Assert.AreEqual(50f, root_child1.LayoutWidth);
Assert.AreEqual(100f, root_child1.LayoutHeight);
root.StyleDirection = YogaDirection.RTL;
root.CalculateLayout();
Assert.AreEqual(0f, root.LayoutX);
Assert.AreEqual(0f, root.LayoutY);
Assert.AreEqual(150f, root.LayoutWidth);
Assert.AreEqual(100f, root.LayoutHeight);
Assert.AreEqual(100f, root_child0.LayoutX);
Assert.AreEqual(0f, root_child0.LayoutY);
Assert.AreEqual(50f, root_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0.LayoutHeight);
Assert.AreEqual(50f, root_child1.LayoutX);
Assert.AreEqual(0f, root_child1.LayoutY);
Assert.AreEqual(50f, root_child1.LayoutWidth);
Assert.AreEqual(100f, root_child1.LayoutHeight);
}
} }
} }

View File

@@ -6,15 +6,23 @@
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
</div> </div>
<div id="align_content_flex_end" style="width: 130px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: flex-end;"> <div id="align_content_flex_start_without_height_on_children" style="width: 100px; height: 100px; flex-wrap: wrap; flex-direction: column; align-content: flex-start;">
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px;"></div>
<div style="width: 50px; height: 10px;"></div>
<div style="width: 50px; height: 10px;"></div>
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
<div style="width: 50px;"></div>
</div> </div>
<div id="align_content_center" style="width: 130px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: center;"> <div id="align_content_flex_start_with_flex" style="width: 100px; height: 120px; flex-wrap: wrap; flex-direction: column; align-content: flex-start;">
<div style="width: 50px; flex: 1; flex-shrink: 0;"></div>
<div style="width: 50px; flex: 1; height: 10px; flex-shrink: 0;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px; flex: 1;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_flex_end" style="width: 100px; height: 100px; flex-wrap: wrap; flex-direction: column; align-content: flex-end;">
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
@@ -45,3 +53,92 @@
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
<div style="width: 50px; height: 10px;"></div> <div style="width: 50px; height: 10px;"></div>
</div> </div>
<div id="align_content_stretch_row" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_children" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;">
<div style="flex: 1;"></div>
</div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_flex" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px; flex: 1;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px; flex: 1;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_flex_no_shrink" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px; flex: 1;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px; flex: 1; flex-shrink: 0;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_margin" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px; margin: 10px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px; margin: 10px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_padding" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px; padding: 10px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px; padding: 10px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_single_row" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_fixed_height" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px; height: 60px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_max_height" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px; max-height: 20px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_row_with_min_height" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row; align-content: stretch;">
<div style="width: 50px;"></div>
<div style="width: 50px; min-height: 80px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
</div>
<div id="align_content_stretch_column" style="width: 100px; height: 150px; flex-wrap: wrap; flex-direction: column; align-content: stretch;">
<div style="height: 50px;">
<div style="flex: 1;"></div>
</div>
<div style="height: 50px; flex: 1;"></div>
<div style="height: 50px;"></div>
<div style="height: 50px;"></div>
<div style="height: 50px;"></div>
</div>

View File

@@ -30,3 +30,17 @@
<div style="flex-basis: 50px; height: 50px; min-width: 55px;"></div> <div style="flex-basis: 50px; height: 50px; min-width: 55px;"></div>
<div style="flex-basis: 50px; height: 50px; min-width: 55px;"></div> <div style="flex-basis: 50px; height: 50px; min-width: 55px;"></div>
</div> </div>
<div id="flex_wrap_wrap_to_child_height">
<div style="flex-direction: row; align-items: flex-start; flex-wrap: wrap;">
<div style="width: 100px;">
<div style="height: 100px; width: 100px;"></div>
</div>
</div>
<div style="width: 100px; height: 100px;"></div>
</div>
<div id="flex_wrap_align_stretch_fits_one_row" style="width: 150px; height: 100px; flex-wrap: wrap; flex-direction: row;">
<div style="width: 50px;"></div>
<div style="width: 50px;"></div>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -404,4 +404,136 @@ public class YGFlexWrapTest {
assertEquals(50f, root_child1.getLayoutHeight(), 0.0f); assertEquals(50f, root_child1.getLayoutHeight(), 0.0f);
} }
@Test
public void test_flex_wrap_wrap_to_child_height() {
final YogaNode root = new YogaNode();
final YogaNode root_child0 = new YogaNode();
root_child0.setFlexDirection(YogaFlexDirection.ROW);
root_child0.setAlignItems(YogaAlign.FLEX_START);
root_child0.setWrap(YogaWrap.WRAP);
root.addChildAt(root_child0, 0);
final YogaNode root_child0_child0 = new YogaNode();
root_child0_child0.setWidth(100f);
root_child0.addChildAt(root_child0_child0, 0);
final YogaNode root_child0_child0_child0 = new YogaNode();
root_child0_child0_child0.setWidth(100f);
root_child0_child0_child0.setHeight(100f);
root_child0_child0.addChildAt(root_child0_child0_child0, 0);
final YogaNode root_child1 = new YogaNode();
root_child1.setWidth(100f);
root_child1.setHeight(100f);
root.addChildAt(root_child1, 1);
root.setDirection(YogaDirection.LTR);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertEquals(0f, root.getLayoutX(), 0.0f);
assertEquals(0f, root.getLayoutY(), 0.0f);
assertEquals(100f, root.getLayoutWidth(), 0.0f);
assertEquals(200f, root.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0_child0_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0_child0_child0.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child1.getLayoutX(), 0.0f);
assertEquals(100f, root_child1.getLayoutY(), 0.0f);
assertEquals(100f, root_child1.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child1.getLayoutHeight(), 0.0f);
root.setDirection(YogaDirection.RTL);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertEquals(0f, root.getLayoutX(), 0.0f);
assertEquals(0f, root.getLayoutY(), 0.0f);
assertEquals(100f, root.getLayoutWidth(), 0.0f);
assertEquals(200f, root.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0_child0_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0_child0_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0_child0_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0_child0_child0.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child1.getLayoutX(), 0.0f);
assertEquals(100f, root_child1.getLayoutY(), 0.0f);
assertEquals(100f, root_child1.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child1.getLayoutHeight(), 0.0f);
}
@Test
public void test_flex_wrap_align_stretch_fits_one_row() {
final YogaNode root = new YogaNode();
root.setFlexDirection(YogaFlexDirection.ROW);
root.setWrap(YogaWrap.WRAP);
root.setWidth(150f);
root.setHeight(100f);
final YogaNode root_child0 = new YogaNode();
root_child0.setWidth(50f);
root.addChildAt(root_child0, 0);
final YogaNode root_child1 = new YogaNode();
root_child1.setWidth(50f);
root.addChildAt(root_child1, 1);
root.setDirection(YogaDirection.LTR);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertEquals(0f, root.getLayoutX(), 0.0f);
assertEquals(0f, root.getLayoutY(), 0.0f);
assertEquals(150f, root.getLayoutWidth(), 0.0f);
assertEquals(100f, root.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0.getLayoutY(), 0.0f);
assertEquals(50f, root_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0.getLayoutHeight(), 0.0f);
assertEquals(50f, root_child1.getLayoutX(), 0.0f);
assertEquals(0f, root_child1.getLayoutY(), 0.0f);
assertEquals(50f, root_child1.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child1.getLayoutHeight(), 0.0f);
root.setDirection(YogaDirection.RTL);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertEquals(0f, root.getLayoutX(), 0.0f);
assertEquals(0f, root.getLayoutY(), 0.0f);
assertEquals(150f, root.getLayoutWidth(), 0.0f);
assertEquals(100f, root.getLayoutHeight(), 0.0f);
assertEquals(100f, root_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0.getLayoutY(), 0.0f);
assertEquals(50f, root_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0.getLayoutHeight(), 0.0f);
assertEquals(50f, root_child1.getLayoutX(), 0.0f);
assertEquals(0f, root_child1.getLayoutY(), 0.0f);
assertEquals(50f, root_child1.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child1.getLayoutHeight(), 0.0f);
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -409,3 +409,139 @@ it("flex_wrap_children_with_min_main_overriding_flex_basis", function () {
(typeof gc !== "undefined") && gc(); (typeof gc !== "undefined") && gc();
console.assert(0 === Yoga.getInstanceCount(), "0 === Yoga.getInstanceCount() (" + Yoga.getInstanceCount() + ")"); console.assert(0 === Yoga.getInstanceCount(), "0 === Yoga.getInstanceCount() (" + Yoga.getInstanceCount() + ")");
}); });
it("flex_wrap_wrap_to_child_height", function () {
var root = Yoga.Node.create();
var root_child0 = Yoga.Node.create();
root_child0.setFlexDirection(Yoga.FLEX_DIRECTION_ROW);
root_child0.setAlignItems(Yoga.ALIGN_FLEX_START);
root_child0.setFlexWrap(Yoga.WRAP_WRAP);
root.insertChild(root_child0, 0);
var root_child0_child0 = Yoga.Node.create();
root_child0_child0.setWidth(100);
root_child0.insertChild(root_child0_child0, 0);
var root_child0_child0_child0 = Yoga.Node.create();
root_child0_child0_child0.setWidth(100);
root_child0_child0_child0.setHeight(100);
root_child0_child0.insertChild(root_child0_child0_child0, 0);
var root_child1 = Yoga.Node.create();
root_child1.setWidth(100);
root_child1.setHeight(100);
root.insertChild(root_child1, 1);
root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_LTR);
console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")");
console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")");
console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")");
console.assert(200 === root.getComputedHeight(), "200 === root.getComputedHeight() (" + root.getComputedHeight() + ")");
console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")");
console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")");
console.assert(100 === root_child0.getComputedWidth(), "100 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")");
console.assert(100 === root_child0.getComputedHeight(), "100 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")");
console.assert(0 === root_child0_child0.getComputedLeft(), "0 === root_child0_child0.getComputedLeft() (" + root_child0_child0.getComputedLeft() + ")");
console.assert(0 === root_child0_child0.getComputedTop(), "0 === root_child0_child0.getComputedTop() (" + root_child0_child0.getComputedTop() + ")");
console.assert(100 === root_child0_child0.getComputedWidth(), "100 === root_child0_child0.getComputedWidth() (" + root_child0_child0.getComputedWidth() + ")");
console.assert(100 === root_child0_child0.getComputedHeight(), "100 === root_child0_child0.getComputedHeight() (" + root_child0_child0.getComputedHeight() + ")");
console.assert(0 === root_child0_child0_child0.getComputedLeft(), "0 === root_child0_child0_child0.getComputedLeft() (" + root_child0_child0_child0.getComputedLeft() + ")");
console.assert(0 === root_child0_child0_child0.getComputedTop(), "0 === root_child0_child0_child0.getComputedTop() (" + root_child0_child0_child0.getComputedTop() + ")");
console.assert(100 === root_child0_child0_child0.getComputedWidth(), "100 === root_child0_child0_child0.getComputedWidth() (" + root_child0_child0_child0.getComputedWidth() + ")");
console.assert(100 === root_child0_child0_child0.getComputedHeight(), "100 === root_child0_child0_child0.getComputedHeight() (" + root_child0_child0_child0.getComputedHeight() + ")");
console.assert(0 === root_child1.getComputedLeft(), "0 === root_child1.getComputedLeft() (" + root_child1.getComputedLeft() + ")");
console.assert(100 === root_child1.getComputedTop(), "100 === root_child1.getComputedTop() (" + root_child1.getComputedTop() + ")");
console.assert(100 === root_child1.getComputedWidth(), "100 === root_child1.getComputedWidth() (" + root_child1.getComputedWidth() + ")");
console.assert(100 === root_child1.getComputedHeight(), "100 === root_child1.getComputedHeight() (" + root_child1.getComputedHeight() + ")");
root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_RTL);
console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")");
console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")");
console.assert(100 === root.getComputedWidth(), "100 === root.getComputedWidth() (" + root.getComputedWidth() + ")");
console.assert(200 === root.getComputedHeight(), "200 === root.getComputedHeight() (" + root.getComputedHeight() + ")");
console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")");
console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")");
console.assert(100 === root_child0.getComputedWidth(), "100 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")");
console.assert(100 === root_child0.getComputedHeight(), "100 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")");
console.assert(0 === root_child0_child0.getComputedLeft(), "0 === root_child0_child0.getComputedLeft() (" + root_child0_child0.getComputedLeft() + ")");
console.assert(0 === root_child0_child0.getComputedTop(), "0 === root_child0_child0.getComputedTop() (" + root_child0_child0.getComputedTop() + ")");
console.assert(100 === root_child0_child0.getComputedWidth(), "100 === root_child0_child0.getComputedWidth() (" + root_child0_child0.getComputedWidth() + ")");
console.assert(100 === root_child0_child0.getComputedHeight(), "100 === root_child0_child0.getComputedHeight() (" + root_child0_child0.getComputedHeight() + ")");
console.assert(0 === root_child0_child0_child0.getComputedLeft(), "0 === root_child0_child0_child0.getComputedLeft() (" + root_child0_child0_child0.getComputedLeft() + ")");
console.assert(0 === root_child0_child0_child0.getComputedTop(), "0 === root_child0_child0_child0.getComputedTop() (" + root_child0_child0_child0.getComputedTop() + ")");
console.assert(100 === root_child0_child0_child0.getComputedWidth(), "100 === root_child0_child0_child0.getComputedWidth() (" + root_child0_child0_child0.getComputedWidth() + ")");
console.assert(100 === root_child0_child0_child0.getComputedHeight(), "100 === root_child0_child0_child0.getComputedHeight() (" + root_child0_child0_child0.getComputedHeight() + ")");
console.assert(0 === root_child1.getComputedLeft(), "0 === root_child1.getComputedLeft() (" + root_child1.getComputedLeft() + ")");
console.assert(100 === root_child1.getComputedTop(), "100 === root_child1.getComputedTop() (" + root_child1.getComputedTop() + ")");
console.assert(100 === root_child1.getComputedWidth(), "100 === root_child1.getComputedWidth() (" + root_child1.getComputedWidth() + ")");
console.assert(100 === root_child1.getComputedHeight(), "100 === root_child1.getComputedHeight() (" + root_child1.getComputedHeight() + ")");
if (typeof root !== "undefined")
root.freeRecursive();
(typeof gc !== "undefined") && gc();
console.assert(0 === Yoga.getInstanceCount(), "0 === Yoga.getInstanceCount() (" + Yoga.getInstanceCount() + ")");
});
it("flex_wrap_align_stretch_fits_one_row", function () {
var root = Yoga.Node.create();
root.setFlexDirection(Yoga.FLEX_DIRECTION_ROW);
root.setFlexWrap(Yoga.WRAP_WRAP);
root.setWidth(150);
root.setHeight(100);
var root_child0 = Yoga.Node.create();
root_child0.setWidth(50);
root.insertChild(root_child0, 0);
var root_child1 = Yoga.Node.create();
root_child1.setWidth(50);
root.insertChild(root_child1, 1);
root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_LTR);
console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")");
console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")");
console.assert(150 === root.getComputedWidth(), "150 === root.getComputedWidth() (" + root.getComputedWidth() + ")");
console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")");
console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")");
console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")");
console.assert(50 === root_child0.getComputedWidth(), "50 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")");
console.assert(100 === root_child0.getComputedHeight(), "100 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")");
console.assert(50 === root_child1.getComputedLeft(), "50 === root_child1.getComputedLeft() (" + root_child1.getComputedLeft() + ")");
console.assert(0 === root_child1.getComputedTop(), "0 === root_child1.getComputedTop() (" + root_child1.getComputedTop() + ")");
console.assert(50 === root_child1.getComputedWidth(), "50 === root_child1.getComputedWidth() (" + root_child1.getComputedWidth() + ")");
console.assert(100 === root_child1.getComputedHeight(), "100 === root_child1.getComputedHeight() (" + root_child1.getComputedHeight() + ")");
root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_RTL);
console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")");
console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")");
console.assert(150 === root.getComputedWidth(), "150 === root.getComputedWidth() (" + root.getComputedWidth() + ")");
console.assert(100 === root.getComputedHeight(), "100 === root.getComputedHeight() (" + root.getComputedHeight() + ")");
console.assert(100 === root_child0.getComputedLeft(), "100 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")");
console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")");
console.assert(50 === root_child0.getComputedWidth(), "50 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")");
console.assert(100 === root_child0.getComputedHeight(), "100 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")");
console.assert(50 === root_child1.getComputedLeft(), "50 === root_child1.getComputedLeft() (" + root_child1.getComputedLeft() + ")");
console.assert(0 === root_child1.getComputedTop(), "0 === root_child1.getComputedTop() (" + root_child1.getComputedTop() + ")");
console.assert(50 === root_child1.getComputedWidth(), "50 === root_child1.getComputedWidth() (" + root_child1.getComputedWidth() + ")");
console.assert(100 === root_child1.getComputedHeight(), "100 === root_child1.getComputedHeight() (" + root_child1.getComputedHeight() + ")");
if (typeof root !== "undefined")
root.freeRecursive();
(typeof gc !== "undefined") && gc();
console.assert(0 === Yoga.getInstanceCount(), "0 === Yoga.getInstanceCount() (" + Yoga.getInstanceCount() + ")");
});

File diff suppressed because it is too large Load Diff

View File

@@ -394,3 +394,133 @@ TEST(YogaTest, flex_wrap_children_with_min_main_overriding_flex_basis) {
YGNodeFreeRecursive(root); YGNodeFreeRecursive(root);
} }
TEST(YogaTest, flex_wrap_wrap_to_child_height) {
const YGNodeRef root = YGNodeNew();
const YGNodeRef root_child0 = YGNodeNew();
YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow);
YGNodeStyleSetAlignItems(root_child0, YGAlignFlexStart);
YGNodeStyleSetFlexWrap(root_child0, YGWrapWrap);
YGNodeInsertChild(root, root_child0, 0);
const YGNodeRef root_child0_child0 = YGNodeNew();
YGNodeStyleSetWidth(root_child0_child0, 100);
YGNodeInsertChild(root_child0, root_child0_child0, 0);
const YGNodeRef root_child0_child0_child0 = YGNodeNew();
YGNodeStyleSetWidth(root_child0_child0_child0, 100);
YGNodeStyleSetHeight(root_child0_child0_child0, 100);
YGNodeInsertChild(root_child0_child0, root_child0_child0_child0, 0);
const YGNodeRef root_child1 = YGNodeNew();
YGNodeStyleSetWidth(root_child1, 100);
YGNodeStyleSetHeight(root_child1, 100);
YGNodeInsertChild(root, root_child1, 1);
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(200, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetTop(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
YGNodeFreeRecursive(root);
}
TEST(YogaTest, flex_wrap_align_stretch_fits_one_row) {
const YGNodeRef root = YGNodeNew();
YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow);
YGNodeStyleSetFlexWrap(root, YGWrapWrap);
YGNodeStyleSetWidth(root, 150);
YGNodeStyleSetHeight(root, 100);
const YGNodeRef root_child0 = YGNodeNew();
YGNodeStyleSetWidth(root_child0, 50);
YGNodeInsertChild(root, root_child0, 0);
const YGNodeRef root_child1 = YGNodeNew();
YGNodeStyleSetWidth(root_child1, 50);
YGNodeInsertChild(root, root_child1, 1);
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
ASSERT_FLOAT_EQ(150, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(50, YGNodeLayoutGetLeft(root_child1));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child1));
ASSERT_FLOAT_EQ(50, YGNodeLayoutGetWidth(root_child1));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child1));
YGNodeFreeRecursive(root);
}

View File

@@ -1956,6 +1956,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
} }
} }
float totalFlexBasis = 0;
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM // STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
for (uint32_t i = 0; i < childCount; i++) { for (uint32_t i = 0; i < childCount; i++) {
const YGNodeRef child = YGNodeListGet(node->children, i); const YGNodeRef child = YGNodeListGet(node->children, i);
@@ -2005,8 +2007,13 @@ static void YGNodelayoutImpl(const YGNodeRef node,
direction); direction);
} }
} }
totalFlexBasis += child->layout.computedFlexBasis;
} }
const bool flexBasisOverflows =
measureModeMainDim == YGMeasureModeUndefined ? false : totalFlexBasis > availableInnerMainDim;
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES // STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
// Indexes of children that represent the first and last items in the line. // Indexes of children that represent the first and last items in the line.
@@ -2287,6 +2294,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
YGFlexDirectionColumn, YGFlexDirectionColumn,
availableInnerHeight) && availableInnerHeight) &&
heightMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly &&
!(isNodeFlexWrap && flexBasisOverflows) &&
YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) { YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) {
childHeight = availableInnerCrossDim; childHeight = availableInnerCrossDim;
childHeightMeasureMode = YGMeasureModeExactly; childHeightMeasureMode = YGMeasureModeExactly;
@@ -2312,7 +2320,7 @@ static void YGNodelayoutImpl(const YGNodeRef node,
!YGNodeIsStyleDimDefined(currentRelativeChild, !YGNodeIsStyleDimDefined(currentRelativeChild,
YGFlexDirectionRow, YGFlexDirectionRow,
availableInnerWidth) && availableInnerWidth) &&
widthMeasureMode == YGMeasureModeExactly && widthMeasureMode == YGMeasureModeExactly && !(isNodeFlexWrap && flexBasisOverflows) &&
YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) { YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) {
childWidth = availableInnerCrossDim; childWidth = availableInnerCrossDim;
childWidthMeasureMode = YGMeasureModeExactly; childWidthMeasureMode = YGMeasureModeExactly;
@@ -2481,13 +2489,11 @@ static void YGNodelayoutImpl(const YGNodeRef node,
child->layout.computedFlexBasis; child->layout.computedFlexBasis;
crossDim = availableInnerCrossDim; crossDim = availableInnerCrossDim;
} else { } else {
// The main dimension is the sum of all the elements dimension plus // The main dimension is the sum of all the elements dimension plus the spacing.
// the spacing.
mainDim += betweenMainDim + YGNodeDimWithMargin(child, mainAxis, availableInnerWidth); mainDim += betweenMainDim + YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
// The cross dimension is the max of the elements dimension since // The cross dimension is the max of the elements dimension since
// there // there can only be one element in that cross dimension.
// can only be one element in that cross dimension.
crossDim = fmaxf(crossDim, YGNodeDimWithMargin(child, crossAxis, availableInnerWidth)); crossDim = fmaxf(crossDim, YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
} }
} else if (performLayout) { } else if (performLayout) {
@@ -2652,7 +2658,8 @@ static void YGNodelayoutImpl(const YGNodeRef node,
} }
// STEP 8: MULTI-LINE CONTENT ALIGNMENT // STEP 8: MULTI-LINE CONTENT ALIGNMENT
if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) && if (performLayout &&
(lineCount > 1 || node->style.alignContent == YGAlignStretch || YGIsBaselineLayout(node)) &&
!YGFloatIsUndefined(availableInnerCrossDim)) { !YGFloatIsUndefined(availableInnerCrossDim)) {
const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim; const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim;
@@ -2760,8 +2767,36 @@ static void YGNodelayoutImpl(const YGNodeRef node,
case YGAlignStretch: { case YGAlignStretch: {
child->layout.position[pos[crossAxis]] = child->layout.position[pos[crossAxis]] =
currentLead + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth); currentLead + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth);
// TODO(prenaux): Correctly set the height of items with indefinite
// (auto) crossAxis dimension. // Remeasure child with the line height as it as been only measured with the
// parents height yet.
if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) {
const float childWidth =
isMainAxisRow ? (child->layout.measuredDimensions[YGDimensionWidth] +
YGNodeMarginForAxis(child, crossAxis, availableInnerWidth))
: lineHeight;
const float childHeight =
!isMainAxisRow ? (child->layout.measuredDimensions[YGDimensionHeight] +
YGNodeMarginForAxis(child, crossAxis, availableInnerWidth))
: lineHeight;
if (!(YGFloatsEqual(childWidth,
child->layout.measuredDimensions[YGDimensionWidth]) &&
YGFloatsEqual(childHeight,
child->layout.measuredDimensions[YGDimensionHeight]))) {
YGLayoutNodeInternal(child,
childWidth,
childHeight,
direction,
YGMeasureModeExactly,
YGMeasureModeExactly,
availableInnerWidth,
availableInnerHeight,
true,
"stretch");
}
}
break; break;
} }
case YGAlignBaseline: { case YGAlignBaseline: {