From 010d1bb0c27b330615a9aebe85ed554e8b3c8b99 Mon Sep 17 00:00:00 2001 From: Pavel Mazurin Date: Fri, 28 Jul 2017 11:39:38 +0200 Subject: [PATCH 01/12] Fixes #606 --- YogaKit/Source/YGLayout.m | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index df4a4821..996504f3 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -304,10 +304,14 @@ static YGSize YGMeasureView( const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height; UIView *view = (__bridge UIView*) YGNodeGetContext(node); - const CGSize sizeThatFits = [view sizeThatFits:(CGSize) { - .width = constrainedWidth, - .height = constrainedHeight, - }]; + CGSize sizeThatFits = CGSizeZero; + + if ([view.subviews count] > 0) { + sizeThatFits = [view sizeThatFits:(CGSize) { + .width = constrainedWidth, + .height = constrainedHeight, + }]; + } return (YGSize) { .width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode), -- 2.50.1.windows.1 From 6366ee45ab6adfaf610a8ec2994d1bf1e90de6d9 Mon Sep 17 00:00:00 2001 From: Pavel Mazurin Date: Mon, 31 Jul 2017 15:43:15 +0200 Subject: [PATCH 02/12] Add unit test. Fix the layout for non-UIView subclasses --- YogaKit/Source/YGLayout.m | 3 ++- YogaKit/Tests/YogaKitTests.m | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index 996504f3..9cc4a6a7 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -306,7 +306,8 @@ static YGSize YGMeasureView( UIView *view = (__bridge UIView*) YGNodeGetContext(node); CGSize sizeThatFits = CGSizeZero; - if ([view.subviews count] > 0) { + // Fix for https://github.com/facebook/yoga/issues/606 + if (![view isMemberOfClass:[UIView class]] || [view.subviews count] > 0) { sizeThatFits = [view sizeThatFits:(CGSize) { .width = constrainedWidth, .height = constrainedHeight, diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index ed4169c5..b6c3b8a3 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -129,6 +129,16 @@ XCTAssertEqual(longTextLabelSize.width + textBadgeView.yoga.intrinsicSize.width, containerSize.width); } +- (void)testSizeThatFitsEmptyView +{ + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 200, 200)]; + view.yoga.isEnabled = YES; + + const CGSize viewSize = view.yoga.intrinsicSize; + XCTAssertEqual(viewSize.height, 0); + XCTAssertEqual(viewSize.width, 0); +} + - (void)testPreservingOrigin { UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,75)]; -- 2.50.1.windows.1 From 5edfb679e7361d6ddfea8cf4a50e01946d8b33dd Mon Sep 17 00:00:00 2001 From: Lior Tubi Date: Sun, 13 Aug 2017 07:26:14 -0700 Subject: [PATCH 03/12] Add a java binary buck target Summary: . Reviewed By: amir-shalem Differential Revision: D5619667 fbshipit-source-id: e956190be0c6a7ea573e5511231de28aab5586fe --- java/BUCK | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/java/BUCK b/java/BUCK index 83d58240..967110c1 100644 --- a/java/BUCK +++ b/java/BUCK @@ -58,3 +58,11 @@ java_test( JUNIT_TARGET, ], ) + +java_binary( + name = "yoga", + deps = [ + ":java", + FBJNI_JAVA_TARGET, + ], +) -- 2.50.1.windows.1 From 2ee2dd439fcd47e548a5171d3a7afe9ff515849a Mon Sep 17 00:00:00 2001 From: Levi McCallum Date: Thu, 17 Aug 2017 13:44:00 -0700 Subject: [PATCH 04/12] Fix link to YGLayout header in docs Summary: Closes https://github.com/facebook/yoga/pull/595 Reviewed By: amonshiz Differential Revision: D5643379 Pulled By: dshahidehpour fbshipit-source-id: ae972f270ee26fe7755ba5dee4d357d150a27c2a --- docs/_docs/api/yogakit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_docs/api/yogakit.md b/docs/_docs/api/yogakit.md index 796de28a..d4f42a0a 100644 --- a/docs/_docs/api/yogakit.md +++ b/docs/_docs/api/yogakit.md @@ -9,7 +9,7 @@ permalink: /docs/api/yogakit/ YogaKit is a Objective-C (and Swift-compatible) wrapper for Yoga. It allows iOS Developers to manage the layout of their views using the power of Yoga. -Layout configuration is done via the [YGLayout](https://github.com/facebook/yoga/blob/master/YogaKit/YGLayout.h) object. YogaKit exposes `YGLayout` via a [category](https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Category.html) on [UIView](https://developer.apple.com/reference/uikit/uiview). +Layout configuration is done via the [YGLayout](https://github.com/facebook/yoga/blob/master/YogaKit/Source/YGLayout.h) object. YogaKit exposes `YGLayout` via a [category](https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Category.html) on [UIView](https://developer.apple.com/reference/uikit/uiview). ### Lifecycle -- 2.50.1.windows.1 From 18d19af7ec716f09b267f9d60e059ef95f8eb89b Mon Sep 17 00:00:00 2001 From: Luc Dion Date: Thu, 17 Aug 2017 14:35:53 -0700 Subject: [PATCH 05/12] Fix a typo in YogaKit, Summary: `YGDimensionFlexibilityFlexibleHeight` it was wrongly spelled `YGDimensionFlexibilityFlexibleHeigth`. [X] Test suite passes [X] Contributor License Agreement Closes https://github.com/facebook/yoga/pull/605 Reviewed By: amonshiz Differential Revision: D5643382 Pulled By: dshahidehpour fbshipit-source-id: 127b0c11dbfd76d298db823e65fd2f6e365642e7 --- YogaKit/Source/YGLayout.h | 2 +- YogaKit/Source/YGLayout.m | 2 +- YogaKit/Tests/YogaKitTests.m | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/YogaKit/Source/YGLayout.h b/YogaKit/Source/YGLayout.h index 05d54a16..19b04d17 100644 --- a/YogaKit/Source/YGLayout.h +++ b/YogaKit/Source/YGLayout.h @@ -23,7 +23,7 @@ YG_EXTERN_C_END typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { YGDimensionFlexibilityFlexibleWidth = 1 << 0, - YGDimensionFlexibilityFlexibleHeigth = 1 << 1, + YGDimensionFlexibilityFlexibleHeight = 1 << 1, }; @interface YGLayout : NSObject diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index df4a4821..547c0eb2 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -254,7 +254,7 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) { size.width = YGUndefined; } - if (dimensionFlexibility & YGDimensionFlexibilityFlexibleHeigth) { + if (dimensionFlexibility & YGDimensionFlexibilityFlexibleHeight) { size.height = YGUndefined; } [self calculateLayoutWithSize:size]; diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index ed4169c5..d27e1faf 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -181,7 +181,7 @@ view.yoga.height = YGPointValue(100); [container addSubview:view]; - [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleHeigth]; + [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleHeight]; XCTAssertEqual(200, container.frame.size.width); XCTAssertEqual(100, container.frame.size.height); } @@ -197,7 +197,7 @@ view.yoga.height = YGPointValue(100); [container addSubview:view]; - [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth | YGDimensionFlexibilityFlexibleHeigth]; + [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth | YGDimensionFlexibilityFlexibleHeight]; XCTAssertEqual(100, container.frame.size.width); XCTAssertEqual(100, container.frame.size.height); } -- 2.50.1.windows.1 From 32f128640b383721bba2a31a623a3a8ed5ded60e Mon Sep 17 00:00:00 2001 From: Hoa Dinh Date: Thu, 17 Aug 2017 15:41:26 -0700 Subject: [PATCH 06/12] Revert D5643382: [yoga][PR] Fix a typo in YogaKit, Summary: This reverts commit 127b0c11dbfd76d298db823e65fd2f6e365642e7 bypass-lint Differential Revision: D5643382 fbshipit-source-id: f25b04680428bcd4515c44741ed72a004be43ef1 --- YogaKit/Source/YGLayout.h | 2 +- YogaKit/Source/YGLayout.m | 2 +- YogaKit/Tests/YogaKitTests.m | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/YogaKit/Source/YGLayout.h b/YogaKit/Source/YGLayout.h index 19b04d17..05d54a16 100644 --- a/YogaKit/Source/YGLayout.h +++ b/YogaKit/Source/YGLayout.h @@ -23,7 +23,7 @@ YG_EXTERN_C_END typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { YGDimensionFlexibilityFlexibleWidth = 1 << 0, - YGDimensionFlexibilityFlexibleHeight = 1 << 1, + YGDimensionFlexibilityFlexibleHeigth = 1 << 1, }; @interface YGLayout : NSObject diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index 547c0eb2..df4a4821 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -254,7 +254,7 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) { size.width = YGUndefined; } - if (dimensionFlexibility & YGDimensionFlexibilityFlexibleHeight) { + if (dimensionFlexibility & YGDimensionFlexibilityFlexibleHeigth) { size.height = YGUndefined; } [self calculateLayoutWithSize:size]; diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index d27e1faf..ed4169c5 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -181,7 +181,7 @@ view.yoga.height = YGPointValue(100); [container addSubview:view]; - [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleHeight]; + [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleHeigth]; XCTAssertEqual(200, container.frame.size.width); XCTAssertEqual(100, container.frame.size.height); } @@ -197,7 +197,7 @@ view.yoga.height = YGPointValue(100); [container addSubview:view]; - [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth | YGDimensionFlexibilityFlexibleHeight]; + [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth | YGDimensionFlexibilityFlexibleHeigth]; XCTAssertEqual(100, container.frame.size.width); XCTAssertEqual(100, container.frame.size.height); } -- 2.50.1.windows.1 From 35a9f33abb85f08530df0e6b58eba50311c5e752 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Mon, 21 Aug 2017 03:09:09 -0700 Subject: [PATCH 07/12] BREAKING: Change aspect ratio behavior Summary: @public == Before == - Aspect ratio would do its best to fit within it's parent constraints - Aspect ratio would prioritize `alignItems: stretch` over other sizing properties. == After == - Aspect ratio is allowed to make a node grow past its parent constraints. This matches many other aspects of flexbox where parent constraints are not treated as hard constraints but rather as suggestions. - Aspect ratio only takes `alignItems: stretch` into account if no other size definition is defined. This matches the interaction of other properties with `alignItems: stretch`. == Updating your code == **You probably don't need to do anything** but in case something does break in your product it should be as easy as adding `{width: '100%', height: '100%', flexShrink: 1}` to the style declaring the `aspectRatio`. Reviewed By: gkassabli Differential Revision: D5639187 fbshipit-source-id: 603e8fcc3373f0b7f2461da2dad1625ab59dcb19 --- tests/YGAspectRatioTest.cpp | 133 +++++++++++++++++++++++++- yoga/Yoga.c | 184 +++++++++++++++++++----------------- 2 files changed, 226 insertions(+), 91 deletions(-) diff --git a/tests/YGAspectRatioTest.cpp b/tests/YGAspectRatioTest.cpp index 49e3e052..b2fa37b8 100644 --- a/tests/YGAspectRatioTest.cpp +++ b/tests/YGAspectRatioTest.cpp @@ -171,6 +171,38 @@ TEST(YogaTest, aspect_ratio_flex_shrink) { YGNodeFreeRecursive(root); } +TEST(YogaTest, aspect_ratio_flex_shrink_2) { + const YGNodeRef root = YGNodeNew(); + YGNodeStyleSetWidth(root, 100); + YGNodeStyleSetHeight(root, 100); + + const YGNodeRef root_child0 = YGNodeNew(); + YGNodeStyleSetHeightPercent(root_child0, 100); + YGNodeStyleSetFlexShrink(root_child0, 1); + YGNodeStyleSetAspectRatio(root_child0, 1); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child1 = YGNodeNew(); + YGNodeStyleSetHeightPercent(root_child1, 100); + YGNodeStyleSetFlexShrink(root_child1, 1); + YGNodeStyleSetAspectRatio(root_child1, 1); + YGNodeInsertChild(root, root_child1, 1); + + YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR); + + ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0)); + ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0)); + ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0)); + ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child1)); + ASSERT_EQ(50, YGNodeLayoutGetTop(root_child1)); + ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child1)); + ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child1)); + + YGNodeFreeRecursive(root); +} + TEST(YogaTest, aspect_ratio_basis) { const YGNodeRef root = YGNodeNew(); YGNodeStyleSetAlignItems(root, YGAlignFlexStart); @@ -562,8 +594,8 @@ TEST(YogaTest, aspect_ratio_overrides_flex_grow_row) { ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0)); ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0)); - ASSERT_EQ(50, YGNodeLayoutGetWidth(root_child0)); - ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_EQ(200, YGNodeLayoutGetHeight(root_child0)); YGNodeFreeRecursive(root); } @@ -584,8 +616,8 @@ TEST(YogaTest, aspect_ratio_overrides_flex_grow_column) { ASSERT_EQ(0, YGNodeLayoutGetLeft(root_child0)); ASSERT_EQ(0, YGNodeLayoutGetTop(root_child0)); - ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0)); - ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0)); + ASSERT_EQ(200, YGNodeLayoutGetWidth(root_child0)); + ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0)); YGNodeFreeRecursive(root); } @@ -747,3 +779,96 @@ TEST(YogaTest, aspect_ratio_defined_cross_with_margin) { YGNodeFreeRecursive(root); } + +TEST(YogaTest, aspect_ratio_should_prefer_explicit_height) { + const YGConfigRef config = YGConfigNew(); + YGConfigSetUseWebDefaults(config, true); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionColumn); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionColumn); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0_child0, YGFlexDirectionColumn); + YGNodeStyleSetHeight(root_child0_child0, 100); + YGNodeStyleSetAspectRatio(root_child0_child0, 2); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + + YGNodeCalculateLayout(root, 100, 200, YGDirectionLTR); + + ASSERT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_EQ(200, YGNodeLayoutGetHeight(root)); + + ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0)); + + YGNodeFreeRecursive(root); +} + +TEST(YogaTest, aspect_ratio_should_prefer_explicit_width) { + const YGConfigRef config = YGConfigNew(); + YGConfigSetUseWebDefaults(config, true); + + const YGNodeRef root = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root, YGFlexDirectionRow); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionRow); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0_child0, YGFlexDirectionRow); + YGNodeStyleSetWidth(root_child0_child0, 100); + YGNodeStyleSetAspectRatio(root_child0_child0, 0.5); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + + YGNodeCalculateLayout(root, 200, 100, YGDirectionLTR); + + ASSERT_EQ(200, YGNodeLayoutGetWidth(root)); + ASSERT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_EQ(100, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_EQ(200, YGNodeLayoutGetHeight(root_child0_child0)); + + YGNodeFreeRecursive(root); +} + +TEST(YogaTest, aspect_ratio_should_prefer_flexed_dimension) { + const YGConfigRef config = YGConfigNew(); + YGConfigSetUseWebDefaults(config, true); + + const YGNodeRef root = YGNodeNewWithConfig(config); + + const YGNodeRef root_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetFlexDirection(root_child0, YGFlexDirectionColumn); + YGNodeStyleSetAspectRatio(root_child0, 2); + YGNodeStyleSetFlexGrow(root_child0, 1); + YGNodeInsertChild(root, root_child0, 0); + + const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config); + YGNodeStyleSetAspectRatio(root_child0_child0, 4); + YGNodeStyleSetFlexGrow(root_child0_child0, 1); + YGNodeInsertChild(root_child0, root_child0_child0, 0); + + YGNodeCalculateLayout(root, 100, 100, YGDirectionLTR); + + ASSERT_EQ(100, YGNodeLayoutGetWidth(root)); + ASSERT_EQ(100, YGNodeLayoutGetHeight(root)); + + ASSERT_EQ(100, YGNodeLayoutGetWidth(root_child0)); + ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0)); + + ASSERT_EQ(200, YGNodeLayoutGetWidth(root_child0_child0)); + ASSERT_EQ(50, YGNodeLayoutGetHeight(root_child0_child0)); + + YGNodeFreeRecursive(root); +} diff --git a/yoga/Yoga.c b/yoga/Yoga.c index ab2ef235..d57f0581 100644 --- a/yoga/Yoga.c +++ b/yoga/Yoga.c @@ -10,8 +10,8 @@ #include #include "YGNodeList.h" -#include "Yoga.h" #include "Yoga-internal.h" +#include "Yoga.h" #ifdef _MSC_VER #include @@ -1514,31 +1514,42 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, } } + if (!YGFloatIsUndefined(child->style.aspectRatio)) { + if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) { + childHeight = (childWidth - marginRow) / child->style.aspectRatio; + childHeightMeasureMode = YGMeasureModeExactly; + } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) { + childWidth = (childHeight - marginColumn) * child->style.aspectRatio; + childWidthMeasureMode = YGMeasureModeExactly; + } + } + // If child has no defined size in the cross axis and is set to stretch, // set the cross // axis to be measured exactly with the available inner width - if (!isMainAxisRow && !YGFloatIsUndefined(width) && !isRowStyleDimDefined && - widthMode == YGMeasureModeExactly && YGNodeAlignItem(node, child) == YGAlignStretch) { + + const bool hasExactWidth = !YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly; + const bool childWidthStretch = YGNodeAlignItem(node, child) == YGAlignStretch && + childWidthMeasureMode != YGMeasureModeExactly; + if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth && childWidthStretch) { childWidth = width; childWidthMeasureMode = YGMeasureModeExactly; - } - if (isMainAxisRow && !YGFloatIsUndefined(height) && !isColumnStyleDimDefined && - heightMode == YGMeasureModeExactly && YGNodeAlignItem(node, child) == YGAlignStretch) { - childHeight = height; - childHeightMeasureMode = YGMeasureModeExactly; + if (!YGFloatIsUndefined(child->style.aspectRatio)) { + childHeight = (childWidth - marginRow) / child->style.aspectRatio; + childHeightMeasureMode = YGMeasureModeExactly; + } } - if (!YGFloatIsUndefined(child->style.aspectRatio)) { - if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) { - child->layout.computedFlexBasis = - fmaxf((childWidth - marginRow) / child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn, parentWidth)); - return; - } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) { - child->layout.computedFlexBasis = - fmaxf((childHeight - marginColumn) * child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth)); - return; + const bool hasExactHeight = !YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly; + const bool childHeightStretch = YGNodeAlignItem(node, child) == YGAlignStretch && + childHeightMeasureMode != YGMeasureModeExactly; + if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight && childHeightStretch) { + childHeight = height; + childHeightMeasureMode = YGMeasureModeExactly; + + if (!YGFloatIsUndefined(child->style.aspectRatio)) { + childWidth = (childHeight - marginColumn) * child->style.aspectRatio; + childWidthMeasureMode = YGMeasureModeExactly; } } @@ -1631,13 +1642,9 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) { if (!YGFloatIsUndefined(child->style.aspectRatio)) { if (YGFloatIsUndefined(childWidth)) { - childWidth = - marginRow + fmaxf((childHeight - marginColumn) * child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn, width)); + childWidth = marginRow + (childHeight - marginColumn) * child->style.aspectRatio; } else if (YGFloatIsUndefined(childHeight)) { - childHeight = - marginColumn + fmaxf((childWidth - marginRow) / child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, width)); + childHeight = marginColumn + (childWidth - marginRow) / child->style.aspectRatio; } } } @@ -1688,11 +1695,11 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, config); if (YGNodeIsTrailingPosDefined(child, mainAxis) && !YGNodeIsLeadingPosDefined(child, mainAxis)) { - child->layout.position[leading[mainAxis]] = node->layout.measuredDimensions[dim[mainAxis]] - - child->layout.measuredDimensions[dim[mainAxis]] - - YGNodeTrailingBorder(node, mainAxis) - - YGNodeTrailingMargin(child, mainAxis, width) - - YGNodeTrailingPosition(child, mainAxis, isMainAxisRow ? width : height); + child->layout.position[leading[mainAxis]] = + node->layout.measuredDimensions[dim[mainAxis]] - + child->layout.measuredDimensions[dim[mainAxis]] - YGNodeTrailingBorder(node, mainAxis) - + YGNodeTrailingMargin(child, mainAxis, width) - + YGNodeTrailingPosition(child, mainAxis, isMainAxisRow ? width : height); } else if (!YGNodeIsLeadingPosDefined(child, mainAxis) && node->style.justifyContent == YGJustifyCenter) { child->layout.position[leading[mainAxis]] = (node->layout.measuredDimensions[dim[mainAxis]] - @@ -1706,11 +1713,11 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, if (YGNodeIsTrailingPosDefined(child, crossAxis) && !YGNodeIsLeadingPosDefined(child, crossAxis)) { - child->layout.position[leading[crossAxis]] = node->layout.measuredDimensions[dim[crossAxis]] - - child->layout.measuredDimensions[dim[crossAxis]] - - YGNodeTrailingBorder(node, crossAxis) - - YGNodeTrailingMargin(child, crossAxis, width) - - YGNodeTrailingPosition(child, crossAxis, isMainAxisRow ? height : width); + child->layout.position[leading[crossAxis]] = + node->layout.measuredDimensions[dim[crossAxis]] - + child->layout.measuredDimensions[dim[crossAxis]] - YGNodeTrailingBorder(node, crossAxis) - + YGNodeTrailingMargin(child, crossAxis, width) - + YGNodeTrailingPosition(child, crossAxis, isMainAxisRow ? height : width); } else if (!YGNodeIsLeadingPosDefined(child, crossAxis) && YGNodeAlignItem(node, child) == YGAlignCenter) { child->layout.position[leading[crossAxis]] = @@ -1718,7 +1725,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, child->layout.measuredDimensions[dim[crossAxis]]) / 2.0f; } else if (!YGNodeIsLeadingPosDefined(child, crossAxis) && - ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^ (node->style.flexWrap == YGWrapWrapReverse))) { + ((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^ + (node->style.flexWrap == YGWrapWrapReverse))) { child->layout.position[leading[crossAxis]] = (node->layout.measuredDimensions[dim[crossAxis]] - child->layout.measuredDimensions[dim[crossAxis]]); } @@ -1742,11 +1750,12 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, // We want to make sure we don't call measure with negative size const float innerWidth = YGFloatIsUndefined(availableWidth) - ? availableWidth - : fmaxf(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow); - const float innerHeight = YGFloatIsUndefined(availableHeight) - ? availableHeight - : fmaxf(0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn); + ? availableWidth + : fmaxf(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow); + const float innerHeight = + YGFloatIsUndefined(availableHeight) + ? availableHeight + : fmaxf(0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn); if (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly) { // Don't bother sizing the text if both dimensions are already defined. @@ -2244,7 +2253,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, const float childMarginMainAxis = YGNodeMarginForAxis(child, mainAxis, availableInnerWidth); const float flexBasisWithMaxConstraints = fminf(YGResolveValue(&child->style.maxDimensions[dim[mainAxis]], mainAxisParentSize), - child->layout.computedFlexBasis); + child->layout.computedFlexBasis); const float flexBasisWithMinAndMaxConstraints = fmaxf(YGResolveValue(&child->style.minDimensions[dim[mainAxis]], mainAxisParentSize), flexBasisWithMaxConstraints); @@ -2498,11 +2507,21 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGMeasureMode childCrossMeasureMode; YGMeasureMode childMainMeasureMode = YGMeasureModeExactly; - if (!YGFloatIsUndefined(availableInnerCrossDim) && - !YGNodeIsStyleDimDefined(currentRelativeChild, crossAxis, availableInnerCrossDim) && - measureModeCrossDim == YGMeasureModeExactly && - !(isNodeFlexWrap && flexBasisOverflows) && - YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) { + if (!YGFloatIsUndefined(currentRelativeChild->style.aspectRatio)) { + childCrossSize = + isMainAxisRow + ? (childMainSize - marginMain) / currentRelativeChild->style.aspectRatio + : (childMainSize - marginMain) * currentRelativeChild->style.aspectRatio; + childCrossMeasureMode = YGMeasureModeExactly; + + childCrossSize += marginCross; + } else if (!YGFloatIsUndefined(availableInnerCrossDim) && + !YGNodeIsStyleDimDefined(currentRelativeChild, + crossAxis, + availableInnerCrossDim) && + measureModeCrossDim == YGMeasureModeExactly && + !(isNodeFlexWrap && flexBasisOverflows) && + YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) { childCrossSize = availableInnerCrossDim; childCrossMeasureMode = YGMeasureModeExactly; } else if (!YGNodeIsStyleDimDefined(currentRelativeChild, @@ -2523,26 +2542,6 @@ static void YGNodelayoutImpl(const YGNodeRef node, : YGMeasureModeExactly; } - if (!YGFloatIsUndefined(currentRelativeChild->style.aspectRatio)) { - childCrossSize = fmaxf( - isMainAxisRow - ? (childMainSize - marginMain) / currentRelativeChild->style.aspectRatio - : (childMainSize - marginMain) * currentRelativeChild->style.aspectRatio, - YGNodePaddingAndBorderForAxis(currentRelativeChild, crossAxis, availableInnerWidth)); - childCrossMeasureMode = YGMeasureModeExactly; - - // Parent size constraint should have higher priority than flex - if (YGNodeIsFlex(currentRelativeChild)) { - childCrossSize = fminf(childCrossSize - marginCross, availableInnerCrossDim); - childMainSize = - marginMain + (isMainAxisRow - ? childCrossSize * currentRelativeChild->style.aspectRatio - : childCrossSize / currentRelativeChild->style.aspectRatio); - } - - childCrossSize += marginCross; - } - YGConstrainMaxSizeForMode(currentRelativeChild, mainAxis, availableInnerMainDim, @@ -3160,9 +3159,9 @@ static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(YGMeasureM } float YGRoundValueToPixelGrid(const float value, - const float pointScaleFactor, - const bool forceCeil, - const bool forceFloor) { + const float pointScaleFactor, + const bool forceCeil, + const bool forceFloor) { float scaledValue = value * pointScaleFactor; float fractial = fmodf(scaledValue, 1.0); if (YGFloatsEqual(fractial, 0)) { @@ -3199,13 +3198,25 @@ bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode, return false; } bool useRoundedComparison = config != NULL && config->pointScaleFactor != 0; - const float effectiveWidth = useRoundedComparison ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false) : width; - const float effectiveHeight = useRoundedComparison ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false) : height; - const float effectiveLastWidth = useRoundedComparison ? YGRoundValueToPixelGrid(lastWidth, config->pointScaleFactor, false, false) : lastWidth; - const float effectiveLastHeight = useRoundedComparison ? YGRoundValueToPixelGrid(lastHeight, config->pointScaleFactor, false, false) : lastHeight; + const float effectiveWidth = + useRoundedComparison ? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false) + : width; + const float effectiveHeight = + useRoundedComparison ? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false) + : height; + const float effectiveLastWidth = + useRoundedComparison + ? YGRoundValueToPixelGrid(lastWidth, config->pointScaleFactor, false, false) + : lastWidth; + const float effectiveLastHeight = + useRoundedComparison + ? YGRoundValueToPixelGrid(lastHeight, config->pointScaleFactor, false, false) + : lastHeight; - const bool hasSameWidthSpec = lastWidthMode == widthMode && YGFloatsEqual(effectiveLastWidth, effectiveWidth); - const bool hasSameHeightSpec = lastHeightMode == heightMode && YGFloatsEqual(effectiveLastHeight, effectiveHeight); + const bool hasSameWidthSpec = + lastWidthMode == widthMode && YGFloatsEqual(effectiveLastWidth, effectiveWidth); + const bool hasSameHeightSpec = + lastHeightMode == heightMode && YGFloatsEqual(effectiveLastHeight, effectiveHeight); const bool widthIsCompatible = hasSameWidthSpec || YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(widthMode, @@ -3479,7 +3490,8 @@ static void YGRoundToPixelGrid(const YGNodeRef node, node->layout.position[YGEdgeTop] = YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding); - // We multiply dimension by scale factor and if the result is close to the whole number, we don't have any fraction + // We multiply dimension by scale factor and if the result is close to the whole number, we don't + // have any fraction // To verify if the result is close to whole number we want to check both floor and ceil numbers const bool hasFractionalWidth = !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) && !YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0); @@ -3487,18 +3499,16 @@ static void YGRoundToPixelGrid(const YGNodeRef node, !YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0); node->layout.dimensions[YGDimensionWidth] = - YGRoundValueToPixelGrid( - absoluteNodeRight, - pointScaleFactor, - (textRounding && hasFractionalWidth), - (textRounding && !hasFractionalWidth)) - + YGRoundValueToPixelGrid(absoluteNodeRight, + pointScaleFactor, + (textRounding && hasFractionalWidth), + (textRounding && !hasFractionalWidth)) - YGRoundValueToPixelGrid(absoluteNodeLeft, pointScaleFactor, false, textRounding); node->layout.dimensions[YGDimensionHeight] = - YGRoundValueToPixelGrid( - absoluteNodeBottom, - pointScaleFactor, - (textRounding && hasFractionalHeight), - (textRounding && !hasFractionalHeight)) - + YGRoundValueToPixelGrid(absoluteNodeBottom, + pointScaleFactor, + (textRounding && hasFractionalHeight), + (textRounding && !hasFractionalHeight)) - YGRoundValueToPixelGrid(absoluteNodeTop, pointScaleFactor, false, textRounding); const uint32_t childCount = YGNodeListCount(node->children); -- 2.50.1.windows.1 From c79c5e3c9d47e6997e06b076ea16a23ab53cdeb4 Mon Sep 17 00:00:00 2001 From: Scott Wolchok Date: Tue, 22 Aug 2017 11:54:13 -0700 Subject: [PATCH 08/12] Make gYGNodeDefaults const Summary: At least one compiler seems to care about it. Reviewed By: emilsjolander Differential Revision: D5675518 fbshipit-source-id: 72a6e208263dde0b6bb46a78fedb2796d0e0a600 --- yoga/Yoga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yoga/Yoga.c b/yoga/Yoga.c index d57f0581..5410895e 100644 --- a/yoga/Yoga.c +++ b/yoga/Yoga.c @@ -156,7 +156,7 @@ static const float kDefaultFlexGrow = 0.0f; static const float kDefaultFlexShrink = 0.0f; static const float kWebDefaultFlexShrink = 1.0f; -static YGNode gYGNodeDefaults = { +static const YGNode gYGNodeDefaults = { .parent = NULL, .children = NULL, .hasNewLayout = true, -- 2.50.1.windows.1 From 4185a4439309e76145477b15f23ef64505140b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 23 Aug 2017 02:40:04 -0700 Subject: [PATCH 09/12] Fix const declaration mismatch and double/float mix Summary: This PR fixes a declaration mismatch for `YGNodeCanUseCachedMeasurement` where the last argument is declared non `const` in `.h` and `const` in `.c`. Additionally it uses explicit `float` for fraction calculation do avoid usage of `double` assignment. Closes https://github.com/facebook/yoga/pull/607 Differential Revision: D5677931 Pulled By: emilsjolander fbshipit-source-id: 502da957089e4439ed956987ff8dec10bd033ba3 --- yoga/Yoga.c | 4 ++-- yoga/Yoga.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yoga/Yoga.c b/yoga/Yoga.c index 5410895e..15ac4586 100644 --- a/yoga/Yoga.c +++ b/yoga/Yoga.c @@ -3171,12 +3171,12 @@ float YGRoundValueToPixelGrid(const float value, scaledValue = scaledValue - fractial + 1.0; } else if (forceCeil) { // Next we check if we need to use forced rounding - scaledValue = scaledValue - fractial + 1.0; + scaledValue = scaledValue - fractial + 1.0f; } else if (forceFloor) { scaledValue = scaledValue - fractial; } else { // Finally we just round the value - scaledValue = scaledValue - fractial + (fractial >= 0.5f ? 1.0 : 0); + scaledValue = scaledValue - fractial + (fractial >= 0.5f ? 1.0f : 0.0f); } return scaledValue / pointScaleFactor; } diff --git a/yoga/Yoga.h b/yoga/Yoga.h index c3d3260d..81bbe7b3 100644 --- a/yoga/Yoga.h +++ b/yoga/Yoga.h @@ -112,7 +112,7 @@ WIN_EXPORT bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode, const float lastComputedHeight, const float marginRow, const float marginColumn, - YGConfigRef config); + const YGConfigRef config); WIN_EXPORT void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode); -- 2.50.1.windows.1 From c20f2864abaf5a81dee23139c80801054b73089b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 23 Aug 2017 15:25:41 -0700 Subject: [PATCH 10/12] Only add UIView nodes to Yoga where they are enabled Summary: Only add UIView nodes to Yoga where they are enabled. We check for it in `isLeaf` but I think we should also check for them in the check for sub views. Closes https://github.com/facebook/yoga/pull/609 Reviewed By: emilsjolander Differential Revision: D5643387 Pulled By: dshahidehpour fbshipit-source-id: a85c62b6b2e0120b2913e7f2df8b094d43ca49a6 --- YogaKit/Source/YGLayout.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index df4a4821..70e6ed40 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -361,7 +361,7 @@ static void YGAttachNodesFromViewHierachy(UIView *const view) NSMutableArray *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count]; for (UIView *subview in view.subviews) { - if (subview.yoga.isIncludedInLayout) { + if (subview.yoga.isEnabled && subview.yoga.isIncludedInLayout) { [subviewsToInclude addObject:subview]; } } -- 2.50.1.windows.1 From d12400c904f3edb130270c5ad394419a04d62b13 Mon Sep 17 00:00:00 2001 From: Pavel Mazurin Date: Thu, 24 Aug 2017 11:13:48 +0200 Subject: [PATCH 11/12] Code review comments --- YogaKit/Source/YGLayout.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index 9cc4a6a7..d22073b9 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -102,6 +102,7 @@ static YGConfigRef globalConfig; @interface YGLayout () @property (nonatomic, weak, readonly) UIView *view; +@property (nonatomic, assign, readonly) BOOL isUIView; @end @@ -126,6 +127,7 @@ static YGConfigRef globalConfig; YGNodeSetContext(_node, (__bridge void *) view); _isEnabled = NO; _isIncludedInLayout = YES; + _isUIView = [view isMemberOfClass:[UIView class]]; } return self; @@ -307,7 +309,7 @@ static YGSize YGMeasureView( CGSize sizeThatFits = CGSizeZero; // Fix for https://github.com/facebook/yoga/issues/606 - if (![view isMemberOfClass:[UIView class]] || [view.subviews count] > 0) { + if (!view.yoga.isUIView || [view.subviews count] > 0) { sizeThatFits = [view sizeThatFits:(CGSize) { .width = constrainedWidth, .height = constrainedHeight, -- 2.50.1.windows.1 From 46bfe2209539a3113b8886fa8d168b4ee71a8426 Mon Sep 17 00:00:00 2001 From: Pavel Mazurin Date: Thu, 25 Jan 2018 12:58:31 +0100 Subject: [PATCH 12/12] Update comment --- YogaKit/Source/YGLayout.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index d22073b9..1bc3a07e 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -308,7 +308,11 @@ static YGSize YGMeasureView( UIView *view = (__bridge UIView*) YGNodeGetContext(node); CGSize sizeThatFits = CGSizeZero; - // Fix for https://github.com/facebook/yoga/issues/606 + // The default implementation of sizeThatFits: returns the existing size of the view. + // That means that if we want to layout an empty UIView, which already has got a frame set, + // its measured size should be CGSizeZero, but UIKit returns the existing size. + // + // See https://github.com/facebook/yoga/issues/606 for more information. if (!view.yoga.isUIView || [view.subviews count] > 0) { sizeThatFits = [view sizeThatFits:(CGSize) { .width = constrainedWidth, -- 2.50.1.windows.1