From 16359ec8eeb601f9e9e20a0cc01b6c4e46627d3a Mon Sep 17 00:00:00 2001 From: Lukas Woehrl Date: Mon, 2 Jan 2017 05:20:37 -0800 Subject: [PATCH] Add feature to use percentage as value unit Summary: Adds the feature to use percentage as a value unit. You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience. I did some benchmarks: ``` Without Percentage Feature - Release x86: Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms Nested flex: median: 0.000000 ms, stddev: 0.490101 ms Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms Nested flex: median: 0.000000 ms, stddev: 0.477791 ms Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms With Percentage Feature - Release x86: Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms Nested flex: median: 0.000000 ms, stddev: 0.489570 ms Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms Closes https://github.com/facebook/yoga/pull/258 Reviewed By: dshahidehpour Differential Revision: D4361945 Pulled By: emilsjolander fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a --- .../UIExplorerUnitTests/RCTShadowViewTests.m | 4 +- Libraries/Text/RCTShadowText.m | 12 +- React/Views/RCTShadowView.m | 89 +- .../react/uimanager/ReactShadowNode.java | 6 +- .../java/com/facebook/yoga/YogaConstants.java | 4 + .../main/java/com/facebook/yoga/YogaNode.java | 129 +- .../java/com/facebook/yoga/YogaNodeAPI.java | 30 +- .../main/java/com/facebook/yoga/YogaUnit.java | 38 + .../java/com/facebook/yoga/YogaValue.java | 45 + .../jni/first-party/yogajni/jni/YGJNI.cpp | 82 +- ReactCommon/yoga/yoga/YGEnums.h | 7 + ReactCommon/yoga/yoga/Yoga.c | 1165 ++++++++++------- ReactCommon/yoga/yoga/Yoga.h | 41 +- 13 files changed, 1094 insertions(+), 558 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/yoga/YogaUnit.java create mode 100644 ReactAndroid/src/main/java/com/facebook/yoga/YogaValue.java diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m index ab338eda5..9f78489c3 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTShadowViewTests.m @@ -165,8 +165,8 @@ - (void)testDoesNotAssignSuggestedDimensionsWhenStyledWithFlexAttribute { - float parentWidth = YGNodeStyleGetWidth(self.parentView.cssNode); - float parentHeight = YGNodeStyleGetHeight(self.parentView.cssNode); + float parentWidth = YGNodeStyleGetWidth(self.parentView.cssNode).value; + float parentHeight = YGNodeStyleGetHeight(self.parentView.cssNode).value; [self _withShadowViewWithStyle:^(YGNodeRef node) { YGNodeStyleSetFlex(node, 1); } diff --git a/Libraries/Text/RCTShadowText.m b/Libraries/Text/RCTShadowText.m index 2a2dc518c..07a2c83c4 100644 --- a/Libraries/Text/RCTShadowText.m +++ b/Libraries/Text/RCTShadowText.m @@ -161,9 +161,9 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f [layoutManager.textStorage enumerateAttribute:RCTShadowViewAttributeName inRange:characterRange options:0 usingBlock:^(RCTShadowView *child, NSRange range, BOOL *_) { if (child) { YGNodeRef childNode = child.cssNode; - float width = YGNodeStyleGetWidth(childNode); - float height = YGNodeStyleGetHeight(childNode); - if (YGValueIsUndefined(width) || YGValueIsUndefined(height)) { + float width = YGNodeStyleGetWidth(childNode).value; + float height = YGNodeStyleGetHeight(childNode).value; + if (YGFloatIsUndefined(width) || YGFloatIsUndefined(height)) { RCTLogError(@"Views nested within a must have a width and height"); } UIFont *font = [textStorage attribute:NSFontAttributeName atIndex:range.location effectiveRange:nil]; @@ -307,9 +307,9 @@ static YGSize RCTMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, f [attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:shadowRawText.text ?: @""]]; [child setTextComputed]; } else { - float width = YGNodeStyleGetWidth(child.cssNode); - float height = YGNodeStyleGetHeight(child.cssNode); - if (YGValueIsUndefined(width) || YGValueIsUndefined(height)) { + float width = YGNodeStyleGetWidth(child.cssNode).value; + float height = YGNodeStyleGetHeight(child.cssNode).value; + if (YGFloatIsUndefined(width) || YGFloatIsUndefined(height)) { RCTLogError(@"Views nested within a must have a width and height"); } NSTextAttachment *attachment = [NSTextAttachment new]; diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m index 676ec004d..0c523e4d1 100644 --- a/React/Views/RCTShadowView.m +++ b/React/Views/RCTShadowView.m @@ -59,41 +59,41 @@ static void RCTPrint(YGNodeRef node) // Enforces precedence rules, e.g. marginLeft > marginHorizontal > margin. #define DEFINE_PROCESS_META_PROPS(type) \ static void RCTProcessMetaProps##type(const float metaProps[META_PROP_COUNT], YGNodeRef node) { \ - if (!YGValueIsUndefined(metaProps[META_PROP_LEFT])) { \ + if (!YGFloatIsUndefined(metaProps[META_PROP_LEFT])) { \ YGNodeStyleSet##type(node, YGEdgeStart, metaProps[META_PROP_LEFT]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_HORIZONTAL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_HORIZONTAL])) { \ YGNodeStyleSet##type(node, YGEdgeStart, metaProps[META_PROP_HORIZONTAL]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_ALL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_ALL])) { \ YGNodeStyleSet##type(node, YGEdgeStart, metaProps[META_PROP_ALL]); \ } else { \ YGNodeStyleSet##type(node, YGEdgeStart, 0); \ } \ \ - if (!YGValueIsUndefined(metaProps[META_PROP_RIGHT])) { \ + if (!YGFloatIsUndefined(metaProps[META_PROP_RIGHT])) { \ YGNodeStyleSet##type(node, YGEdgeEnd, metaProps[META_PROP_RIGHT]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_HORIZONTAL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_HORIZONTAL])) { \ YGNodeStyleSet##type(node, YGEdgeEnd, metaProps[META_PROP_HORIZONTAL]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_ALL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_ALL])) { \ YGNodeStyleSet##type(node, YGEdgeEnd, metaProps[META_PROP_ALL]); \ } else { \ YGNodeStyleSet##type(node, YGEdgeEnd, 0); \ } \ \ - if (!YGValueIsUndefined(metaProps[META_PROP_TOP])) { \ + if (!YGFloatIsUndefined(metaProps[META_PROP_TOP])) { \ YGNodeStyleSet##type(node, YGEdgeTop, metaProps[META_PROP_TOP]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_VERTICAL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_VERTICAL])) { \ YGNodeStyleSet##type(node, YGEdgeTop, metaProps[META_PROP_VERTICAL]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_ALL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_ALL])) { \ YGNodeStyleSet##type(node, YGEdgeTop, metaProps[META_PROP_ALL]); \ } else { \ YGNodeStyleSet##type(node, YGEdgeTop, 0); \ } \ \ - if (!YGValueIsUndefined(metaProps[META_PROP_BOTTOM])) { \ + if (!YGFloatIsUndefined(metaProps[META_PROP_BOTTOM])) { \ YGNodeStyleSet##type(node, YGEdgeBottom, metaProps[META_PROP_BOTTOM]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_VERTICAL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_VERTICAL])) { \ YGNodeStyleSet##type(node, YGEdgeBottom, metaProps[META_PROP_VERTICAL]); \ - } else if (!YGValueIsUndefined(metaProps[META_PROP_ALL])) { \ + } else if (!YGFloatIsUndefined(metaProps[META_PROP_ALL])) { \ YGNodeStyleSet##type(node, YGEdgeBottom, metaProps[META_PROP_ALL]); \ } else { \ YGNodeStyleSet##type(node, YGEdgeBottom, 0); \ @@ -145,9 +145,9 @@ DEFINE_PROCESS_META_PROPS(Border); #if RCT_DEBUG // This works around a breaking change in css-layout where setting flexBasis needs to be set explicitly, instead of relying on flex to propagate. // We check for it by seeing if a width/height is provided along with a flexBasis of 0 and the width/height is laid out as 0. - if ((!YGValueIsUndefined(YGNodeStyleGetFlexBasis(node)) && YGNodeStyleGetFlexBasis(node) == 0) && - ((!YGValueIsUndefined(YGNodeStyleGetWidth(node)) && YGNodeStyleGetWidth(node) > 0 && YGNodeLayoutGetWidth(node) == 0) || - (!YGValueIsUndefined(YGNodeStyleGetHeight(node)) && YGNodeStyleGetHeight(node) > 0 && YGNodeLayoutGetHeight(node) == 0))) { + if ((YGNodeStyleGetFlexBasis(node).unit == YGUnitPixel && YGNodeStyleGetFlexBasis(node).value == 0) && + ((YGNodeStyleGetWidth(node).unit == YGUnitPixel && YGNodeStyleGetWidth(node).value > 0 && YGNodeLayoutGetWidth(node) == 0) || + (YGNodeStyleGetHeight(node).unit == YGUnitPixel && YGNodeStyleGetHeight(node).value > 0 && YGNodeLayoutGetHeight(node) == 0))) { RCTLogError(@"View was rendered with explicitly set width/height but with a 0 flexBasis. (This might be fixed by changing flex: to flexGrow:) View: %@", self); } #endif @@ -493,25 +493,25 @@ RCT_PADDING_PROPERTY(Right, RIGHT) { if (YGNodeLayoutGetDirection(_cssNode) == YGDirectionRTL) { return (UIEdgeInsets){ - YGNodeStyleGetPadding(_cssNode, YGEdgeTop), - !YGValueIsUndefined(YGNodeStyleGetPadding(_cssNode, YGEdgeEnd)) ? - YGNodeStyleGetPadding(_cssNode, YGEdgeEnd) : - YGNodeStyleGetPadding(_cssNode, YGEdgeLeft), - YGNodeStyleGetPadding(_cssNode, YGEdgeBottom), - !YGValueIsUndefined(YGNodeStyleGetPadding(_cssNode, YGEdgeStart)) ? - YGNodeStyleGetPadding(_cssNode, YGEdgeStart) : - YGNodeStyleGetPadding(_cssNode, YGEdgeRight) + YGNodeStyleGetPadding(_cssNode, YGEdgeTop).value, + YGNodeStyleGetPadding(_cssNode, YGEdgeEnd).unit == YGUnitPixel ? + YGNodeStyleGetPadding(_cssNode, YGEdgeEnd).value : + YGNodeStyleGetPadding(_cssNode, YGEdgeLeft).value, + YGNodeStyleGetPadding(_cssNode, YGEdgeBottom).value, + YGNodeStyleGetPadding(_cssNode, YGEdgeStart).unit == YGUnitPixel ? + YGNodeStyleGetPadding(_cssNode, YGEdgeStart).value : + YGNodeStyleGetPadding(_cssNode, YGEdgeRight).value }; } else { return (UIEdgeInsets){ - YGNodeStyleGetPadding(_cssNode, YGEdgeTop), - !YGValueIsUndefined(YGNodeStyleGetPadding(_cssNode, YGEdgeStart)) ? - YGNodeStyleGetPadding(_cssNode, YGEdgeStart) : - YGNodeStyleGetPadding(_cssNode, YGEdgeLeft), - YGNodeStyleGetPadding(_cssNode, YGEdgeBottom), - !YGValueIsUndefined(YGNodeStyleGetPadding(_cssNode, YGEdgeEnd)) ? - YGNodeStyleGetPadding(_cssNode, YGEdgeEnd) : - YGNodeStyleGetPadding(_cssNode, YGEdgeRight) + YGNodeStyleGetPadding(_cssNode, YGEdgeTop).value, + YGNodeStyleGetPadding(_cssNode, YGEdgeStart).unit == YGUnitPixel ? + YGNodeStyleGetPadding(_cssNode, YGEdgeStart).value : + YGNodeStyleGetPadding(_cssNode, YGEdgeLeft).value, + YGNodeStyleGetPadding(_cssNode, YGEdgeBottom).value, + YGNodeStyleGetPadding(_cssNode, YGEdgeEnd).unit == YGUnitPixel ? + YGNodeStyleGetPadding(_cssNode, YGEdgeEnd).value : + YGNodeStyleGetPadding(_cssNode, YGEdgeRight).value }; } } @@ -541,12 +541,12 @@ RCT_BORDER_PROPERTY(Right, RIGHT) #define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \ - (void)set##setProp:(float)value \ { \ - YGNodeStyleSet##cssProp(_cssNode, value); \ + YGNodeStyleSet##cssProp(_cssNode, value); \ [self dirtyText]; \ } \ - (float)getProp \ { \ - return YGNodeStyleGet##cssProp(_cssNode); \ + return YGNodeStyleGet##cssProp(_cssNode).value; \ } RCT_DIMENSION_PROPERTY(Width, width, Width) @@ -561,12 +561,12 @@ RCT_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight) #define RCT_POSITION_PROPERTY(setProp, getProp, edge) \ - (void)set##setProp:(float)value \ { \ - YGNodeStyleSetPosition(_cssNode, edge, value); \ + YGNodeStyleSetPosition(_cssNode, edge, value); \ [self dirtyText]; \ } \ - (float)getProp \ { \ - return YGNodeStyleGetPosition(_cssNode, edge); \ + return YGNodeStyleGetPosition(_cssNode, edge).value; \ } RCT_POSITION_PROPERTY(Top, top, YGEdgeTop) @@ -590,12 +590,12 @@ static inline void RCTAssignSuggestedDimension(YGNodeRef cssNode, YGDimension di if (amount != UIViewNoIntrinsicMetric) { switch (dimension) { case YGDimensionWidth: - if (isnan(YGNodeStyleGetWidth(cssNode))) { + if (isnan(YGNodeStyleGetWidth(cssNode).value)) { YGNodeStyleSetWidth(cssNode, amount); } break; case YGDimensionHeight: - if (isnan(YGNodeStyleGetHeight(cssNode))) { + if (isnan(YGNodeStyleGetHeight(cssNode).value)) { YGNodeStyleSetHeight(cssNode, amount); } break; @@ -630,19 +630,28 @@ static inline void RCTAssignSuggestedDimension(YGNodeRef cssNode, YGDimension di YGNodeStyleSetFlex(_cssNode, value); } +- (void)setFlexBasis:(float)value +{ + YGNodeStyleSetFlexBasis(_cssNode, value); +} + +- (float)flexBasis +{ + return YGNodeStyleGetFlexBasis(_cssNode).value; +} + #define RCT_STYLE_PROPERTY(setProp, getProp, cssProp, type) \ - (void)set##setProp:(type)value \ { \ - YGNodeStyleSet##cssProp(_cssNode, value); \ + YGNodeStyleSet##cssProp(_cssNode, value); \ } \ - (type)getProp \ { \ - return YGNodeStyleGet##cssProp(_cssNode); \ + return YGNodeStyleGet##cssProp(_cssNode); \ } RCT_STYLE_PROPERTY(FlexGrow, flexGrow, FlexGrow, float) RCT_STYLE_PROPERTY(FlexShrink, flexShrink, FlexShrink, float) -RCT_STYLE_PROPERTY(FlexBasis, flexBasis, FlexBasis, float) RCT_STYLE_PROPERTY(FlexDirection, flexDirection, FlexDirection, YGFlexDirection) RCT_STYLE_PROPERTY(JustifyContent, justifyContent, JustifyContent, YGJustify) RCT_STYLE_PROPERTY(AlignSelf, alignSelf, AlignSelf, YGAlign) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index 3959ce1e8..731e82941 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -515,7 +515,7 @@ public class ReactShadowNode { } public final float getStyleWidth() { - return mYogaNode.getWidth(); + return mYogaNode.getWidth().value; } public void setStyleWidth(float widthPx) { @@ -531,7 +531,7 @@ public class ReactShadowNode { } public final float getStyleHeight() { - return mYogaNode.getHeight(); + return mYogaNode.getHeight().value; } public void setStyleHeight(float heightPx) { @@ -595,7 +595,7 @@ public class ReactShadowNode { } public final float getPadding(int spacingType) { - return mYogaNode.getPadding(YogaEdge.fromInt(spacingType)); + return mYogaNode.getPadding(YogaEdge.fromInt(spacingType)).value; } public void setDefaultPadding(int spacingType, float padding) { diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java index 93dc9f818..ff50f2ab6 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConstants.java @@ -16,4 +16,8 @@ public class YogaConstants { public static boolean isUndefined(float value) { return Float.compare(value, UNDEFINED) == 0; } + + public static boolean isUndefined(YogaValue value) { + return value.unit == YogaUnit.UNDEFINED; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 2aa11faa7..0a4e0bac4 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -323,10 +323,10 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetFlexShrink(mNativePointer, flexShrink); } - private native float jni_YGNodeStyleGetFlexBasis(long nativePointer); + private native Object jni_YGNodeStyleGetFlexBasis(long nativePointer); @Override - public float getFlexBasis() { - return jni_YGNodeStyleGetFlexBasis(mNativePointer); + public YogaValue getFlexBasis() { + return (YogaValue) jni_YGNodeStyleGetFlexBasis(mNativePointer); } private native void jni_YGNodeStyleSetFlexBasis(long nativePointer, float flexBasis); @@ -335,13 +335,19 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetFlexBasis(mNativePointer, flexBasis); } - private native float jni_YGNodeStyleGetMargin(long nativePointer, int edge); + private native void jni_YGNodeStyleSetFlexBasisPercent(long nativePointer, float percent); @Override - public float getMargin(YogaEdge edge) { + public void setFlexBasisPercent(float percent) { + jni_YGNodeStyleSetFlexBasisPercent(mNativePointer, percent); + } + + private native Object jni_YGNodeStyleGetMargin(long nativePointer, int edge); + @Override + public YogaValue getMargin(YogaEdge edge) { if (!mHasSetMargin) { - return edge.intValue() < YogaEdge.START.intValue() ? 0 : YogaConstants.UNDEFINED; + return edge.intValue() < YogaEdge.START.intValue() ? YogaValue.ZERO : YogaValue.UNDEFINED; } - return jni_YGNodeStyleGetMargin(mNativePointer, edge.intValue()); + return (YogaValue) jni_YGNodeStyleGetMargin(mNativePointer, edge.intValue()); } private native void jni_YGNodeStyleSetMargin(long nativePointer, int edge, float margin); @@ -351,13 +357,20 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetMargin(mNativePointer, edge.intValue(), margin); } - private native float jni_YGNodeStyleGetPadding(long nativePointer, int edge); + private native void jni_YGNodeStyleSetMarginPercent(long nativePointer, int edge, float percent); @Override - public float getPadding(YogaEdge edge) { + public void setMarginPercent(YogaEdge edge, float percent) { + mHasSetMargin = true; + jni_YGNodeStyleSetMarginPercent(mNativePointer, edge.intValue(), percent); + } + + private native Object jni_YGNodeStyleGetPadding(long nativePointer, int edge); + @Override + public YogaValue getPadding(YogaEdge edge) { if (!mHasSetPadding) { - return edge.intValue() < YogaEdge.START.intValue() ? 0 : YogaConstants.UNDEFINED; + return edge.intValue() < YogaEdge.START.intValue() ? YogaValue.ZERO : YogaValue.UNDEFINED; } - return jni_YGNodeStyleGetPadding(mNativePointer, edge.intValue()); + return (YogaValue) jni_YGNodeStyleGetPadding(mNativePointer, edge.intValue()); } private native void jni_YGNodeStyleSetPadding(long nativePointer, int edge, float padding); @@ -367,6 +380,13 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetPadding(mNativePointer, edge.intValue(), padding); } + private native void jni_YGNodeStyleSetPaddingPercent(long nativePointer, int edge, float percent); + @Override + public void setPaddingPercent(YogaEdge edge, float percent) { + mHasSetPadding = true; + jni_YGNodeStyleSetPaddingPercent(mNativePointer, edge.intValue(), percent); + } + private native float jni_YGNodeStyleGetBorder(long nativePointer, int edge); @Override public float getBorder(YogaEdge edge) { @@ -383,13 +403,13 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetBorder(mNativePointer, edge.intValue(), border); } - private native float jni_YGNodeStyleGetPosition(long nativePointer, int edge); + private native Object jni_YGNodeStyleGetPosition(long nativePointer, int edge); @Override - public float getPosition(YogaEdge edge) { + public YogaValue getPosition(YogaEdge edge) { if (!mHasSetPosition) { - return YogaConstants.UNDEFINED; + return YogaValue.UNDEFINED; } - return jni_YGNodeStyleGetPosition(mNativePointer, edge.intValue()); + return (YogaValue) jni_YGNodeStyleGetPosition(mNativePointer, edge.intValue()); } private native void jni_YGNodeStyleSetPosition(long nativePointer, int edge, float position); @@ -399,10 +419,17 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetPosition(mNativePointer, edge.intValue(), position); } - private native float jni_YGNodeStyleGetWidth(long nativePointer); + private native void jni_YGNodeStyleSetPositionPercent(long nativePointer, int edge, float percent); @Override - public float getWidth() { - return jni_YGNodeStyleGetWidth(mNativePointer); + public void setPositionPercent(YogaEdge edge, float percent) { + mHasSetPosition = true; + jni_YGNodeStyleSetPositionPercent(mNativePointer, edge.intValue(), percent); + } + + private native Object jni_YGNodeStyleGetWidth(long nativePointer); + @Override + public YogaValue getWidth() { + return (YogaValue) jni_YGNodeStyleGetWidth(mNativePointer); } private native void jni_YGNodeStyleSetWidth(long nativePointer, float width); @@ -411,10 +438,16 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetWidth(mNativePointer, width); } - private native float jni_YGNodeStyleGetHeight(long nativePointer); + private native void jni_YGNodeStyleSetWidthPercent(long nativePointer, float percent); @Override - public float getHeight() { - return jni_YGNodeStyleGetHeight(mNativePointer); + public void setWidthPercent(float percent) { + jni_YGNodeStyleSetWidthPercent(mNativePointer, percent); + } + + private native Object jni_YGNodeStyleGetHeight(long nativePointer); + @Override + public YogaValue getHeight() { + return (YogaValue) jni_YGNodeStyleGetHeight(mNativePointer); } private native void jni_YGNodeStyleSetHeight(long nativePointer, float height); @@ -423,10 +456,16 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetHeight(mNativePointer, height); } - private native float jni_YGNodeStyleGetMinWidth(long nativePointer); + private native void jni_YGNodeStyleSetHeightPercent(long nativePointer, float percent); @Override - public float getMinWidth() { - return jni_YGNodeStyleGetMinWidth(mNativePointer); + public void setHeightPercent(float percent) { + jni_YGNodeStyleSetHeightPercent(mNativePointer, percent); + } + + private native Object jni_YGNodeStyleGetMinWidth(long nativePointer); + @Override + public YogaValue getMinWidth() { + return (YogaValue) jni_YGNodeStyleGetMinWidth(mNativePointer); } private native void jni_YGNodeStyleSetMinWidth(long nativePointer, float minWidth); @@ -435,10 +474,16 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetMinWidth(mNativePointer, minWidth); } - private native float jni_YGNodeStyleGetMinHeight(long nativePointer); + private native void jni_YGNodeStyleSetMinWidthPercent(long nativePointer, float percent); @Override - public float getMinHeight() { - return jni_YGNodeStyleGetMinHeight(mNativePointer); + public void setMinWidthPercent(float percent) { + jni_YGNodeStyleSetMinWidthPercent(mNativePointer, percent); + } + + private native Object jni_YGNodeStyleGetMinHeight(long nativePointer); + @Override + public YogaValue getMinHeight() { + return (YogaValue) jni_YGNodeStyleGetMinHeight(mNativePointer); } private native void jni_YGNodeStyleSetMinHeight(long nativePointer, float minHeight); @@ -447,10 +492,16 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetMinHeight(mNativePointer, minHeight); } - private native float jni_YGNodeStyleGetMaxWidth(long nativePointer); + private native void jni_YGNodeStyleSetMinHeightPercent(long nativePointer, float percent); @Override - public float getMaxWidth() { - return jni_YGNodeStyleGetMaxWidth(mNativePointer); + public void setMinHeightPercent(float percent) { + jni_YGNodeStyleSetMinHeightPercent(mNativePointer, percent); + } + + private native Object jni_YGNodeStyleGetMaxWidth(long nativePointer); + @Override + public YogaValue getMaxWidth() { + return (YogaValue) jni_YGNodeStyleGetMaxWidth(mNativePointer); } private native void jni_YGNodeStyleSetMaxWidth(long nativePointer, float maxWidth); @@ -459,10 +510,16 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetMaxWidth(mNativePointer, maxWidth); } - private native float jni_YGNodeStyleGetMaxHeight(long nativePointer); + private native void jni_YGNodeStyleSetMaxWidthPercent(long nativePointer, float percent); @Override - public float getMaxHeight() { - return jni_YGNodeStyleGetMaxHeight(mNativePointer); + public void setMaxWidthPercent(float percent) { + jni_YGNodeStyleSetMaxWidthPercent(mNativePointer, percent); + } + + private native Object jni_YGNodeStyleGetMaxHeight(long nativePointer); + @Override + public YogaValue getMaxHeight() { + return (YogaValue) jni_YGNodeStyleGetMaxHeight(mNativePointer); } private native void jni_YGNodeStyleSetMaxHeight(long nativePointer, float maxheight); @@ -471,6 +528,12 @@ public class YogaNode implements YogaNodeAPI { jni_YGNodeStyleSetMaxHeight(mNativePointer, maxheight); } + private native void jni_YGNodeStyleSetMaxHeightPercent(long nativePointer, float percent); + @Override + public void setMaxHeightPercent(float percent) { + jni_YGNodeStyleSetMaxHeightPercent(mNativePointer, percent); + } + private native float jni_YGNodeStyleGetAspectRatio(long nativePointer); public float getAspectRatio() { return jni_YGNodeStyleGetAspectRatio(mNativePointer); diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java index cb3b5be87..b3cf0ac3f 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNodeAPI.java @@ -45,28 +45,38 @@ public interface YogaNodeAPI { void setFlexGrow(float flexGrow); float getFlexShrink(); void setFlexShrink(float flexShrink); - float getFlexBasis(); + YogaValue getFlexBasis(); void setFlexBasis(float flexBasis); - float getMargin(YogaEdge edge); + void setFlexBasisPercent(float percent); + YogaValue getMargin(YogaEdge edge); void setMargin(YogaEdge edge, float margin); - float getPadding(YogaEdge edge); + void setMarginPercent(YogaEdge edge, float percent); + YogaValue getPadding(YogaEdge edge); void setPadding(YogaEdge edge, float padding); + void setPaddingPercent(YogaEdge edge, float percent); float getBorder(YogaEdge edge); void setBorder(YogaEdge edge, float border); - float getPosition(YogaEdge edge); + YogaValue getPosition(YogaEdge edge); void setPosition(YogaEdge edge, float position); - float getWidth(); + void setPositionPercent(YogaEdge edge, float percent); + YogaValue getWidth(); void setWidth(float width); - float getHeight(); + void setWidthPercent(float percent); + YogaValue getHeight(); void setHeight(float height); - float getMaxWidth(); + void setHeightPercent(float percent); + YogaValue getMaxWidth(); void setMaxWidth(float maxWidth); - float getMinWidth(); + void setMaxWidthPercent(float percent); + YogaValue getMinWidth(); void setMinWidth(float minWidth); - float getMaxHeight(); + void setMinWidthPercent(float percent); + YogaValue getMaxHeight(); void setMaxHeight(float maxHeight); - float getMinHeight(); + void setMaxHeightPercent(float percent); + YogaValue getMinHeight(); void setMinHeight(float minHeight); + void setMinHeightPercent(float percent); float getLayoutX(); float getLayoutY(); float getLayoutWidth(); diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaUnit.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaUnit.java new file mode 100644 index 000000000..43e4b787b --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaUnit.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.yoga; + +import com.facebook.proguard.annotations.DoNotStrip; + +@DoNotStrip +public enum YogaUnit { + UNDEFINED(0), + PIXEL(1), + PERCENT(2); + + private int mIntValue; + + YogaUnit(int intValue) { + mIntValue = intValue; + } + + public int intValue() { + return mIntValue; + } + + public static YogaUnit fromInt(int value) { + switch (value) { + case 0: return UNDEFINED; + case 1: return PIXEL; + case 2: return PERCENT; + default: throw new IllegalArgumentException("Unkown enum value: " + value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaValue.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaValue.java new file mode 100644 index 000000000..c2d257fc2 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaValue.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +package com.facebook.yoga; + +import com.facebook.proguard.annotations.DoNotStrip; + +@DoNotStrip +public class YogaValue { + static final YogaValue UNDEFINED = new YogaValue(YogaConstants.UNDEFINED, YogaUnit.UNDEFINED); + static final YogaValue ZERO = new YogaValue(0, YogaUnit.PIXEL); + + public final float value; + public final YogaUnit unit; + + YogaValue(float value, YogaUnit unit) { + this.value = value; + this.unit = unit; + } + + @DoNotStrip + YogaValue(float value, int unit) { + this(value, YogaUnit.fromInt(unit)); + } + + @Override + public boolean equals(Object other) { + if (other instanceof YogaValue) { + final YogaValue otherValue = (YogaValue) other; + return value == otherValue.value && unit == otherValue.unit; + } + return false; + } + + @Override + public int hashCode() { + return Float.floatToIntBits(value) + unit.intValue(); + } +} diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index d0c2a8049..de648a4ba 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -7,9 +7,9 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -#include #include #include +#include using namespace facebook::jni; using namespace std; @@ -70,8 +70,8 @@ static YGSize YGJNIMeasureFunc(YGNodeRef node, int32_t wBits = 0xFFFFFFFF & (measureResult >> 32); int32_t hBits = 0xFFFFFFFF & measureResult; - const float *measuredWidth = reinterpret_cast(&wBits); - const float *measuredHeight = reinterpret_cast(&hBits); + const float *measuredWidth = reinterpret_cast(&wBits); + const float *measuredHeight = reinterpret_cast(&hBits); return YGSize{*measuredWidth, *measuredHeight}; } else { @@ -204,6 +204,14 @@ void jni_YGNodeCopyStyle(alias_ref, jlong dstNativePointer, jlong srcNa YGNodeCopyStyle(_jlong2YGNodeRef(dstNativePointer), _jlong2YGNodeRef(srcNativePointer)); } +struct JYogaValue : public JavaClass { + constexpr static auto kJavaDescriptor = "Lcom/facebook/yoga/YogaValue;"; + + static local_ref create(YGValue value) { + return newInstance(value.value, static_cast(value.unit)); + } +}; + #define YG_NODE_JNI_STYLE_PROP(javatype, type, name) \ javatype jni_YGNodeStyleGet##name(alias_ref, jlong nativePointer) { \ return (javatype) YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer)); \ @@ -213,6 +221,19 @@ void jni_YGNodeCopyStyle(alias_ref, jlong dstNativePointer, jlong srcNa YGNodeStyleSet##name(_jlong2YGNodeRef(nativePointer), static_cast(value)); \ } +#define YG_NODE_JNI_STYLE_UNIT_PROP(name) \ + local_ref jni_YGNodeStyleGet##name(alias_ref, jlong nativePointer) { \ + return JYogaValue::create(YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer))); \ + } \ + \ + void jni_YGNodeStyleSet##name(alias_ref, jlong nativePointer, jfloat value) { \ + YGNodeStyleSet##name(_jlong2YGNodeRef(nativePointer), static_cast(value)); \ + } \ + \ + void jni_YGNodeStyleSet##name##Percent(alias_ref, jlong nativePointer, jfloat value) { \ + YGNodeStyleSet##name##Percent(_jlong2YGNodeRef(nativePointer), static_cast(value)); \ + } + #define YG_NODE_JNI_STYLE_EDGE_PROP(javatype, type, name) \ javatype jni_YGNodeStyleGet##name(alias_ref, jlong nativePointer, jint edge) { \ return (javatype) YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer), \ @@ -228,6 +249,29 @@ void jni_YGNodeCopyStyle(alias_ref, jlong dstNativePointer, jlong srcNa static_cast(value)); \ } +#define YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(name) \ + local_ref jni_YGNodeStyleGet##name(alias_ref, \ + jlong nativePointer, \ + jint edge) { \ + return JYogaValue::create( \ + YGNodeStyleGet##name(_jlong2YGNodeRef(nativePointer), static_cast(edge))); \ + } \ + \ + void jni_YGNodeStyleSet##name(alias_ref, jlong nativePointer, jint edge, jfloat value) { \ + YGNodeStyleSet##name(_jlong2YGNodeRef(nativePointer), \ + static_cast(edge), \ + static_cast(value)); \ + } \ + \ + void jni_YGNodeStyleSet##name##Percent(alias_ref, \ + jlong nativePointer, \ + jint edge, \ + jfloat value) { \ + YGNodeStyleSet##name##Percent(_jlong2YGNodeRef(nativePointer), \ + static_cast(edge), \ + static_cast(value)); \ + } + YG_NODE_JNI_STYLE_PROP(jint, YGDirection, Direction); YG_NODE_JNI_STYLE_PROP(jint, YGFlexDirection, FlexDirection); YG_NODE_JNI_STYLE_PROP(jint, YGJustify, JustifyContent); @@ -243,19 +287,19 @@ void jni_YGNodeStyleSetFlex(alias_ref, jlong nativePointer, jfloat valu } YG_NODE_JNI_STYLE_PROP(jfloat, float, FlexGrow); YG_NODE_JNI_STYLE_PROP(jfloat, float, FlexShrink); -YG_NODE_JNI_STYLE_PROP(jfloat, float, FlexBasis); +YG_NODE_JNI_STYLE_UNIT_PROP(FlexBasis); -YG_NODE_JNI_STYLE_EDGE_PROP(jfloat, float, Position); -YG_NODE_JNI_STYLE_EDGE_PROP(jfloat, float, Margin); -YG_NODE_JNI_STYLE_EDGE_PROP(jfloat, float, Padding); +YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(Position); +YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(Margin); +YG_NODE_JNI_STYLE_EDGE_UNIT_PROP(Padding); YG_NODE_JNI_STYLE_EDGE_PROP(jfloat, float, Border); -YG_NODE_JNI_STYLE_PROP(jfloat, float, Width); -YG_NODE_JNI_STYLE_PROP(jfloat, float, MinWidth); -YG_NODE_JNI_STYLE_PROP(jfloat, float, MaxWidth); -YG_NODE_JNI_STYLE_PROP(jfloat, float, Height); -YG_NODE_JNI_STYLE_PROP(jfloat, float, MinHeight); -YG_NODE_JNI_STYLE_PROP(jfloat, float, MaxHeight); +YG_NODE_JNI_STYLE_UNIT_PROP(Width); +YG_NODE_JNI_STYLE_UNIT_PROP(MinWidth); +YG_NODE_JNI_STYLE_UNIT_PROP(MaxWidth); +YG_NODE_JNI_STYLE_UNIT_PROP(Height); +YG_NODE_JNI_STYLE_UNIT_PROP(MinHeight); +YG_NODE_JNI_STYLE_UNIT_PROP(MaxHeight); // Yoga specific properties, not compatible with flexbox specification YG_NODE_JNI_STYLE_PROP(jfloat, float, AspectRatio); @@ -278,7 +322,6 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGNodeMarkLayoutSeen), YGMakeNativeMethod(jni_YGNodeSetHasMeasureFunc), YGMakeNativeMethod(jni_YGNodeCopyStyle), - YGMakeNativeMethod(jni_YGNodeStyleGetDirection), YGMakeNativeMethod(jni_YGNodeStyleSetDirection), YGMakeNativeMethod(jni_YGNodeStyleGetFlexDirection), @@ -303,29 +346,38 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGNodeStyleSetFlexShrink), YGMakeNativeMethod(jni_YGNodeStyleGetFlexBasis), YGMakeNativeMethod(jni_YGNodeStyleSetFlexBasis), + YGMakeNativeMethod(jni_YGNodeStyleSetFlexBasisPercent), YGMakeNativeMethod(jni_YGNodeStyleGetMargin), YGMakeNativeMethod(jni_YGNodeStyleSetMargin), + YGMakeNativeMethod(jni_YGNodeStyleSetMarginPercent), YGMakeNativeMethod(jni_YGNodeStyleGetPadding), YGMakeNativeMethod(jni_YGNodeStyleSetPadding), + YGMakeNativeMethod(jni_YGNodeStyleSetPaddingPercent), YGMakeNativeMethod(jni_YGNodeStyleGetBorder), YGMakeNativeMethod(jni_YGNodeStyleSetBorder), YGMakeNativeMethod(jni_YGNodeStyleGetPosition), YGMakeNativeMethod(jni_YGNodeStyleSetPosition), + YGMakeNativeMethod(jni_YGNodeStyleSetPositionPercent), YGMakeNativeMethod(jni_YGNodeStyleGetWidth), YGMakeNativeMethod(jni_YGNodeStyleSetWidth), + YGMakeNativeMethod(jni_YGNodeStyleSetWidthPercent), YGMakeNativeMethod(jni_YGNodeStyleGetHeight), YGMakeNativeMethod(jni_YGNodeStyleSetHeight), + YGMakeNativeMethod(jni_YGNodeStyleSetHeightPercent), YGMakeNativeMethod(jni_YGNodeStyleGetMinWidth), YGMakeNativeMethod(jni_YGNodeStyleSetMinWidth), + YGMakeNativeMethod(jni_YGNodeStyleSetMinWidthPercent), YGMakeNativeMethod(jni_YGNodeStyleGetMinHeight), YGMakeNativeMethod(jni_YGNodeStyleSetMinHeight), + YGMakeNativeMethod(jni_YGNodeStyleSetMinHeightPercent), YGMakeNativeMethod(jni_YGNodeStyleGetMaxWidth), YGMakeNativeMethod(jni_YGNodeStyleSetMaxWidth), + YGMakeNativeMethod(jni_YGNodeStyleSetMaxWidthPercent), YGMakeNativeMethod(jni_YGNodeStyleGetMaxHeight), YGMakeNativeMethod(jni_YGNodeStyleSetMaxHeight), + YGMakeNativeMethod(jni_YGNodeStyleSetMaxHeightPercent), YGMakeNativeMethod(jni_YGNodeStyleGetAspectRatio), YGMakeNativeMethod(jni_YGNodeStyleSetAspectRatio), - YGMakeNativeMethod(jni_YGNodeGetInstanceCount), YGMakeNativeMethod(jni_YGSetLogger), YGMakeNativeMethod(jni_YGLog), diff --git a/ReactCommon/yoga/yoga/YGEnums.h b/ReactCommon/yoga/yoga/YGEnums.h index a64c1673b..be60e02cd 100644 --- a/ReactCommon/yoga/yoga/YGEnums.h +++ b/ReactCommon/yoga/yoga/YGEnums.h @@ -113,4 +113,11 @@ typedef enum YGAlign { YGAlignStretch, } YGAlign; +#define YGUnitCount 3 +typedef enum YGUnit { + YGUnitUndefined, + YGUnitPixel, + YGUnitPercent, +} YGUnit; + YG_EXTERN_C_END diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index 32bc01e4b..d42854443 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -77,14 +77,14 @@ typedef struct YGStyle { float flex; float flexGrow; float flexShrink; - float flexBasis; - float margin[YGEdgeCount]; - float position[YGEdgeCount]; - float padding[YGEdgeCount]; - float border[YGEdgeCount]; - float dimensions[2]; - float minDimensions[2]; - float maxDimensions[2]; + YGValue flexBasis; + YGValue margin[YGEdgeCount]; + YGValue position[YGEdgeCount]; + YGValue padding[YGEdgeCount]; + YGValue border[YGEdgeCount]; + YGValue dimensions[2]; + YGValue minDimensions[2]; + YGValue maxDimensions[2]; // Yoga specific properties, not compatible with flexbox specification float aspectRatio; @@ -106,64 +106,68 @@ typedef struct YGNode { void *context; } YGNode; -#define YG_DEFAULT_EDGE_VALUES { \ - [YGEdgeLeft] = YGUndefined, \ - [YGEdgeTop] = YGUndefined, \ - [YGEdgeRight] = YGUndefined, \ - [YGEdgeBottom] = YGUndefined, \ - [YGEdgeStart] = YGUndefined, \ - [YGEdgeEnd] = YGUndefined, \ - [YGEdgeHorizontal] = YGUndefined, \ - [YGEdgeVertical] = YGUndefined, \ - [YGEdgeAll] = YGUndefined, \ -} +#define YG_UNDEFINED_VALUES \ + { .value = YGUndefined, .unit = YGUnitUndefined } -#define YG_DEFAULT_DIMENSION_VALUES { \ - [YGDimensionWidth] = YGUndefined, \ - [YGDimensionHeight] = YGUndefined, \ -} +#define YG_DEFAULT_EDGE_VALUES_UNIT \ + { \ + [YGEdgeLeft] = YG_UNDEFINED_VALUES, [YGEdgeTop] = YG_UNDEFINED_VALUES, \ + [YGEdgeRight] = YG_UNDEFINED_VALUES, [YGEdgeBottom] = YG_UNDEFINED_VALUES, \ + [YGEdgeStart] = YG_UNDEFINED_VALUES, [YGEdgeEnd] = YG_UNDEFINED_VALUES, \ + [YGEdgeHorizontal] = YG_UNDEFINED_VALUES, [YGEdgeVertical] = YG_UNDEFINED_VALUES, \ + [YGEdgeAll] = YG_UNDEFINED_VALUES, \ + } -YGNode gYGNodeDefaults = { - .parent = NULL, - .children = NULL, - .hasNewLayout = true, - .isDirty = false, +#define YG_DEFAULT_DIMENSION_VALUES \ + { [YGDimensionWidth] = YGUndefined, [YGDimensionHeight] = YGUndefined, } - .style = { - .flex = YGUndefined, - .flexGrow = YGUndefined, - .flexShrink = YGUndefined, - .flexBasis = YGUndefined, - .justifyContent = YGJustifyFlexStart, - .alignItems = YGAlignStretch, - .alignContent = YGAlignFlexStart, - .direction = YGDirectionInherit, - .flexDirection = YGFlexDirectionColumn, - .overflow = YGOverflowVisible, - .dimensions = YG_DEFAULT_DIMENSION_VALUES, - .minDimensions = YG_DEFAULT_DIMENSION_VALUES, - .maxDimensions = YG_DEFAULT_DIMENSION_VALUES, - .position = YG_DEFAULT_EDGE_VALUES, - .margin = YG_DEFAULT_EDGE_VALUES, - .padding = YG_DEFAULT_EDGE_VALUES, - .border = YG_DEFAULT_EDGE_VALUES, - .aspectRatio = YGUndefined, - }, +#define YG_DEFAULT_DIMENSION_VALUES_UNIT \ + { [YGDimensionWidth] = YG_UNDEFINED_VALUES, [YGDimensionHeight] = YG_UNDEFINED_VALUES, } - .layout = { - .dimensions = YG_DEFAULT_DIMENSION_VALUES, - .lastParentDirection = (YGDirection) -1, - .nextCachedMeasurementsIndex = 0, - .computedFlexBasis = YGUndefined, - .measuredDimensions = YG_DEFAULT_DIMENSION_VALUES, +static YGNode gYGNodeDefaults = { + .parent = NULL, + .children = NULL, + .hasNewLayout = true, + .isDirty = false, - .cachedLayout = { - .widthMeasureMode = (YGMeasureMode) -1, - .heightMeasureMode = (YGMeasureMode) -1, - .computedWidth = -1, - .computedHeight = -1, - }, - }, + .style = + { + .flex = YGUndefined, + .flexGrow = YGUndefined, + .flexShrink = YGUndefined, + .flexBasis = YG_UNDEFINED_VALUES, + .justifyContent = YGJustifyFlexStart, + .alignItems = YGAlignStretch, + .alignContent = YGAlignFlexStart, + .direction = YGDirectionInherit, + .flexDirection = YGFlexDirectionColumn, + .overflow = YGOverflowVisible, + .dimensions = YG_DEFAULT_DIMENSION_VALUES_UNIT, + .minDimensions = YG_DEFAULT_DIMENSION_VALUES_UNIT, + .maxDimensions = YG_DEFAULT_DIMENSION_VALUES_UNIT, + .position = YG_DEFAULT_EDGE_VALUES_UNIT, + .margin = YG_DEFAULT_EDGE_VALUES_UNIT, + .padding = YG_DEFAULT_EDGE_VALUES_UNIT, + .border = YG_DEFAULT_EDGE_VALUES_UNIT, + .aspectRatio = YGUndefined, + }, + + .layout = + { + .dimensions = YG_DEFAULT_DIMENSION_VALUES, + .lastParentDirection = (YGDirection) -1, + .nextCachedMeasurementsIndex = 0, + .computedFlexBasis = YGUndefined, + .measuredDimensions = YG_DEFAULT_DIMENSION_VALUES, + + .cachedLayout = + { + .widthMeasureMode = (YGMeasureMode) -1, + .heightMeasureMode = (YGMeasureMode) -1, + .computedWidth = -1, + .computedHeight = -1, + }, + }, }; static void YGNodeMarkDirtyInternal(const YGNodeRef node); @@ -173,6 +177,10 @@ YGCalloc gYGCalloc = &calloc; YGRealloc gYGRealloc = &realloc; YGFree gYGFree = &free; +static YGValue YGValueUndefined = YG_UNDEFINED_VALUES; + +static YGValue YGValueZero = {.value = 0, .unit = YGUnitPixel}; + #ifdef ANDROID #include static int YGAndroidLog(YGLogLevel level, const char *format, va_list args) { @@ -214,35 +222,44 @@ static int YGDefaultLog(YGLogLevel level, const char *format, va_list args) { static YGLogger gLogger = &YGDefaultLog; #endif -static inline float YGComputedEdgeValue(const float edges[YGEdgeCount], - const YGEdge edge, - const float defaultValue) { +static inline const YGValue *YGComputedEdgeValue(const YGValue edges[YGEdgeCount], + const YGEdge edge, + const YGValue *const defaultValue) { YG_ASSERT(edge <= YGEdgeEnd, "Cannot get computed value of multi-edge shorthands"); - if (!YGValueIsUndefined(edges[edge])) { - return edges[edge]; + if (edges[edge].unit != YGUnitUndefined) { + return &edges[edge]; } - if ((edge == YGEdgeTop || edge == YGEdgeBottom) && !YGValueIsUndefined(edges[YGEdgeVertical])) { - return edges[YGEdgeVertical]; + if ((edge == YGEdgeTop || edge == YGEdgeBottom) && + edges[YGEdgeVertical].unit != YGUnitUndefined) { + return &edges[YGEdgeVertical]; } if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart || edge == YGEdgeEnd) && - !YGValueIsUndefined(edges[YGEdgeHorizontal])) { - return edges[YGEdgeHorizontal]; + edges[YGEdgeHorizontal].unit != YGUnitUndefined) { + return &edges[YGEdgeHorizontal]; } - if (!YGValueIsUndefined(edges[YGEdgeAll])) { - return edges[YGEdgeAll]; + if (edges[YGEdgeAll].unit != YGUnitUndefined) { + return &edges[YGEdgeAll]; } if (edge == YGEdgeStart || edge == YGEdgeEnd) { - return YGUndefined; + return &YGValueUndefined; } return defaultValue; } +static inline float YGValueResolve(const YGValue *const unit, const float parentSize) { + if (unit->unit == YGUnitPixel) { + return unit->value; + } else { + return unit->value * parentSize / 100.0f; + } +} + int32_t gNodeInstanceCount = 0; YGNodeRef YGNodeNew(void) { @@ -281,7 +298,8 @@ void YGNodeFreeRecursive(const YGNodeRef root) { } void YGNodeReset(const YGNodeRef node) { - YG_ASSERT(YGNodeGetChildCount(node) == 0, "Cannot reset a node which still has children attached"); + YG_ASSERT(YGNodeGetChildCount(node) == 0, + "Cannot reset a node which still has children attached"); YG_ASSERT(node->parent == NULL, "Cannot reset a node still attached to a parent"); YGNodeListFree(node->children); @@ -363,33 +381,37 @@ void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) { } inline float YGNodeStyleGetFlexGrow(const YGNodeRef node) { - if (!YGValueIsUndefined(node->style.flexGrow)) { + if (!YGFloatIsUndefined(node->style.flexGrow)) { return node->style.flexGrow; } - if (!YGValueIsUndefined(node->style.flex) && node->style.flex > 0) { + if (!YGFloatIsUndefined(node->style.flex) && node->style.flex > 0.0f) { return node->style.flex; } - return 0; + return 0.0f; } inline float YGNodeStyleGetFlexShrink(const YGNodeRef node) { - if (!YGValueIsUndefined(node->style.flexShrink)) { + if (!YGFloatIsUndefined(node->style.flexShrink)) { return node->style.flexShrink; } - if (!YGValueIsUndefined(node->style.flex) && node->style.flex < 0) { + if (!YGFloatIsUndefined(node->style.flex) && node->style.flex < 0.0f) { return -node->style.flex; } - return 0; + return 0.0f; } -inline float YGNodeStyleGetFlexBasis(const YGNodeRef node) { - if (!YGValueIsUndefined(node->style.flexBasis)) { - return node->style.flexBasis; +static inline const YGValue *YGNodeStyleGetFlexBasisPtr(const YGNodeRef node) { + if (node->style.flexBasis.unit != YGUnitUndefined) { + return &node->style.flexBasis; } - if (!YGValueIsUndefined(node->style.flex)) { - return node->style.flex > 0 ? 0 : YGUndefined; + if (!YGFloatIsUndefined(node->style.flex) && node->style.flex > 0.0f) { + return &YGValueZero; } - return YGUndefined; + return &YGValueUndefined; +} + +inline YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) { + return *YGNodeStyleGetFlexBasisPtr(node); } void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { @@ -416,6 +438,27 @@ void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { } \ } +#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(type, name, paramName, instanceName) \ + void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \ + if (node->style.instanceName.value != paramName || \ + node->style.instanceName.unit != YGUnitPixel) { \ + node->style.instanceName.value = paramName; \ + node->style.instanceName.unit = \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPixel; \ + YGNodeMarkDirtyInternal(node); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent(const YGNodeRef node, const type paramName) { \ + if (node->style.instanceName.value != paramName || \ + node->style.instanceName.unit != YGUnitPercent) { \ + node->style.instanceName.value = paramName; \ + node->style.instanceName.unit = \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent; \ + YGNodeMarkDirtyInternal(node); \ + } \ + } + #define YG_NODE_STYLE_PROPERTY_IMPL(type, name, paramName, instanceName) \ YG_NODE_STYLE_PROPERTY_SETTER_IMPL(type, name, paramName, instanceName) \ \ @@ -423,16 +466,53 @@ void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { return node->style.instanceName; \ } -#define YG_NODE_STYLE_EDGE_PROPERTY_IMPL(type, name, paramName, instanceName, defaultValue) \ - void YGNodeStyleSet##name(const YGNodeRef node, const YGEdge edge, const type paramName) { \ - if (node->style.instanceName[edge] != paramName) { \ - node->style.instanceName[edge] = paramName; \ - YGNodeMarkDirtyInternal(node); \ - } \ - } \ - \ - type YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ - return YGComputedEdgeValue(node->style.instanceName, edge, defaultValue); \ +#define YG_NODE_STYLE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName) \ + YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(float, name, paramName, instanceName) \ + \ + type YGNodeStyleGet##name(const YGNodeRef node) { \ + return node->style.instanceName; \ + } + +#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName, defaultValue) \ + void YGNodeStyleSet##name(const YGNodeRef node, const YGEdge edge, const float paramName) { \ + if (node->style.instanceName[edge].value != paramName || \ + node->style.instanceName[edge].unit != YGUnitPixel) { \ + node->style.instanceName[edge].value = paramName; \ + node->style.instanceName[edge].unit = \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPixel; \ + YGNodeMarkDirtyInternal(node); \ + } \ + } \ + \ + void YGNodeStyleSet##name##Percent(const YGNodeRef node, \ + const YGEdge edge, \ + const float paramName) { \ + if (node->style.instanceName[edge].value != paramName || \ + node->style.instanceName[edge].unit != YGUnitPercent) { \ + node->style.instanceName[edge].value = paramName; \ + node->style.instanceName[edge].unit = \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent; \ + YGNodeMarkDirtyInternal(node); \ + } \ + } \ + \ + type YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ + return *YGComputedEdgeValue(node->style.instanceName, edge, &defaultValue); \ + } + +#define YG_NODE_STYLE_EDGE_PROPERTY_IMPL(type, name, paramName, instanceName, defaultValue) \ + void YGNodeStyleSet##name(const YGNodeRef node, const YGEdge edge, const float paramName) { \ + if (node->style.instanceName[edge].value != paramName || \ + node->style.instanceName[edge].unit != YGUnitPixel) { \ + node->style.instanceName[edge].value = paramName; \ + node->style.instanceName[edge].unit = \ + YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPixel; \ + YGNodeMarkDirtyInternal(node); \ + } \ + } \ + \ + float YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \ + return YGComputedEdgeValue(node->style.instanceName, edge, &defaultValue)->value; \ } #define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \ @@ -456,19 +536,19 @@ YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow); YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow); YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexShrink, flexShrink, flexShrink); -YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexBasis, flexBasis, flexBasis); +YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL(float, FlexBasis, flexBasis, flexBasis); -YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Position, position, position, YGUndefined); -YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Margin, margin, margin, 0); -YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Padding, padding, padding, 0); -YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Border, border, border, 0); +YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position, YGValueUndefined); +YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin, YGValueZero); +YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding, YGValueZero); +YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Border, border, border, YGValueZero); -YG_NODE_STYLE_PROPERTY_IMPL(float, Width, width, dimensions[YGDimensionWidth]); -YG_NODE_STYLE_PROPERTY_IMPL(float, Height, height, dimensions[YGDimensionHeight]); -YG_NODE_STYLE_PROPERTY_IMPL(float, MinWidth, minWidth, minDimensions[YGDimensionWidth]); -YG_NODE_STYLE_PROPERTY_IMPL(float, MinHeight, minHeight, minDimensions[YGDimensionHeight]); -YG_NODE_STYLE_PROPERTY_IMPL(float, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]); -YG_NODE_STYLE_PROPERTY_IMPL(float, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]); +YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]); +YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]); +YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinWidth, minWidth, minDimensions[YGDimensionWidth]); +YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MinHeight, minHeight, minDimensions[YGDimensionHeight]); +YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxWidth, maxWidth, maxDimensions[YGDimensionWidth]); +YG_NODE_STYLE_PROPERTY_UNIT_IMPL(YGValue, MaxHeight, maxHeight, maxDimensions[YGDimensionHeight]); // Yoga specific properties, not compatible with flexbox specification YG_NODE_STYLE_PROPERTY_IMPL(float, AspectRatio, aspectRatio, aspectRatio); @@ -489,18 +569,32 @@ bool YGLayoutNodeInternal(const YGNodeRef node, const YGDirection parentDirection, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, + const float parentWidth, + const float parentHeight, const bool performLayout, const char *reason); -inline bool YGValueIsUndefined(const float value) { +inline bool YGFloatIsUndefined(const float value) { return isnan(value); } -static inline bool YGFloatsEqual(const float a, const float b) { - if (YGValueIsUndefined(a)) { - return YGValueIsUndefined(b); +static inline bool YGValueEqual(const YGValue a, const YGValue b) { + if (a.unit != b.unit) { + return false; } - return fabs(a - b) < 0.0001; + + if (a.unit == YGUnitUndefined) { + return true; + } + + return fabs(a.value - b.value) < 0.0001f; +} + +static inline bool YGFloatsEqual(const float a, const float b) { + if (YGFloatIsUndefined(a)) { + return YGFloatIsUndefined(b); + } + return fabs(a - b) < 0.0001f; } static void YGIndent(const uint32_t n) { @@ -509,21 +603,35 @@ static void YGIndent(const uint32_t n) { } } -static void YGPrintNumberIfNotZero(const char *str, const float number) { - if (!YGFloatsEqual(number, 0)) { +static void YGPrintNumberIfNotZero(const char *str, const YGValue *const number) { + if (!YGFloatsEqual(number->value, 0)) { + YGLog(YGLogLevelDebug, + "%s: %g%s, ", + str, + number->value, + number->unit == YGUnitPixel ? "px" : "%"); + } +} + +static void YGPrintNumberIfNotUndefinedf(const char *str, const float number) { + if (!YGFloatIsUndefined(number)) { YGLog(YGLogLevelDebug, "%s: %g, ", str, number); } } -static void YGPrintNumberIfNotUndefined(const char *str, const float number) { - if (!YGValueIsUndefined(number)) { - YGLog(YGLogLevelDebug, "%s: %g, ", str, number); +static void YGPrintNumberIfNotUndefined(const char *str, const YGValue *const number) { + if (number->unit != YGUnitUndefined) { + YGLog(YGLogLevelDebug, + "%s: %g%s, ", + str, + number->value, + number->unit == YGUnitPixel ? "px" : "%"); } } -static bool YGFourFloatsEqual(const float four[4]) { - return YGFloatsEqual(four[0], four[1]) && YGFloatsEqual(four[0], four[2]) && - YGFloatsEqual(four[0], four[3]); +static bool YGFourValuesEqual(const YGValue four[4]) { + return YGValueEqual(four[0], four[1]) && YGValueEqual(four[0], four[2]) && + YGValueEqual(four[0], four[3]); } static void YGNodePrintInternal(const YGNodeRef node, @@ -592,9 +700,9 @@ static void YGNodePrintInternal(const YGNodeRef node, YGLog(YGLogLevelDebug, "alignSelf: 'stretch', "); } - YGPrintNumberIfNotUndefined("flexGrow", YGNodeStyleGetFlexGrow(node)); - YGPrintNumberIfNotUndefined("flexShrink", YGNodeStyleGetFlexShrink(node)); - YGPrintNumberIfNotUndefined("flexBasis", YGNodeStyleGetFlexBasis(node)); + YGPrintNumberIfNotUndefinedf("flexGrow", YGNodeStyleGetFlexGrow(node)); + YGPrintNumberIfNotUndefinedf("flexShrink", YGNodeStyleGetFlexShrink(node)); + YGPrintNumberIfNotUndefined("flexBasis", YGNodeStyleGetFlexBasisPtr(node)); if (node->style.overflow == YGOverflowHidden) { YGLog(YGLogLevelDebug, "overflow: 'hidden', "); @@ -604,71 +712,79 @@ static void YGNodePrintInternal(const YGNodeRef node, YGLog(YGLogLevelDebug, "overflow: 'scroll', "); } - if (YGFourFloatsEqual(node->style.margin)) { - YGPrintNumberIfNotZero("margin", YGComputedEdgeValue(node->style.margin, YGEdgeLeft, 0)); + if (YGFourValuesEqual(node->style.margin)) { + YGPrintNumberIfNotZero("margin", + YGComputedEdgeValue(node->style.margin, YGEdgeLeft, &YGValueZero)); } else { - YGPrintNumberIfNotZero("marginLeft", YGComputedEdgeValue(node->style.margin, YGEdgeLeft, 0)); + YGPrintNumberIfNotZero("marginLeft", + YGComputedEdgeValue(node->style.margin, YGEdgeLeft, &YGValueZero)); YGPrintNumberIfNotZero("marginRight", - YGComputedEdgeValue(node->style.margin, YGEdgeRight, 0)); - YGPrintNumberIfNotZero("marginTop", YGComputedEdgeValue(node->style.margin, YGEdgeTop, 0)); + YGComputedEdgeValue(node->style.margin, YGEdgeRight, &YGValueZero)); + YGPrintNumberIfNotZero("marginTop", + YGComputedEdgeValue(node->style.margin, YGEdgeTop, &YGValueZero)); YGPrintNumberIfNotZero("marginBottom", - YGComputedEdgeValue(node->style.margin, YGEdgeBottom, 0)); + YGComputedEdgeValue(node->style.margin, YGEdgeBottom, &YGValueZero)); YGPrintNumberIfNotZero("marginStart", - YGComputedEdgeValue(node->style.margin, YGEdgeStart, 0)); - YGPrintNumberIfNotZero("marginEnd", YGComputedEdgeValue(node->style.margin, YGEdgeEnd, 0)); + YGComputedEdgeValue(node->style.margin, YGEdgeStart, &YGValueZero)); + YGPrintNumberIfNotZero("marginEnd", + YGComputedEdgeValue(node->style.margin, YGEdgeEnd, &YGValueZero)); } - if (YGFourFloatsEqual(node->style.padding)) { - YGPrintNumberIfNotZero("padding", YGComputedEdgeValue(node->style.padding, YGEdgeLeft, 0)); + if (YGFourValuesEqual(node->style.padding)) { + YGPrintNumberIfNotZero("padding", + YGComputedEdgeValue(node->style.padding, YGEdgeLeft, &YGValueZero)); } else { YGPrintNumberIfNotZero("paddingLeft", - YGComputedEdgeValue(node->style.padding, YGEdgeLeft, 0)); + YGComputedEdgeValue(node->style.padding, YGEdgeLeft, &YGValueZero)); YGPrintNumberIfNotZero("paddingRight", - YGComputedEdgeValue(node->style.padding, YGEdgeRight, 0)); - YGPrintNumberIfNotZero("paddingTop", YGComputedEdgeValue(node->style.padding, YGEdgeTop, 0)); + YGComputedEdgeValue(node->style.padding, YGEdgeRight, &YGValueZero)); + YGPrintNumberIfNotZero("paddingTop", + YGComputedEdgeValue(node->style.padding, YGEdgeTop, &YGValueZero)); YGPrintNumberIfNotZero("paddingBottom", - YGComputedEdgeValue(node->style.padding, YGEdgeBottom, 0)); + YGComputedEdgeValue(node->style.padding, YGEdgeBottom, &YGValueZero)); YGPrintNumberIfNotZero("paddingStart", - YGComputedEdgeValue(node->style.padding, YGEdgeStart, 0)); - YGPrintNumberIfNotZero("paddingEnd", YGComputedEdgeValue(node->style.padding, YGEdgeEnd, 0)); + YGComputedEdgeValue(node->style.padding, YGEdgeStart, &YGValueZero)); + YGPrintNumberIfNotZero("paddingEnd", + YGComputedEdgeValue(node->style.padding, YGEdgeEnd, &YGValueZero)); } - if (YGFourFloatsEqual(node->style.border)) { - YGPrintNumberIfNotZero("borderWidth", YGComputedEdgeValue(node->style.border, YGEdgeLeft, 0)); + if (YGFourValuesEqual(node->style.border)) { + YGPrintNumberIfNotZero("borderWidth", + YGComputedEdgeValue(node->style.border, YGEdgeLeft, &YGValueZero)); } else { YGPrintNumberIfNotZero("borderLeftWidth", - YGComputedEdgeValue(node->style.border, YGEdgeLeft, 0)); + YGComputedEdgeValue(node->style.border, YGEdgeLeft, &YGValueZero)); YGPrintNumberIfNotZero("borderRightWidth", - YGComputedEdgeValue(node->style.border, YGEdgeRight, 0)); + YGComputedEdgeValue(node->style.border, YGEdgeRight, &YGValueZero)); YGPrintNumberIfNotZero("borderTopWidth", - YGComputedEdgeValue(node->style.border, YGEdgeTop, 0)); + YGComputedEdgeValue(node->style.border, YGEdgeTop, &YGValueZero)); YGPrintNumberIfNotZero("borderBottomWidth", - YGComputedEdgeValue(node->style.border, YGEdgeBottom, 0)); + YGComputedEdgeValue(node->style.border, YGEdgeBottom, &YGValueZero)); YGPrintNumberIfNotZero("borderStartWidth", - YGComputedEdgeValue(node->style.border, YGEdgeStart, 0)); + YGComputedEdgeValue(node->style.border, YGEdgeStart, &YGValueZero)); YGPrintNumberIfNotZero("borderEndWidth", - YGComputedEdgeValue(node->style.border, YGEdgeEnd, 0)); + YGComputedEdgeValue(node->style.border, YGEdgeEnd, &YGValueZero)); } - YGPrintNumberIfNotUndefined("width", node->style.dimensions[YGDimensionWidth]); - YGPrintNumberIfNotUndefined("height", node->style.dimensions[YGDimensionHeight]); - YGPrintNumberIfNotUndefined("maxWidth", node->style.maxDimensions[YGDimensionWidth]); - YGPrintNumberIfNotUndefined("maxHeight", node->style.maxDimensions[YGDimensionHeight]); - YGPrintNumberIfNotUndefined("minWidth", node->style.minDimensions[YGDimensionWidth]); - YGPrintNumberIfNotUndefined("minHeight", node->style.minDimensions[YGDimensionHeight]); + YGPrintNumberIfNotUndefined("width", &node->style.dimensions[YGDimensionWidth]); + YGPrintNumberIfNotUndefined("height", &node->style.dimensions[YGDimensionHeight]); + YGPrintNumberIfNotUndefined("maxWidth", &node->style.maxDimensions[YGDimensionWidth]); + YGPrintNumberIfNotUndefined("maxHeight", &node->style.maxDimensions[YGDimensionHeight]); + YGPrintNumberIfNotUndefined("minWidth", &node->style.minDimensions[YGDimensionWidth]); + YGPrintNumberIfNotUndefined("minHeight", &node->style.minDimensions[YGDimensionHeight]); if (node->style.positionType == YGPositionTypeAbsolute) { YGLog(YGLogLevelDebug, "position: 'absolute', "); } - YGPrintNumberIfNotUndefined("left", - YGComputedEdgeValue(node->style.position, YGEdgeLeft, YGUndefined)); YGPrintNumberIfNotUndefined( - "right", YGComputedEdgeValue(node->style.position, YGEdgeRight, YGUndefined)); - YGPrintNumberIfNotUndefined("top", - YGComputedEdgeValue(node->style.position, YGEdgeTop, YGUndefined)); + "left", YGComputedEdgeValue(node->style.position, YGEdgeLeft, &YGValueUndefined)); YGPrintNumberIfNotUndefined( - "bottom", YGComputedEdgeValue(node->style.position, YGEdgeBottom, YGUndefined)); + "right", YGComputedEdgeValue(node->style.position, YGEdgeRight, &YGValueUndefined)); + YGPrintNumberIfNotUndefined( + "top", YGComputedEdgeValue(node->style.position, YGEdgeTop, &YGValueUndefined)); + YGPrintNumberIfNotUndefined( + "bottom", YGComputedEdgeValue(node->style.position, YGEdgeBottom, &YGValueUndefined)); } const uint32_t childCount = YGNodeListCount(node->children); @@ -721,75 +837,95 @@ static inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) return flexDirection == YGFlexDirectionColumn || flexDirection == YGFlexDirectionColumnReverse; } -static inline float YGNodeLeadingMargin(const YGNodeRef node, const YGFlexDirection axis) { - if (YGFlexDirectionIsRow(axis) && !YGValueIsUndefined(node->style.margin[YGEdgeStart])) { - return node->style.margin[YGEdgeStart]; +static inline float YGNodeLeadingMargin(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { + if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeStart].unit != YGUnitUndefined) { + return YGValueResolve(&node->style.margin[YGEdgeStart], widthSize); } - return YGComputedEdgeValue(node->style.margin, leading[axis], 0); + return YGValueResolve(YGComputedEdgeValue(node->style.margin, leading[axis], &YGValueZero), + widthSize); } -static float YGNodeTrailingMargin(const YGNodeRef node, const YGFlexDirection axis) { - if (YGFlexDirectionIsRow(axis) && !YGValueIsUndefined(node->style.margin[YGEdgeEnd])) { - return node->style.margin[YGEdgeEnd]; +static float YGNodeTrailingMargin(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { + if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeEnd].unit != YGUnitUndefined) { + return YGValueResolve(&node->style.margin[YGEdgeEnd], widthSize); } - return YGComputedEdgeValue(node->style.margin, trailing[axis], 0); + return YGValueResolve(YGComputedEdgeValue(node->style.margin, trailing[axis], &YGValueZero), + widthSize); } -static float YGNodeLeadingPadding(const YGNodeRef node, const YGFlexDirection axis) { - if (YGFlexDirectionIsRow(axis) && !YGValueIsUndefined(node->style.padding[YGEdgeStart]) && - node->style.padding[YGEdgeStart] >= 0) { - return node->style.padding[YGEdgeStart]; +static float YGNodeLeadingPadding(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { + if (YGFlexDirectionIsRow(axis) && node->style.padding[YGEdgeStart].unit != YGUnitUndefined && + YGValueResolve(&node->style.padding[YGEdgeStart], widthSize) >= 0.0f) { + return YGValueResolve(&node->style.padding[YGEdgeStart], widthSize); } - return fmaxf(YGComputedEdgeValue(node->style.padding, leading[axis], 0), 0); + return fmaxf(YGValueResolve(YGComputedEdgeValue(node->style.padding, leading[axis], &YGValueZero), + widthSize), + 0.0f); } -static float YGNodeTrailingPadding(const YGNodeRef node, const YGFlexDirection axis) { - if (YGFlexDirectionIsRow(axis) && !YGValueIsUndefined(node->style.padding[YGEdgeEnd]) && - node->style.padding[YGEdgeEnd] >= 0) { - return node->style.padding[YGEdgeEnd]; +static float YGNodeTrailingPadding(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { + if (YGFlexDirectionIsRow(axis) && node->style.padding[YGEdgeEnd].unit != YGUnitUndefined && + YGValueResolve(&node->style.padding[YGEdgeEnd], widthSize) >= 0.0f) { + return YGValueResolve(&node->style.padding[YGEdgeEnd], widthSize); } - return fmaxf(YGComputedEdgeValue(node->style.padding, trailing[axis], 0), 0); + return fmaxf(YGValueResolve(YGComputedEdgeValue(node->style.padding, trailing[axis], &YGValueZero), + widthSize), + 0.0f); } static float YGNodeLeadingBorder(const YGNodeRef node, const YGFlexDirection axis) { - if (YGFlexDirectionIsRow(axis) && !YGValueIsUndefined(node->style.border[YGEdgeStart]) && - node->style.border[YGEdgeStart] >= 0) { - return node->style.border[YGEdgeStart]; + if (YGFlexDirectionIsRow(axis) && node->style.border[YGEdgeStart].unit != YGUnitUndefined && + node->style.border[YGEdgeStart].value >= 0.0f) { + return node->style.border[YGEdgeStart].value; } - return fmaxf(YGComputedEdgeValue(node->style.border, leading[axis], 0), 0); + return fmaxf(YGComputedEdgeValue(node->style.border, leading[axis], &YGValueZero)->value, 0.0f); } static float YGNodeTrailingBorder(const YGNodeRef node, const YGFlexDirection axis) { - if (YGFlexDirectionIsRow(axis) && !YGValueIsUndefined(node->style.border[YGEdgeEnd]) && - node->style.border[YGEdgeEnd] >= 0) { - return node->style.border[YGEdgeEnd]; + if (YGFlexDirectionIsRow(axis) && node->style.border[YGEdgeEnd].unit != YGUnitUndefined && + node->style.border[YGEdgeEnd].value >= 0.0f) { + return node->style.border[YGEdgeEnd].value; } - return fmaxf(YGComputedEdgeValue(node->style.border, trailing[axis], 0), 0); + return fmaxf(YGComputedEdgeValue(node->style.border, trailing[axis], &YGValueZero)->value, 0.0f); } static inline float YGNodeLeadingPaddingAndBorder(const YGNodeRef node, - const YGFlexDirection axis) { - return YGNodeLeadingPadding(node, axis) + YGNodeLeadingBorder(node, axis); + const YGFlexDirection axis, + const float widthSize) { + return YGNodeLeadingPadding(node, axis, widthSize) + YGNodeLeadingBorder(node, axis); } static inline float YGNodeTrailingPaddingAndBorder(const YGNodeRef node, - const YGFlexDirection axis) { - return YGNodeTrailingPadding(node, axis) + YGNodeTrailingBorder(node, axis); + const YGFlexDirection axis, + const float widthSize) { + return YGNodeTrailingPadding(node, axis, widthSize) + YGNodeTrailingBorder(node, axis); } -static inline float YGNodeMarginForAxis(const YGNodeRef node, const YGFlexDirection axis) { - return YGNodeLeadingMargin(node, axis) + YGNodeTrailingMargin(node, axis); +static inline float YGNodeMarginForAxis(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { + return YGNodeLeadingMargin(node, axis, widthSize) + YGNodeTrailingMargin(node, axis, widthSize); } static inline float YGNodePaddingAndBorderForAxis(const YGNodeRef node, - const YGFlexDirection axis) { - return YGNodeLeadingPaddingAndBorder(node, axis) + YGNodeTrailingPaddingAndBorder(node, axis); + const YGFlexDirection axis, + const float widthSize) { + return YGNodeLeadingPaddingAndBorder(node, axis, widthSize) + + YGNodeTrailingPaddingAndBorder(node, axis, widthSize); } static inline YGAlign YGNodeAlignItem(const YGNodeRef node, const YGNodeRef child) { @@ -830,86 +966,97 @@ static inline bool YGNodeIsFlex(const YGNodeRef node) { (YGNodeStyleGetFlexGrow(node) != 0 || YGNodeStyleGetFlexShrink(node) != 0)); } -static inline float YGNodeDimWithMargin(const YGNodeRef node, const YGFlexDirection axis) { - return node->layout.measuredDimensions[dim[axis]] + YGNodeLeadingMargin(node, axis) + - YGNodeTrailingMargin(node, axis); +static inline float YGNodeDimWithMargin(const YGNodeRef node, + const YGFlexDirection axis, + const float widthSize) { + return node->layout.measuredDimensions[dim[axis]] + YGNodeLeadingMargin(node, axis, widthSize) + + YGNodeTrailingMargin(node, axis, widthSize); } static inline bool YGNodeIsStyleDimDefined(const YGNodeRef node, const YGFlexDirection axis) { - const float value = node->style.dimensions[dim[axis]]; - return !YGValueIsUndefined(value) && value >= 0.0; + return node->style.dimensions[dim[axis]].unit != YGUnitUndefined && + node->style.dimensions[dim[axis]].value >= 0.0f; } static inline bool YGNodeIsLayoutDimDefined(const YGNodeRef node, const YGFlexDirection axis) { const float value = node->layout.measuredDimensions[dim[axis]]; - return !YGValueIsUndefined(value) && value >= 0.0; + return !YGFloatIsUndefined(value) && value >= 0.0f; } static inline bool YGNodeIsLeadingPosDefined(const YGNodeRef node, const YGFlexDirection axis) { return (YGFlexDirectionIsRow(axis) && - !YGValueIsUndefined( - YGComputedEdgeValue(node->style.position, YGEdgeStart, YGUndefined))) || - !YGValueIsUndefined(YGComputedEdgeValue(node->style.position, leading[axis], YGUndefined)); + YGComputedEdgeValue(node->style.position, YGEdgeStart, &YGValueUndefined)->unit != + YGUnitUndefined) || + YGComputedEdgeValue(node->style.position, leading[axis], &YGValueUndefined)->unit != + YGUnitUndefined; } static inline bool YGNodeIsTrailingPosDefined(const YGNodeRef node, const YGFlexDirection axis) { return (YGFlexDirectionIsRow(axis) && - !YGValueIsUndefined(YGComputedEdgeValue(node->style.position, YGEdgeEnd, YGUndefined))) || - !YGValueIsUndefined( - YGComputedEdgeValue(node->style.position, trailing[axis], YGUndefined)); + YGComputedEdgeValue(node->style.position, YGEdgeEnd, &YGValueUndefined)->unit != + YGUnitUndefined) || + YGComputedEdgeValue(node->style.position, trailing[axis], &YGValueUndefined)->unit != + YGUnitUndefined; } -static float YGNodeLeadingPosition(const YGNodeRef node, const YGFlexDirection axis) { +static float YGNodeLeadingPosition(const YGNodeRef node, + const YGFlexDirection axis, + const float axisSize) { if (YGFlexDirectionIsRow(axis)) { - const float leadingPosition = - YGComputedEdgeValue(node->style.position, YGEdgeStart, YGUndefined); - if (!YGValueIsUndefined(leadingPosition)) { - return leadingPosition; + const YGValue *leadingPosition = + YGComputedEdgeValue(node->style.position, YGEdgeStart, &YGValueUndefined); + if (leadingPosition->unit != YGUnitUndefined) { + return YGValueResolve(leadingPosition, axisSize); } } - const float leadingPosition = - YGComputedEdgeValue(node->style.position, leading[axis], YGUndefined); + const YGValue *leadingPosition = + YGComputedEdgeValue(node->style.position, leading[axis], &YGValueUndefined); - return YGValueIsUndefined(leadingPosition) ? 0 : leadingPosition; + return leadingPosition->unit == YGUnitUndefined ? 0.0f + : YGValueResolve(leadingPosition, axisSize); } -static float YGNodeTrailingPosition(const YGNodeRef node, const YGFlexDirection axis) { +static float YGNodeTrailingPosition(const YGNodeRef node, + const YGFlexDirection axis, + const float axisSize) { if (YGFlexDirectionIsRow(axis)) { - const float trailingPosition = - YGComputedEdgeValue(node->style.position, YGEdgeEnd, YGUndefined); - if (!YGValueIsUndefined(trailingPosition)) { - return trailingPosition; + const YGValue *trailingPosition = + YGComputedEdgeValue(node->style.position, YGEdgeEnd, &YGValueUndefined); + if (trailingPosition->unit != YGUnitUndefined) { + return YGValueResolve(trailingPosition, axisSize); } } - const float trailingPosition = - YGComputedEdgeValue(node->style.position, trailing[axis], YGUndefined); + const YGValue *trailingPosition = + YGComputedEdgeValue(node->style.position, trailing[axis], &YGValueUndefined); - return YGValueIsUndefined(trailingPosition) ? 0 : trailingPosition; + return trailingPosition->unit == YGUnitUndefined ? 0.0f + : YGValueResolve(trailingPosition, axisSize); } static float YGNodeBoundAxisWithinMinAndMax(const YGNodeRef node, const YGFlexDirection axis, - const float value) { + const float value, + const float axisSize) { float min = YGUndefined; float max = YGUndefined; if (YGFlexDirectionIsColumn(axis)) { - min = node->style.minDimensions[YGDimensionHeight]; - max = node->style.maxDimensions[YGDimensionHeight]; + min = YGValueResolve(&node->style.minDimensions[YGDimensionHeight], axisSize); + max = YGValueResolve(&node->style.maxDimensions[YGDimensionHeight], axisSize); } else if (YGFlexDirectionIsRow(axis)) { - min = node->style.minDimensions[YGDimensionWidth]; - max = node->style.maxDimensions[YGDimensionWidth]; + min = YGValueResolve(&node->style.minDimensions[YGDimensionWidth], axisSize); + max = YGValueResolve(&node->style.maxDimensions[YGDimensionWidth], axisSize); } float boundValue = value; - if (!YGValueIsUndefined(max) && max >= 0.0 && boundValue > max) { + if (!YGFloatIsUndefined(max) && max >= 0.0f && boundValue > max) { boundValue = max; } - if (!YGValueIsUndefined(min) && min >= 0.0 && boundValue < min) { + if (!YGFloatIsUndefined(min) && min >= 0.0f && boundValue < min) { boundValue = min; } @@ -921,9 +1068,11 @@ static float YGNodeBoundAxisWithinMinAndMax(const YGNodeRef node, // padding and border amount. static inline float YGNodeBoundAxis(const YGNodeRef node, const YGFlexDirection axis, - const float value) { - return fmaxf(YGNodeBoundAxisWithinMinAndMax(node, axis, value), - YGNodePaddingAndBorderForAxis(node, axis)); + const float value, + const float axisSize, + const float widthSize) { + return fmaxf(YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize), + YGNodePaddingAndBorderForAxis(node, axis, widthSize)); } static void YGNodeSetChildTrailingPosition(const YGNodeRef node, @@ -936,19 +1085,21 @@ static void YGNodeSetChildTrailingPosition(const YGNodeRef node, // If both left and right are defined, then use left. Otherwise return // +left or -right depending on which is defined. -static float YGNodeRelativePosition(const YGNodeRef node, const YGFlexDirection axis) { - return YGNodeIsLeadingPosDefined(node, axis) ? YGNodeLeadingPosition(node, axis) - : -YGNodeTrailingPosition(node, axis); +static float YGNodeRelativePosition(const YGNodeRef node, + const YGFlexDirection axis, + const float axisSize) { + return YGNodeIsLeadingPosDefined(node, axis) ? YGNodeLeadingPosition(node, axis, axisSize) + : -YGNodeTrailingPosition(node, axis, axisSize); } static void YGConstrainMaxSizeForMode(const float maxSize, YGMeasureMode *mode, float *size) { switch (*mode) { case YGMeasureModeExactly: case YGMeasureModeAtMost: - *size = (YGValueIsUndefined(maxSize) || *size < maxSize) ? *size : maxSize; + *size = (YGFloatIsUndefined(maxSize) || *size < maxSize) ? *size : maxSize; break; case YGMeasureModeUndefined: - if (!YGValueIsUndefined(maxSize)) { + if (!YGFloatIsUndefined(maxSize)) { *mode = YGMeasureModeAtMost; *size = maxSize; } @@ -956,20 +1107,24 @@ static void YGConstrainMaxSizeForMode(const float maxSize, YGMeasureMode *mode, } } -static void YGNodeSetPosition(const YGNodeRef node, const YGDirection direction) { +static void YGNodeSetPosition(const YGNodeRef node, + const YGDirection direction, + const float mainSize, + const float crossSize, + const float parentWidth) { const YGFlexDirection mainAxis = YGFlexDirectionResolve(node->style.flexDirection, direction); const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction); - const float relativePositionMain = YGNodeRelativePosition(node, mainAxis); - const float relativePositionCross = YGNodeRelativePosition(node, crossAxis); + const float relativePositionMain = YGNodeRelativePosition(node, mainAxis, mainSize); + const float relativePositionCross = YGNodeRelativePosition(node, crossAxis, crossSize); node->layout.position[leading[mainAxis]] = - YGNodeLeadingMargin(node, mainAxis) + relativePositionMain; + YGNodeLeadingMargin(node, mainAxis, parentWidth) + relativePositionMain; node->layout.position[trailing[mainAxis]] = - YGNodeTrailingMargin(node, mainAxis) + relativePositionMain; + YGNodeTrailingMargin(node, mainAxis, parentWidth) + relativePositionMain; node->layout.position[leading[crossAxis]] = - YGNodeLeadingMargin(node, crossAxis) + relativePositionCross; + YGNodeLeadingMargin(node, crossAxis, parentWidth) + relativePositionCross; node->layout.position[trailing[crossAxis]] = - YGNodeTrailingMargin(node, crossAxis) + relativePositionCross; + YGNodeTrailingMargin(node, crossAxis, parentWidth) + relativePositionCross; } static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, @@ -977,10 +1132,14 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, const float width, const YGMeasureMode widthMode, const float height, + const float parentWidth, + const float parentHeight, const YGMeasureMode heightMode, const YGDirection direction) { const YGFlexDirection mainAxis = YGFlexDirectionResolve(node->style.flexDirection, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); + const float mainAxisSize = isMainAxisRow ? width : height; + const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight; float childWidth; float childHeight; @@ -990,24 +1149,25 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow); const bool isColumnStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn); - if (!YGValueIsUndefined(YGNodeStyleGetFlexBasis(child)) && - !YGValueIsUndefined(isMainAxisRow ? width : height)) { - if (YGValueIsUndefined(child->layout.computedFlexBasis) || + if (YGNodeStyleGetFlexBasisPtr(child)->unit != YGUnitUndefined && + !YGFloatIsUndefined(mainAxisSize)) { + if (YGFloatIsUndefined(child->layout.computedFlexBasis) || (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis) && child->layout.computedFlexBasisGeneration != gCurrentGenerationCount)) { child->layout.computedFlexBasis = - fmaxf(YGNodeStyleGetFlexBasis(child), YGNodePaddingAndBorderForAxis(child, mainAxis)); + fmaxf(YGValueResolve(YGNodeStyleGetFlexBasisPtr(child), mainAxisParentSize), + YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth)); } } else if (isMainAxisRow && isRowStyleDimDefined) { // The width is definite, so use that as the flex basis. child->layout.computedFlexBasis = - fmaxf(child->style.dimensions[YGDimensionWidth], - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow)); + fmaxf(YGValueResolve(&child->style.dimensions[YGDimensionWidth], parentWidth), + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth)); } else if (!isMainAxisRow && isColumnStyleDimDefined) { // The height is definite, so use that as the flex basis. child->layout.computedFlexBasis = - fmaxf(child->style.dimensions[YGDimensionHeight], - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn)); + fmaxf(YGValueResolve(&child->style.dimensions[YGDimensionHeight], parentHeight), + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn, parentWidth)); } else { // Compute the flex basis and hypothetical main size (i.e. the clamped // flex basis). @@ -1017,13 +1177,13 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, childHeightMeasureMode = YGMeasureModeUndefined; if (isRowStyleDimDefined) { - childWidth = child->style.dimensions[YGDimensionWidth] + - YGNodeMarginForAxis(child, YGFlexDirectionRow); + childWidth = YGValueResolve(&child->style.dimensions[YGDimensionWidth], parentWidth) + + YGNodeMarginForAxis(child, YGFlexDirectionRow, parentWidth); childWidthMeasureMode = YGMeasureModeExactly; } if (isColumnStyleDimDefined) { - childHeight = child->style.dimensions[YGDimensionHeight] + - YGNodeMarginForAxis(child, YGFlexDirectionColumn); + childHeight = YGValueResolve(&child->style.dimensions[YGDimensionHeight], parentHeight) + + YGNodeMarginForAxis(child, YGFlexDirectionColumn, parentWidth); childHeightMeasureMode = YGMeasureModeExactly; } @@ -1031,7 +1191,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, // but all major browsers appear to implement the following logic. if ((!isMainAxisRow && node->style.overflow == YGOverflowScroll) || node->style.overflow != YGOverflowScroll) { - if (YGValueIsUndefined(childWidth) && !YGValueIsUndefined(width)) { + if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) { childWidth = width; childWidthMeasureMode = YGMeasureModeAtMost; } @@ -1039,7 +1199,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, if ((isMainAxisRow && node->style.overflow == YGOverflowScroll) || node->style.overflow != YGOverflowScroll) { - if (YGValueIsUndefined(childHeight) && !YGValueIsUndefined(height)) { + if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) { childHeight = height; childHeightMeasureMode = YGMeasureModeAtMost; } @@ -1048,35 +1208,37 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, // 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 && !YGValueIsUndefined(width) && !isRowStyleDimDefined && + if (!isMainAxisRow && !YGFloatIsUndefined(width) && !isRowStyleDimDefined && widthMode == YGMeasureModeExactly && YGNodeAlignItem(node, child) == YGAlignStretch) { childWidth = width; childWidthMeasureMode = YGMeasureModeExactly; } - if (isMainAxisRow && !YGValueIsUndefined(height) && !isColumnStyleDimDefined && + if (isMainAxisRow && !YGFloatIsUndefined(height) && !isColumnStyleDimDefined && heightMode == YGMeasureModeExactly && YGNodeAlignItem(node, child) == YGAlignStretch) { childHeight = height; childHeightMeasureMode = YGMeasureModeExactly; } - if (!YGValueIsUndefined(child->style.aspectRatio)) { + if (!YGFloatIsUndefined(child->style.aspectRatio)) { if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) { child->layout.computedFlexBasis = fmaxf(childWidth / child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn)); + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn, parentWidth)); return; } else if (isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) { child->layout.computedFlexBasis = fmaxf(childHeight * child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow)); + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth)); return; } } - YGConstrainMaxSizeForMode(child->style.maxDimensions[YGDimensionWidth], + YGConstrainMaxSizeForMode(YGValueResolve(&child->style.maxDimensions[YGDimensionWidth], + parentWidth), &childWidthMeasureMode, &childWidth); - YGConstrainMaxSizeForMode(child->style.maxDimensions[YGDimensionHeight], + YGConstrainMaxSizeForMode(YGValueResolve(&child->style.maxDimensions[YGDimensionHeight], + parentHeight), &childHeightMeasureMode, &childHeight); @@ -1087,13 +1249,15 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, direction, childWidthMeasureMode, childHeightMeasureMode, + parentWidth, + parentHeight, false, "measure"); child->layout.computedFlexBasis = fmaxf(isMainAxisRow ? child->layout.measuredDimensions[YGDimensionWidth] : child->layout.measuredDimensions[YGDimensionHeight], - YGNodePaddingAndBorderForAxis(child, mainAxis)); + YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth)); } child->layout.computedFlexBasisGeneration = gCurrentGenerationCount; @@ -1103,6 +1267,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, const YGNodeRef child, const float width, const YGMeasureMode widthMode, + const float height, const YGDirection direction) { const YGFlexDirection mainAxis = YGFlexDirectionResolve(node->style.flexDirection, direction); const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction); @@ -1114,8 +1279,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined; if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow)) { - childWidth = - child->style.dimensions[YGDimensionWidth] + YGNodeMarginForAxis(child, YGFlexDirectionRow); + childWidth = YGValueResolve(&child->style.dimensions[YGDimensionWidth], width) + + YGNodeMarginForAxis(child, YGFlexDirectionRow, width); } else { // If the child doesn't have a specified width, compute the width based // on the left/right @@ -1125,15 +1290,15 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childWidth = node->layout.measuredDimensions[YGDimensionWidth] - (YGNodeLeadingBorder(node, YGFlexDirectionRow) + YGNodeTrailingBorder(node, YGFlexDirectionRow)) - - (YGNodeLeadingPosition(child, YGFlexDirectionRow) + - YGNodeTrailingPosition(child, YGFlexDirectionRow)); - childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth); + (YGNodeLeadingPosition(child, YGFlexDirectionRow, width) + + YGNodeTrailingPosition(child, YGFlexDirectionRow, width)); + childWidth = YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width); } } if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn)) { - childHeight = child->style.dimensions[YGDimensionHeight] + - YGNodeMarginForAxis(child, YGFlexDirectionColumn); + childHeight = YGValueResolve(&child->style.dimensions[YGDimensionHeight], height) + + YGNodeMarginForAxis(child, YGFlexDirectionColumn, width); } else { // If the child doesn't have a specified height, compute the height // based on the top/bottom @@ -1143,38 +1308,38 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childHeight = node->layout.measuredDimensions[YGDimensionHeight] - (YGNodeLeadingBorder(node, YGFlexDirectionColumn) + YGNodeTrailingBorder(node, YGFlexDirectionColumn)) - - (YGNodeLeadingPosition(child, YGFlexDirectionColumn) + - YGNodeTrailingPosition(child, YGFlexDirectionColumn)); - childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight); + (YGNodeLeadingPosition(child, YGFlexDirectionColumn, height) + + YGNodeTrailingPosition(child, YGFlexDirectionColumn, height)); + childHeight = YGNodeBoundAxis(child, YGFlexDirectionColumn, childHeight, height, width); } } // Exactly one dimension needs to be defined for us to be able to do aspect ratio // calculation. One dimension being the anchor and the other being flexible. - if (YGValueIsUndefined(childWidth) ^ YGValueIsUndefined(childHeight)) { - if (!YGValueIsUndefined(child->style.aspectRatio)) { - if (YGValueIsUndefined(childWidth)) { + if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) { + if (!YGFloatIsUndefined(child->style.aspectRatio)) { + if (YGFloatIsUndefined(childWidth)) { childWidth = fmaxf(childHeight * child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn)); - } else if (YGValueIsUndefined(childHeight)) { + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionColumn, width)); + } else if (YGFloatIsUndefined(childHeight)) { childHeight = fmaxf(childWidth / child->style.aspectRatio, - YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow)); + YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, width)); } } } // If we're still missing one or the other dimension, measure the content. - if (YGValueIsUndefined(childWidth) || YGValueIsUndefined(childHeight)) { + if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) { childWidthMeasureMode = - YGValueIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly; + YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly; childHeightMeasureMode = - YGValueIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly; + YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly; // According to the spec, if the main size is not definite and the // child's inline axis is parallel to the main axis (i.e. it's // horizontal), the child should be sized using "UNDEFINED" in // the main size. Otherwise use "AT_MOST" in the cross axis. - if (!isMainAxisRow && YGValueIsUndefined(childWidth) && widthMode != YGMeasureModeUndefined) { + if (!isMainAxisRow && YGFloatIsUndefined(childWidth) && widthMode != YGMeasureModeUndefined) { childWidth = width; childWidthMeasureMode = YGMeasureModeAtMost; } @@ -1185,12 +1350,14 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, direction, childWidthMeasureMode, childHeightMeasureMode, + childWidth, + childHeight, false, "abs-measure"); childWidth = child->layout.measuredDimensions[YGDimensionWidth] + - YGNodeMarginForAxis(child, YGFlexDirectionRow); + YGNodeMarginForAxis(child, YGFlexDirectionRow, width); childHeight = child->layout.measuredDimensions[YGDimensionHeight] + - YGNodeMarginForAxis(child, YGFlexDirectionColumn); + YGNodeMarginForAxis(child, YGFlexDirectionColumn, width); } YGLayoutNodeInternal(child, @@ -1199,6 +1366,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, direction, YGMeasureModeExactly, YGMeasureModeExactly, + childWidth, + childHeight, true, "abs-layout"); @@ -1206,7 +1375,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, child->layout.position[leading[mainAxis]] = node->layout.measuredDimensions[dim[mainAxis]] - child->layout.measuredDimensions[dim[mainAxis]] - YGNodeTrailingBorder(node, mainAxis) - - YGNodeTrailingPosition(child, mainAxis); + YGNodeTrailingPosition(child, mainAxis, width); } if (YGNodeIsTrailingPosDefined(child, crossAxis) && @@ -1214,7 +1383,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, child->layout.position[leading[crossAxis]] = node->layout.measuredDimensions[dim[crossAxis]] - child->layout.measuredDimensions[dim[crossAxis]] - YGNodeTrailingBorder(node, crossAxis) - - YGNodeTrailingPosition(child, crossAxis); + YGNodeTrailingPosition(child, crossAxis, width); } } @@ -1225,28 +1394,33 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, const YGMeasureMode heightMeasureMode) { YG_ASSERT(node->measure, "Expected node to have custom measure function"); - const float paddingAndBorderAxisRow = YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow); + const float paddingAndBorderAxisRow = + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); const float paddingAndBorderAxisColumn = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn); - const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow); - const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn); + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, availableWidth); + const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, availableWidth); + const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, availableWidth); const float innerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow; const float innerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn; if (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly) { // Don't bother sizing the text if both dimensions are already defined. - node->layout.measuredDimensions[YGDimensionWidth] = - YGNodeBoundAxis(node, YGFlexDirectionRow, availableWidth - marginAxisRow); + node->layout.measuredDimensions[YGDimensionWidth] = YGNodeBoundAxis( + node, YGFlexDirectionRow, availableWidth - marginAxisRow, availableWidth, availableWidth); node->layout.measuredDimensions[YGDimensionHeight] = - YGNodeBoundAxis(node, YGFlexDirectionColumn, availableHeight - marginAxisColumn); - } else if (innerWidth <= 0 || innerHeight <= 0) { + YGNodeBoundAxis(node, + YGFlexDirectionColumn, + availableHeight - marginAxisColumn, + availableHeight, + availableWidth); + } else if (innerWidth <= 0.0f || innerHeight <= 0.0f) { // Don't bother sizing the text if there's no horizontal or vertical // space. node->layout.measuredDimensions[YGDimensionWidth] = - YGNodeBoundAxis(node, YGFlexDirectionRow, 0); + YGNodeBoundAxis(node, YGFlexDirectionRow, 0.0f, availableWidth, availableWidth); node->layout.measuredDimensions[YGDimensionHeight] = - YGNodeBoundAxis(node, YGFlexDirectionColumn, 0); + YGNodeBoundAxis(node, YGFlexDirectionColumn, 0.0f, availableHeight, availableWidth); } else { // Measure the text under the current constraints. const YGSize measuredSize = @@ -1258,14 +1432,18 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(const YGNodeRef node, (widthMeasureMode == YGMeasureModeUndefined || widthMeasureMode == YGMeasureModeAtMost) ? measuredSize.width + paddingAndBorderAxisRow - : availableWidth - marginAxisRow); + : availableWidth - marginAxisRow, + availableWidth, + availableWidth); node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis(node, YGFlexDirectionColumn, (heightMeasureMode == YGMeasureModeUndefined || heightMeasureMode == YGMeasureModeAtMost) ? measuredSize.height + paddingAndBorderAxisColumn - : availableHeight - marginAxisColumn); + : availableHeight - marginAxisColumn, + availableHeight, + availableWidth); } } @@ -1275,12 +1453,15 @@ static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node, const float availableWidth, const float availableHeight, const YGMeasureMode widthMeasureMode, - const YGMeasureMode heightMeasureMode) { - const float paddingAndBorderAxisRow = YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow); + const YGMeasureMode heightMeasureMode, + const float parentWidth, + const float parentHeight) { + const float paddingAndBorderAxisRow = + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, parentWidth); const float paddingAndBorderAxisColumn = - YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn); - const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow); - const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn); + YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, parentWidth); + const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth); + const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth); node->layout.measuredDimensions[YGDimensionWidth] = YGNodeBoundAxis(node, @@ -1288,40 +1469,52 @@ static void YGNodeEmptyContainerSetMeasuredDimensions(const YGNodeRef node, (widthMeasureMode == YGMeasureModeUndefined || widthMeasureMode == YGMeasureModeAtMost) ? paddingAndBorderAxisRow - : availableWidth - marginAxisRow); + : availableWidth - marginAxisRow, + parentWidth, + parentWidth); node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis(node, YGFlexDirectionColumn, (heightMeasureMode == YGMeasureModeUndefined || heightMeasureMode == YGMeasureModeAtMost) ? paddingAndBorderAxisColumn - : availableHeight - marginAxisColumn); + : availableHeight - marginAxisColumn, + parentHeight, + parentWidth); } static bool YGNodeFixedSizeSetMeasuredDimensions(const YGNodeRef node, const float availableWidth, const float availableHeight, const YGMeasureMode widthMeasureMode, - const YGMeasureMode heightMeasureMode) { - if ((widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0) || - (heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0) || + const YGMeasureMode heightMeasureMode, + const float parentWidth, + const float parentHeight) { + if ((widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) || + (heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) || (widthMeasureMode == YGMeasureModeExactly && heightMeasureMode == YGMeasureModeExactly)) { - const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn); - const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow); + const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth); + const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth); node->layout.measuredDimensions[YGDimensionWidth] = YGNodeBoundAxis(node, YGFlexDirectionRow, - YGValueIsUndefined(availableWidth) || (widthMeasureMode == YGMeasureModeAtMost && availableWidth < 0) - ? 0 - : availableWidth - marginAxisRow); + YGFloatIsUndefined(availableWidth) || + (widthMeasureMode == YGMeasureModeAtMost && availableWidth < 0.0f) + ? 0.0f + : availableWidth - marginAxisRow, + parentWidth, + parentWidth); node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis(node, YGFlexDirectionColumn, - YGValueIsUndefined(availableHeight) || (heightMeasureMode == YGMeasureModeAtMost && availableHeight < 0) - ? 0 - : availableHeight - marginAxisColumn); + YGFloatIsUndefined(availableHeight) || + (heightMeasureMode == YGMeasureModeAtMost && availableHeight < 0.0f) + ? 0.0f + : availableHeight - marginAxisColumn, + parentHeight, + parentWidth); return true; } @@ -1447,11 +1640,13 @@ static void YGNodelayoutImpl(const YGNodeRef node, const YGDirection parentDirection, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, + const float parentWidth, + const float parentHeight, const bool performLayout) { - YG_ASSERT(YGValueIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined : true, + YG_ASSERT(YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined : true, "availableWidth is indefinite so widthMeasureMode must be " "YGMeasureModeUndefined"); - YG_ASSERT(YGValueIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined + YG_ASSERT(YGFloatIsUndefined(availableHeight) ? heightMeasureMode == YGMeasureModeUndefined : true, "availableHeight is indefinite so heightMeasureMode must be " "YGMeasureModeUndefined"); @@ -1468,16 +1663,25 @@ static void YGNodelayoutImpl(const YGNodeRef node, const uint32_t childCount = YGNodeListCount(node->children); if (childCount == 0) { - YGNodeEmptyContainerSetMeasuredDimensions( - node, availableWidth, availableHeight, widthMeasureMode, heightMeasureMode); + YGNodeEmptyContainerSetMeasuredDimensions(node, + availableWidth, + availableHeight, + widthMeasureMode, + heightMeasureMode, + parentWidth, + parentHeight); return; } // If we're not being asked to perform a full layout we can skip the algorithm if we already know // the size - if (!performLayout && - YGNodeFixedSizeSetMeasuredDimensions( - node, availableWidth, availableHeight, widthMeasureMode, heightMeasureMode)) { + if (!performLayout && YGNodeFixedSizeSetMeasuredDimensions(node, + availableWidth, + availableHeight, + widthMeasureMode, + heightMeasureMode, + parentWidth, + parentHeight)) { return; } @@ -1488,40 +1692,58 @@ static void YGNodelayoutImpl(const YGNodeRef node, const YGJustify justifyContent = node->style.justifyContent; const bool isNodeFlexWrap = node->style.flexWrap == YGWrapWrap; + const float mainAxisParentSize = isMainAxisRow ? parentWidth : parentHeight; + const float crossAxisParentSize = isMainAxisRow ? parentHeight : parentWidth; + YGNodeRef firstAbsoluteChild = NULL; YGNodeRef currentAbsoluteChild = NULL; - const float leadingPaddingAndBorderMain = YGNodeLeadingPaddingAndBorder(node, mainAxis); - const float trailingPaddingAndBorderMain = YGNodeTrailingPaddingAndBorder(node, mainAxis); - const float leadingPaddingAndBorderCross = YGNodeLeadingPaddingAndBorder(node, crossAxis); - const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis); - const float paddingAndBorderAxisCross = YGNodePaddingAndBorderForAxis(node, crossAxis); + const float leadingPaddingAndBorderMain = + YGNodeLeadingPaddingAndBorder(node, mainAxis, parentWidth); + const float trailingPaddingAndBorderMain = + YGNodeTrailingPaddingAndBorder(node, mainAxis, parentWidth); + const float leadingPaddingAndBorderCross = + YGNodeLeadingPaddingAndBorder(node, crossAxis, parentWidth); + const float paddingAndBorderAxisMain = YGNodePaddingAndBorderForAxis(node, mainAxis, parentWidth); + const float paddingAndBorderAxisCross = + YGNodePaddingAndBorderForAxis(node, crossAxis, parentWidth); const YGMeasureMode measureModeMainDim = isMainAxisRow ? widthMeasureMode : heightMeasureMode; const YGMeasureMode measureModeCrossDim = isMainAxisRow ? heightMeasureMode : widthMeasureMode; - const float paddingAndBorderAxisRow = isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross; - const float paddingAndBorderAxisColumn = isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain; + const float paddingAndBorderAxisRow = + isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross; + const float paddingAndBorderAxisColumn = + isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain; - const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow); - const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn); + const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth); + const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth); // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS - float availableInnerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow; - const float minInnerWidth = node->style.minDimensions[YGDimensionWidth] - marginAxisRow - paddingAndBorderAxisRow; - const float maxInnerWidth = node->style.maxDimensions[YGDimensionWidth] - marginAxisRow - paddingAndBorderAxisRow; - float availableInnerHeight = - availableHeight - marginAxisColumn - paddingAndBorderAxisColumn; - const float minInnerHeight = node->style.minDimensions[YGDimensionHeight] - marginAxisColumn - paddingAndBorderAxisColumn; - const float maxInnerHeight = node->style.maxDimensions[YGDimensionHeight] - marginAxisColumn - paddingAndBorderAxisColumn; + const float minInnerWidth = + YGValueResolve(&node->style.minDimensions[YGDimensionWidth], parentWidth) - marginAxisRow - + paddingAndBorderAxisRow; + const float maxInnerWidth = + YGValueResolve(&node->style.maxDimensions[YGDimensionWidth], parentWidth) - marginAxisRow - + paddingAndBorderAxisRow; + const float minInnerHeight = + YGValueResolve(&node->style.minDimensions[YGDimensionHeight], parentHeight) - + marginAxisColumn - paddingAndBorderAxisColumn; + const float maxInnerHeight = + YGValueResolve(&node->style.maxDimensions[YGDimensionHeight], parentHeight) - + marginAxisColumn - paddingAndBorderAxisColumn; const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight; const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight; - // Max dimension overrides predefined dimension value; Min dimension in turn overrides both of the above - if (!YGValueIsUndefined(availableInnerWidth)) { + // Max dimension overrides predefined dimension value; Min dimension in turn overrides both of the + // above + float availableInnerWidth = availableWidth - marginAxisRow - paddingAndBorderAxisRow; + if (!YGFloatIsUndefined(availableInnerWidth)) { availableInnerWidth = fmaxf(fminf(availableInnerWidth, maxInnerWidth), minInnerWidth); } - if (!YGValueIsUndefined(availableInnerHeight)) { + + float availableInnerHeight = availableHeight - marginAxisColumn - paddingAndBorderAxisColumn; + if (!YGFloatIsUndefined(availableInnerHeight)) { availableInnerHeight = fmaxf(fminf(availableInnerHeight, maxInnerHeight), minInnerHeight); } @@ -1542,7 +1764,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, singleFlexChild = NULL; break; } - } else if (YGNodeStyleGetFlexGrow(child) > 0 && YGNodeStyleGetFlexShrink(child) > 0) { + } else if (YGNodeStyleGetFlexGrow(child) > 0.0f && YGNodeStyleGetFlexShrink(child) > 0.0f) { singleFlexChild = child; } } @@ -1555,7 +1777,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (performLayout) { // Set the initial position (relative to the parent). const YGDirection childDirection = YGNodeResolveDirection(child, direction); - YGNodeSetPosition(child, childDirection); + YGNodeSetPosition(child, + childDirection, + availableInnerMainDim, + availableInnerCrossDim, + availableInnerWidth); } // Absolute-positioned children don't participate in flex layout. Add them @@ -1581,6 +1807,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerWidth, widthMeasureMode, availableInnerHeight, + availableInnerWidth, + availableInnerHeight, heightMeasureMode, direction); } @@ -1628,8 +1856,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, child->lineIndex = lineCount; if (child->style.positionType != YGPositionTypeAbsolute) { - const float outerFlexBasis = - child->layout.computedFlexBasis + YGNodeMarginForAxis(child, mainAxis); + const float outerFlexBasis = child->layout.computedFlexBasis + + YGNodeMarginForAxis(child, mainAxis, availableInnerWidth); // If this is a multi-line flow and this item pushes us over the // available size, we've @@ -1681,18 +1909,17 @@ static void YGNodelayoutImpl(const YGNodeRef node, // the line length, so there's no more space left to distribute. // We resolve main dimension to fit minimum and maximum values - if (YGValueIsUndefined(availableInnerMainDim)) { - if (!YGValueIsUndefined(minInnerMainDim) && - sizeConsumedOnCurrentLine < minInnerMainDim) { + if (YGFloatIsUndefined(availableInnerMainDim)) { + if (!YGFloatIsUndefined(minInnerMainDim) && sizeConsumedOnCurrentLine < minInnerMainDim) { availableInnerMainDim = minInnerMainDim; - } else if (!YGValueIsUndefined(maxInnerMainDim) && + } else if (!YGFloatIsUndefined(maxInnerMainDim) && sizeConsumedOnCurrentLine > maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; } } float remainingFreeSpace = 0; - if (!YGValueIsUndefined(availableInnerMainDim)) { + if (!YGFloatIsUndefined(availableInnerMainDim)) { remainingFreeSpace = availableInnerMainDim - sizeConsumedOnCurrentLine; } else if (sizeConsumedOnCurrentLine < 0) { // availableInnerMainDim is indefinite which means the node is being sized @@ -1752,7 +1979,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, baseMainSize = childFlexBasis + remainingFreeSpace / totalFlexShrinkScaledFactors * flexShrinkScaledFactor; - boundMainSize = YGNodeBoundAxis(currentRelativeChild, mainAxis, baseMainSize); + boundMainSize = YGNodeBoundAxis(currentRelativeChild, + mainAxis, + baseMainSize, + availableInnerMainDim, + availableInnerWidth); if (baseMainSize != boundMainSize) { // By excluding this item's size and flex factor from remaining, // this item's @@ -1771,7 +2002,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (flexGrowFactor != 0) { baseMainSize = childFlexBasis + remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor; - boundMainSize = YGNodeBoundAxis(currentRelativeChild, mainAxis, baseMainSize); + boundMainSize = YGNodeBoundAxis(currentRelativeChild, + mainAxis, + baseMainSize, + availableInnerMainDim, + availableInnerWidth); if (baseMainSize != boundMainSize) { // By excluding this item's size and flex factor from remaining, // this item's @@ -1813,7 +2048,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, (remainingFreeSpace / totalFlexShrinkScaledFactors) * flexShrinkScaledFactor; } - updatedMainSize = YGNodeBoundAxis(currentRelativeChild, mainAxis, childSize); + updatedMainSize = YGNodeBoundAxis(currentRelativeChild, + mainAxis, + childSize, + availableInnerMainDim, + availableInnerWidth); } } else if (remainingFreeSpace > 0) { flexGrowFactor = YGNodeStyleGetFlexGrow(currentRelativeChild); @@ -1824,7 +2063,9 @@ static void YGNodelayoutImpl(const YGNodeRef node, YGNodeBoundAxis(currentRelativeChild, mainAxis, childFlexBasis + - remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor); + remainingFreeSpace / totalFlexGrowFactors * flexGrowFactor, + availableInnerMainDim, + availableInnerWidth); } } @@ -1837,10 +2078,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (isMainAxisRow) { childWidth = - updatedMainSize + YGNodeMarginForAxis(currentRelativeChild, YGFlexDirectionRow); + updatedMainSize + + YGNodeMarginForAxis(currentRelativeChild, YGFlexDirectionRow, availableInnerWidth); childWidthMeasureMode = YGMeasureModeExactly; - if (!YGValueIsUndefined(availableInnerCrossDim) && + if (!YGFloatIsUndefined(availableInnerCrossDim) && !YGNodeIsStyleDimDefined(currentRelativeChild, YGFlexDirectionColumn) && heightMeasureMode == YGMeasureModeExactly && YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) { @@ -1849,18 +2091,22 @@ static void YGNodelayoutImpl(const YGNodeRef node, } else if (!YGNodeIsStyleDimDefined(currentRelativeChild, YGFlexDirectionColumn)) { childHeight = availableInnerCrossDim; childHeightMeasureMode = - YGValueIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeAtMost; + YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeAtMost; } else { - childHeight = currentRelativeChild->style.dimensions[YGDimensionHeight] + - YGNodeMarginForAxis(currentRelativeChild, YGFlexDirectionColumn); + childHeight = YGValueResolve(¤tRelativeChild->style.dimensions[YGDimensionHeight], + availableInnerHeight) + + YGNodeMarginForAxis(currentRelativeChild, + YGFlexDirectionColumn, + availableInnerWidth); childHeightMeasureMode = YGMeasureModeExactly; } } else { childHeight = - updatedMainSize + YGNodeMarginForAxis(currentRelativeChild, YGFlexDirectionColumn); + updatedMainSize + + YGNodeMarginForAxis(currentRelativeChild, YGFlexDirectionColumn, availableInnerWidth); childHeightMeasureMode = YGMeasureModeExactly; - if (!YGValueIsUndefined(availableInnerCrossDim) && + if (!YGFloatIsUndefined(availableInnerCrossDim) && !YGNodeIsStyleDimDefined(currentRelativeChild, YGFlexDirectionRow) && widthMeasureMode == YGMeasureModeExactly && YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch) { @@ -1869,27 +2115,31 @@ static void YGNodelayoutImpl(const YGNodeRef node, } else if (!YGNodeIsStyleDimDefined(currentRelativeChild, YGFlexDirectionRow)) { childWidth = availableInnerCrossDim; childWidthMeasureMode = - YGValueIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeAtMost; + YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeAtMost; } else { - childWidth = currentRelativeChild->style.dimensions[YGDimensionWidth] + - YGNodeMarginForAxis(currentRelativeChild, YGFlexDirectionRow); + childWidth = + YGValueResolve(¤tRelativeChild->style.dimensions[YGDimensionWidth], + availableInnerWidth) + + YGNodeMarginForAxis(currentRelativeChild, YGFlexDirectionRow, availableInnerWidth); childWidthMeasureMode = YGMeasureModeExactly; } } - if (!YGValueIsUndefined(currentRelativeChild->style.aspectRatio)) { + if (!YGFloatIsUndefined(currentRelativeChild->style.aspectRatio)) { if (isMainAxisRow) { - childHeight = - fmaxf(childWidth / currentRelativeChild->style.aspectRatio, - YGNodePaddingAndBorderForAxis(currentRelativeChild, YGFlexDirectionColumn)); + childHeight = fmaxf(childWidth / currentRelativeChild->style.aspectRatio, + YGNodePaddingAndBorderForAxis(currentRelativeChild, + YGFlexDirectionColumn, + availableInnerWidth)); childHeightMeasureMode = YGMeasureModeExactly; childHeight = fminf(childHeight, availableInnerHeight); childWidth = childHeight * currentRelativeChild->style.aspectRatio; } else { - childWidth = - fmaxf(childHeight * currentRelativeChild->style.aspectRatio, - YGNodePaddingAndBorderForAxis(currentRelativeChild, YGFlexDirectionRow)); + childWidth = fmaxf(childHeight * currentRelativeChild->style.aspectRatio, + YGNodePaddingAndBorderForAxis(currentRelativeChild, + YGFlexDirectionRow, + availableInnerWidth)); childWidthMeasureMode = YGMeasureModeExactly; childWidth = fminf(childWidth, availableInnerWidth); @@ -1897,12 +2147,16 @@ static void YGNodelayoutImpl(const YGNodeRef node, } } - YGConstrainMaxSizeForMode(currentRelativeChild->style.maxDimensions[YGDimensionWidth], - &childWidthMeasureMode, - &childWidth); - YGConstrainMaxSizeForMode(currentRelativeChild->style.maxDimensions[YGDimensionHeight], - &childHeightMeasureMode, - &childHeight); + YGConstrainMaxSizeForMode( + YGValueResolve(¤tRelativeChild->style.maxDimensions[YGDimensionWidth], + availableInnerWidth), + &childWidthMeasureMode, + &childWidth); + YGConstrainMaxSizeForMode( + YGValueResolve(¤tRelativeChild->style.maxDimensions[YGDimensionHeight], + availableInnerHeight), + &childHeightMeasureMode, + &childHeight); const bool requiresStretchLayout = !YGNodeIsStyleDimDefined(currentRelativeChild, crossAxis) && @@ -1916,6 +2170,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, direction, childWidthMeasureMode, childHeightMeasureMode, + availableInnerWidth, + availableInnerHeight, performLayout && !requiresStretchLayout, "flex"); @@ -1938,11 +2194,12 @@ static void YGNodelayoutImpl(const YGNodeRef node, // constraint by the min size defined for the main axis. if (measureModeMainDim == YGMeasureModeAtMost && remainingFreeSpace > 0) { - if (!YGValueIsUndefined(node->style.minDimensions[dim[mainAxis]]) && - node->style.minDimensions[dim[mainAxis]] >= 0) { - remainingFreeSpace = fmaxf(0, - node->style.minDimensions[dim[mainAxis]] - - (availableInnerMainDim - remainingFreeSpace)); + if (node->style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined && + YGValueResolve(&node->style.minDimensions[dim[mainAxis]], mainAxisParentSize) >= 0) { + remainingFreeSpace = + fmaxf(0, + YGValueResolve(&node->style.minDimensions[dim[mainAxis]], mainAxisParentSize) - + (availableInnerMainDim - remainingFreeSpace)); } else { remainingFreeSpace = 0; } @@ -1983,9 +2240,10 @@ static void YGNodelayoutImpl(const YGNodeRef node, // In case the child is position absolute and has left/top being // defined, we override the position to whatever the user said // (and margin/border). - child->layout.position[pos[mainAxis]] = YGNodeLeadingPosition(child, mainAxis) + - YGNodeLeadingBorder(node, mainAxis) + - YGNodeLeadingMargin(child, mainAxis); + child->layout.position[pos[mainAxis]] = + YGNodeLeadingPosition(child, mainAxis, availableInnerMainDim) + + YGNodeLeadingBorder(node, mainAxis) + + YGNodeLeadingMargin(child, mainAxis, availableInnerWidth); } } else { // Now that we placed the element, we need to update the variables. @@ -2000,18 +2258,18 @@ static void YGNodelayoutImpl(const YGNodeRef node, // If we skipped the flex step, then we can't rely on the // measuredDims because // they weren't computed. This means we can't call YGNodeDimWithMargin. - mainDim += betweenMainDim + YGNodeMarginForAxis(child, mainAxis) + + mainDim += betweenMainDim + YGNodeMarginForAxis(child, mainAxis, availableInnerWidth) + child->layout.computedFlexBasis; crossDim = availableInnerCrossDim; } else { // The main dimension is the sum of all the elements dimension plus // the spacing. - mainDim += betweenMainDim + YGNodeDimWithMargin(child, mainAxis); + mainDim += betweenMainDim + YGNodeDimWithMargin(child, mainAxis, availableInnerWidth); // The cross dimension is the max of the elements dimension since // there // can only be one element in that cross dimension. - crossDim = fmaxf(crossDim, YGNodeDimWithMargin(child, crossAxis)); + crossDim = fmaxf(crossDim, YGNodeDimWithMargin(child, crossAxis, availableInnerWidth)); } } else if (performLayout) { child->layout.position[pos[mainAxis]] += @@ -2026,7 +2284,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (measureModeCrossDim == YGMeasureModeUndefined || measureModeCrossDim == YGMeasureModeAtMost) { // Compute the cross axis from the max cross dimension of the children. - containerCrossAxis = YGNodeBoundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - + containerCrossAxis = YGNodeBoundAxis(node, + crossAxis, + crossDim + paddingAndBorderAxisCross, + crossAxisParentSize, + parentWidth) - paddingAndBorderAxisCross; if (measureModeCrossDim == YGMeasureModeAtMost) { @@ -2040,7 +2302,11 @@ static void YGNodelayoutImpl(const YGNodeRef node, } // Clamp to the min/max size specified on the container. - crossDim = YGNodeBoundAxis(node, crossAxis, crossDim + paddingAndBorderAxisCross) - + crossDim = YGNodeBoundAxis(node, + crossAxis, + crossDim + paddingAndBorderAxisCross, + crossAxisParentSize, + parentWidth) - paddingAndBorderAxisCross; // STEP 7: CROSS-AXIS ALIGNMENT @@ -2055,12 +2321,14 @@ static void YGNodelayoutImpl(const YGNodeRef node, // set, override all the previously computed positions to set it // correctly. if (YGNodeIsLeadingPosDefined(child, crossAxis)) { - child->layout.position[pos[crossAxis]] = YGNodeLeadingPosition(child, crossAxis) + - YGNodeLeadingBorder(node, crossAxis) + - YGNodeLeadingMargin(child, crossAxis); + child->layout.position[pos[crossAxis]] = + YGNodeLeadingPosition(child, crossAxis, availableInnerCrossDim) + + YGNodeLeadingBorder(node, crossAxis) + + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth); } else { child->layout.position[pos[crossAxis]] = - YGNodeLeadingBorder(node, crossAxis) + YGNodeLeadingMargin(child, crossAxis); + YGNodeLeadingBorder(node, crossAxis) + + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth); } } else { float leadingCrossDim = leadingPaddingAndBorderCross; @@ -2086,28 +2354,30 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (isMainAxisRow) { childWidth = child->layout.measuredDimensions[YGDimensionWidth] + - YGNodeMarginForAxis(child, YGFlexDirectionRow); + YGNodeMarginForAxis(child, YGFlexDirectionRow, availableInnerWidth); - if (!YGValueIsUndefined(child->style.aspectRatio)) { + if (!YGFloatIsUndefined(child->style.aspectRatio)) { childHeight = childWidth / child->style.aspectRatio; } else { childHeight = crossDim; } } else { childHeight = child->layout.measuredDimensions[YGDimensionHeight] + - YGNodeMarginForAxis(child, YGFlexDirectionColumn); + YGNodeMarginForAxis(child, YGFlexDirectionColumn, availableInnerWidth); - if (!YGValueIsUndefined(child->style.aspectRatio)) { + if (!YGFloatIsUndefined(child->style.aspectRatio)) { childWidth = childHeight * child->style.aspectRatio; } else { childWidth = crossDim; } } - YGConstrainMaxSizeForMode(child->style.maxDimensions[YGDimensionWidth], + YGConstrainMaxSizeForMode(YGValueResolve(&child->style.maxDimensions[YGDimensionWidth], + availableInnerWidth), &childWidthMeasureMode, &childWidth); - YGConstrainMaxSizeForMode(child->style.maxDimensions[YGDimensionHeight], + YGConstrainMaxSizeForMode(YGValueResolve(&child->style.maxDimensions[YGDimensionHeight], + availableInnerHeight), &childHeightMeasureMode, &childHeight); @@ -2115,9 +2385,9 @@ static void YGNodelayoutImpl(const YGNodeRef node, // no need to stretch. if (!isCrossSizeDefinite) { childWidthMeasureMode = - YGValueIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly; + YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined : YGMeasureModeExactly; childHeightMeasureMode = - YGValueIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly; + YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined : YGMeasureModeExactly; YGLayoutNodeInternal(child, childWidth, @@ -2125,12 +2395,14 @@ static void YGNodelayoutImpl(const YGNodeRef node, direction, childWidthMeasureMode, childHeightMeasureMode, + availableInnerWidth, + availableInnerHeight, true, "stretch"); } } else if (alignItem != YGAlignFlexStart) { const float remainingCrossDim = - containerCrossAxis - YGNodeDimWithMargin(child, crossAxis); + containerCrossAxis - YGNodeDimWithMargin(child, crossAxis, availableInnerWidth); if (alignItem == YGAlignCenter) { leadingCrossDim += remainingCrossDim / 2; @@ -2150,7 +2422,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, } // STEP 8: MULTI-LINE CONTENT ALIGNMENT - if (lineCount > 1 && performLayout && !YGValueIsUndefined(availableInnerCrossDim)) { + if (lineCount > 1 && performLayout && !YGFloatIsUndefined(availableInnerCrossDim)) { const float remainingAlignContentDim = availableInnerCrossDim - totalLineCrossDim; float crossDimLead = 0; @@ -2191,7 +2463,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, if (YGNodeIsLayoutDimDefined(child, crossAxis)) { lineHeight = fmaxf(lineHeight, child->layout.measuredDimensions[dim[crossAxis]] + - YGNodeMarginForAxis(child, crossAxis)); + YGNodeMarginForAxis(child, crossAxis, availableInnerWidth)); } } } @@ -2206,12 +2478,13 @@ static void YGNodelayoutImpl(const YGNodeRef node, switch (YGNodeAlignItem(node, child)) { case YGAlignFlexStart: { child->layout.position[pos[crossAxis]] = - currentLead + YGNodeLeadingMargin(child, crossAxis); + currentLead + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth); break; } case YGAlignFlexEnd: { child->layout.position[pos[crossAxis]] = - currentLead + lineHeight - YGNodeTrailingMargin(child, crossAxis) - + currentLead + lineHeight - + YGNodeTrailingMargin(child, crossAxis, availableInnerWidth) - child->layout.measuredDimensions[dim[crossAxis]]; break; } @@ -2223,7 +2496,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, } case YGAlignStretch: { child->layout.position[pos[crossAxis]] = - currentLead + YGNodeLeadingMargin(child, crossAxis); + currentLead + YGNodeLeadingMargin(child, crossAxis, availableInnerWidth); // TODO(prenaux): Correctly set the height of items with indefinite // (auto) crossAxis dimension. break; @@ -2240,10 +2513,10 @@ static void YGNodelayoutImpl(const YGNodeRef node, } // STEP 9: COMPUTING FINAL DIMENSIONS - node->layout.measuredDimensions[YGDimensionWidth] = - YGNodeBoundAxis(node, YGFlexDirectionRow, availableWidth - marginAxisRow); - node->layout.measuredDimensions[YGDimensionHeight] = - YGNodeBoundAxis(node, YGFlexDirectionColumn, availableHeight - marginAxisColumn); + node->layout.measuredDimensions[YGDimensionWidth] = YGNodeBoundAxis( + node, YGFlexDirectionRow, availableWidth - marginAxisRow, parentWidth, parentWidth); + node->layout.measuredDimensions[YGDimensionHeight] = YGNodeBoundAxis( + node, YGFlexDirectionColumn, availableHeight - marginAxisColumn, parentHeight, parentWidth); // If the user didn't specify a width or height for the node, set the // dimensions based on the children. @@ -2251,25 +2524,30 @@ static void YGNodelayoutImpl(const YGNodeRef node, // Clamp the size to the min/max size, if specified, and make sure it // doesn't go below the padding and border amount. node->layout.measuredDimensions[dim[mainAxis]] = - YGNodeBoundAxis(node, mainAxis, maxLineMainDim); + YGNodeBoundAxis(node, mainAxis, maxLineMainDim, mainAxisParentSize, parentWidth); } else if (measureModeMainDim == YGMeasureModeAtMost) { - node->layout.measuredDimensions[dim[mainAxis]] = - fmaxf(fminf(availableInnerMainDim + paddingAndBorderAxisMain, - YGNodeBoundAxisWithinMinAndMax(node, mainAxis, maxLineMainDim)), - paddingAndBorderAxisMain); + node->layout.measuredDimensions[dim[mainAxis]] = fmaxf( + fminf(availableInnerMainDim + paddingAndBorderAxisMain, + YGNodeBoundAxisWithinMinAndMax(node, mainAxis, maxLineMainDim, mainAxisParentSize)), + paddingAndBorderAxisMain); } if (measureModeCrossDim == YGMeasureModeUndefined) { // Clamp the size to the min/max size, if specified, and make sure it // doesn't go below the padding and border amount. node->layout.measuredDimensions[dim[crossAxis]] = - YGNodeBoundAxis(node, crossAxis, totalLineCrossDim + paddingAndBorderAxisCross); + YGNodeBoundAxis(node, + crossAxis, + totalLineCrossDim + paddingAndBorderAxisCross, + crossAxisParentSize, + parentWidth); } else if (measureModeCrossDim == YGMeasureModeAtMost) { node->layout.measuredDimensions[dim[crossAxis]] = fmaxf(fminf(availableInnerCrossDim + paddingAndBorderAxisCross, YGNodeBoundAxisWithinMinAndMax(node, crossAxis, - totalLineCrossDim + paddingAndBorderAxisCross)), + totalLineCrossDim + paddingAndBorderAxisCross, + crossAxisParentSize)), paddingAndBorderAxisCross); } @@ -2277,8 +2555,12 @@ static void YGNodelayoutImpl(const YGNodeRef node, // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN for (currentAbsoluteChild = firstAbsoluteChild; currentAbsoluteChild != NULL; currentAbsoluteChild = currentAbsoluteChild->nextChild) { - YGNodeAbsoluteLayoutChild( - node, currentAbsoluteChild, availableInnerWidth, widthMeasureMode, direction); + YGNodeAbsoluteLayoutChild(node, + currentAbsoluteChild, + availableInnerWidth, + widthMeasureMode, + availableInnerHeight, + direction); } // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN @@ -2415,6 +2697,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node, const YGDirection parentDirection, const YGMeasureMode widthMeasureMode, const YGMeasureMode heightMeasureMode, + const float parentWidth, + const float parentHeight, const bool performLayout, const char *reason) { YGLayout *layout = &node->layout; @@ -2449,8 +2733,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node, // expensive to measure, so it's worth avoiding redundant measurements if at // all possible. if (node->measure) { - const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow); - const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn); + const float marginAxisRow = YGNodeMarginForAxis(node, YGFlexDirectionRow, parentWidth); + const float marginAxisColumn = YGNodeMarginForAxis(node, YGFlexDirectionColumn, parentWidth); // First, try to use the layout cache. if (YGNodeCanUseCachedMeasurement(widthMeasureMode, @@ -2543,6 +2827,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node, parentDirection, widthMeasureMode, heightMeasureMode, + parentWidth, + parentHeight, performLayout); if (gPrintChanges) { @@ -2634,25 +2920,26 @@ void YGNodeCalculateLayout(const YGNodeRef node, YGMeasureMode widthMeasureMode = YGMeasureModeUndefined; YGMeasureMode heightMeasureMode = YGMeasureModeUndefined; - if (!YGValueIsUndefined(width)) { + if (!YGFloatIsUndefined(width)) { widthMeasureMode = YGMeasureModeExactly; } else if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow)) { - width = node->style.dimensions[dim[YGFlexDirectionRow]] + - YGNodeMarginForAxis(node, YGFlexDirectionRow); + width = YGValueResolve(&node->style.dimensions[dim[YGFlexDirectionRow]], availableWidth) + + YGNodeMarginForAxis(node, YGFlexDirectionRow, availableWidth); widthMeasureMode = YGMeasureModeExactly; - } else if (node->style.maxDimensions[YGDimensionWidth] >= 0.0) { - width = node->style.maxDimensions[YGDimensionWidth]; + } else if (YGValueResolve(&node->style.maxDimensions[YGDimensionWidth], availableWidth) >= 0.0f) { + width = YGValueResolve(&node->style.maxDimensions[YGDimensionWidth], availableWidth); widthMeasureMode = YGMeasureModeAtMost; } - if (!YGValueIsUndefined(height)) { + if (!YGFloatIsUndefined(height)) { heightMeasureMode = YGMeasureModeExactly; } else if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn)) { - height = node->style.dimensions[dim[YGFlexDirectionColumn]] + - YGNodeMarginForAxis(node, YGFlexDirectionColumn); + height = YGValueResolve(&node->style.dimensions[dim[YGFlexDirectionColumn]], availableHeight) + + YGNodeMarginForAxis(node, YGFlexDirectionColumn, availableWidth); heightMeasureMode = YGMeasureModeExactly; - } else if (node->style.maxDimensions[YGDimensionHeight] >= 0.0) { - height = node->style.maxDimensions[YGDimensionHeight]; + } else if (YGValueResolve(&node->style.maxDimensions[YGDimensionHeight], availableHeight) >= + 0.0f) { + height = YGValueResolve(&node->style.maxDimensions[YGDimensionHeight], availableHeight); heightMeasureMode = YGMeasureModeAtMost; } @@ -2662,10 +2949,12 @@ void YGNodeCalculateLayout(const YGNodeRef node, parentDirection, widthMeasureMode, heightMeasureMode, + availableWidth, + availableHeight, true, "initia" "l")) { - YGNodeSetPosition(node, node->layout.direction); + YGNodeSetPosition(node, node->layout.direction, availableWidth, availableHeight, availableWidth); if (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureRounding)) { roundToPixelGrid(node); diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 5e10b503f..083d30739 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -38,6 +38,11 @@ typedef struct YGSize { float height; } YGSize; +typedef struct YGValue { + float value; + YGUnit unit; +} YGValue; + typedef struct YGNode *YGNodeRef; typedef YGSize (*YGMeasureFunc)(YGNodeRef node, float width, @@ -83,7 +88,7 @@ WIN_EXPORT bool YGNodeIsDirty(const YGNodeRef node); WIN_EXPORT void YGNodePrint(const YGNodeRef node, const YGPrintOptions options); -WIN_EXPORT bool YGValueIsUndefined(const float value); +WIN_EXPORT bool YGFloatIsUndefined(const float value); WIN_EXPORT bool YGNodeCanUseCachedMeasurement(const YGMeasureMode widthMode, const float width, @@ -108,12 +113,26 @@ WIN_EXPORT void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, const type paramName); \ WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node); +#define YG_NODE_STYLE_PROPERTY_UNIT(type, name, paramName) \ + WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, const float paramName); \ + WIN_EXPORT void YGNodeStyleSet##name##Percent(const YGNodeRef node, const float paramName); \ + WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node); + #define YG_NODE_STYLE_EDGE_PROPERTY(type, name, paramName) \ WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, \ const YGEdge edge, \ const type paramName); \ WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge); +#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT(type, name, paramName) \ + WIN_EXPORT void YGNodeStyleSet##name(const YGNodeRef node, \ + const YGEdge edge, \ + const float paramName); \ + WIN_EXPORT void YGNodeStyleSet##name##Percent(const YGNodeRef node, \ + const YGEdge edge, \ + const float paramName); \ + WIN_EXPORT type YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge); + #define YG_NODE_LAYOUT_PROPERTY(type, name) \ WIN_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node); @@ -135,19 +154,19 @@ YG_NODE_STYLE_PROPERTY(YGOverflow, Overflow, overflow); WIN_EXPORT void YGNodeStyleSetFlex(const YGNodeRef node, const float flex); YG_NODE_STYLE_PROPERTY(float, FlexGrow, flexGrow); YG_NODE_STYLE_PROPERTY(float, FlexShrink, flexShrink); -YG_NODE_STYLE_PROPERTY(float, FlexBasis, flexBasis); +YG_NODE_STYLE_PROPERTY_UNIT(YGValue, FlexBasis, flexBasis); -YG_NODE_STYLE_EDGE_PROPERTY(float, Position, position); -YG_NODE_STYLE_EDGE_PROPERTY(float, Margin, margin); -YG_NODE_STYLE_EDGE_PROPERTY(float, Padding, padding); +YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Position, position); +YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Margin, margin); +YG_NODE_STYLE_EDGE_PROPERTY_UNIT(YGValue, Padding, padding); YG_NODE_STYLE_EDGE_PROPERTY(float, Border, border); -YG_NODE_STYLE_PROPERTY(float, Width, width); -YG_NODE_STYLE_PROPERTY(float, Height, height); -YG_NODE_STYLE_PROPERTY(float, MinWidth, minWidth); -YG_NODE_STYLE_PROPERTY(float, MinHeight, minHeight); -YG_NODE_STYLE_PROPERTY(float, MaxWidth, maxWidth); -YG_NODE_STYLE_PROPERTY(float, MaxHeight, maxHeight); +YG_NODE_STYLE_PROPERTY_UNIT(YGValue, Width, width); +YG_NODE_STYLE_PROPERTY_UNIT(YGValue, Height, height); +YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MinWidth, minWidth); +YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MinHeight, minHeight); +YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MaxWidth, maxWidth); +YG_NODE_STYLE_PROPERTY_UNIT(YGValue, MaxHeight, maxHeight); // Yoga specific properties, not compatible with flexbox specification // Aspect ratio control the size of the undefined dimension of a node.