Compare commits

..

21 Commits

Author SHA1 Message Date
yxping
8bea26d0a0 Fix test failure about zero_size_with_child
A test about parent has zero width and height can not pass.
2018-03-30 15:12:50 +08:00
Jonathan Dann
187fc54596 Add YGNodeSetChildren(), YGNodeTraversePreOrder()
Summary:
We had functions for inserting/removing a specific child, but not for simply replacing the child set with another list.

`YGNodeSetChildren()` will unhook child nodes from the parent that don't appear in the new set. We set the disconnected child node layouts to `YGLayout()` b/c that's what the rest of the code does.

`YGTraversePreOrder()` walks the tree and calls a labmda for each node. We could very easily add a post-order traversal and the ability to stop traversal if we ever want, but for now this is an MVP.

Reviewed By: Woody17

Differential Revision: D7360203

fbshipit-source-id: 32df8e1213ead03bc0a026ec4bf453bc799bb9ce
2018-03-25 13:59:44 -07:00
Pritesh Nandgaonkar
c951ad7c7b Push Yoga 1.8.0 to cocoapods
Summary:
Podspec to push yoga 1.8.0 to cocoapods. There is an issue with cocoapods and it fails to lint those projects with C++ in its header, which is the case with yoga too.

Follow this thread https://github.com/CocoaPods/CocoaPods/issues/5152. To make the lint pass, one would have to change `app_target_helper.rb` cocoapod source file in the local machine. Follow my [gist](https://gist.github.com/priteshrnandgaonkar/dcca9639a3bc0a3b9adecae3a2b3b0c4).

I am able to pass the lint, but not able to push the pod in cocoapods as I am not the admin. @[759512522:emilsj], please push it on Cocoapods or give me permission.

Podspec now also exposes public header explicitly.

Reviewed By: gkassabli

Differential Revision: D7375018

fbshipit-source-id: 4e82e1c0b6340c3f8d3b8a96ecadbcb711d4bcd8
2018-03-23 05:33:59 -07:00
Daniel Büchele
9785975f77 add documentation about JS library usage. fixes #733
Summary: Adds an example of how to use yoga from JavaScript to the documentation pages.

Reviewed By: priteshrnandgaonkar

Differential Revision: D7354390

fbshipit-source-id: 0dbc08e5341c06b621acd99bfb9ce7e789b67a45
2018-03-22 04:53:24 -07:00
Jonathan Dann
79281049f2 Mark more member functions as const
Summary: These don't mutate internal state.

Reviewed By: priteshrnandgaonkar

Differential Revision: D7291364

fbshipit-source-id: 2e7d96cfe0345692ffa411bb21a80eb7a859880b
2018-03-21 16:14:21 -07:00
Jonathan Dann
7d2b84aab6 Pass some constructor argumetns by const-reference
Summary: These don't need to be copied twice.

Reviewed By: priteshrnandgaonkar

Differential Revision: D7291363

fbshipit-source-id: 22e606d0b3fa1133d7e0334c8cf9f5f1f32fe64b
2018-03-21 16:14:21 -07:00
Jonathan Dann
cda328fa7e Pass-by-reference in YGNode::setStyle() ::setChildren() ::setLayout()
Summary: These shouldn't be copying the arguments when they pass by value. Instead these only get copied when assigning the value to the member.

Reviewed By: priteshrnandgaonkar

Differential Revision: D7291096

fbshipit-source-id: 7a4025831811d622050adbb5f86608855b94d68e
2018-03-21 16:14:20 -07:00
Pritesh Nandgaonkar
5d7b75a47a Moved YGFloatOptional from C struct to C++ struct
Summary:
Earlier `YGfloatOptional` was plain struct with no privacy around the variables. This diff adds privacy and also enforces checks when one tries to access value of an undefined `YGFloatOptional`

This diff also adds a behaviour in which when a value of an undefined YGFloatOptional is accessed, it will normally terminate(Several cleanup steps are performed).

Reviewed By: emilsjolander

Differential Revision: D7288555

fbshipit-source-id: f61cc92c8fd0d48d2fc1f4d0e6fcef155f19ff8a
2018-03-15 13:04:51 -07:00
Pritesh Nandgaonkar
ae86824636 Fixed a typo and added a test case
Summary: Fixed a typo of flexshrink and added a test case

Reviewed By: emilsjolander

Differential Revision: D7289221

fbshipit-source-id: 48ee9ccfac4adee51d515a366b5a11790f7236fc
2018-03-15 13:04:51 -07:00
Pritesh Nandgaonkar
0dde40ce0b Fix getters and setters if min and max Dimension
Summary: Fix getters and setters of min and max Dimension to behave exactly the same way as it was before fast math changes

Reviewed By: emilsjolander

Differential Revision: D7274807

fbshipit-source-id: 7c1a4c19e8d0552b089a410c3330392cb26a6a47
2018-03-15 07:27:55 -07:00
Pritesh Nandgaonkar
369c9ad12a Fix setter and getter of margin, position, border and padding
Summary:
This diff fixes the setter and getter of margin, position, border and padding to the previous behaviour of yoga, before floatoptional change

This diff also removes the unrequired `#define`

Reviewed By: emilsjolander

Differential Revision: D7274115

fbshipit-source-id: 942a91e6562ef789ae79102a828f397889468fa7
2018-03-15 07:27:55 -07:00
Pritesh Nandgaonkar
cfb9eeca20 Fix failing float max test
Summary:
Earlier YGUndefined was NAN, but recently it was replaced with 10E20 and the check for `isUndefined` is as follows

```
  public static boolean isUndefined(float value) {
    return (Float.compare(value, (float) 10E8) >= 0 || Float.compare(value, (float) -10E8) <= 0);
}
```

If the number is in (-inf, -10E8] and [10E8, inf) then it is considered as undefined. Failing test passed values in this range, so thats why the test was failing. Current diff fixes this issue, and passes a big number which is outside the range as the result of measure function.

Reviewed By: emilsjolander

Differential Revision: D7272325

fbshipit-source-id: 81a77117c65c5dc0cec920f50f0735ec0a7433d1
2018-03-14 09:21:15 -07:00
Pritesh Nandgaonkar
3dfb68887d Expose layout diffing flag to java
Summary:
This diff exposes `shouldDiffLayoutWithoutLegacyStretchBehaviour` from YGConfig and `doesLegacyStretchFlagAffectsLayout` from YGLayout to YogaConfig and YogaNode respectively

Also added a positive test case. Didn't find the negative test case example. @[508947467:ianc] or @[759512522:emilsj], can you suggest a negative test case example.

Reviewed By: emilsjolander

Differential Revision: D7272067

fbshipit-source-id: e67e82eb057e4c7124904c715f9dca4dcfea21ea
2018-03-14 08:43:01 -07:00
Pritesh Nandgaonkar
d567885070 Remove the use of YGUndefined for flex-basis
Summary: Remove the use of YGUndefined for default flex-basis value

Reviewed By: emilsjolander

Differential Revision: D7243924

fbshipit-source-id: 2bfaca1a5e3da40d5292a273cabf705f59c9d666
2018-03-14 04:36:53 -07:00
Pritesh Nandgaonkar
877c275a13 Change the type of flexShrink to YGFloatOptional
Summary: Change the type of flexShrink to YGFloatOptional

Reviewed By: emilsjolander

Differential Revision: D7232171

fbshipit-source-id: 3111119d3d74a7035c01132bff61b30cf44e120a
2018-03-14 04:36:53 -07:00
Pritesh Nandgaonkar
8aadae8ce4 Change the type of flexGrow to YGFloatOptional
Summary: Change the type of flexGrow to YGFloatOptional

Reviewed By: emilsjolander

Differential Revision: D7215355

fbshipit-source-id: 1298ee332551d44e4d070169a1e4103d005c4f43
2018-03-14 04:36:53 -07:00
Pritesh Nandgaonkar
2232d7603a Change the type of flex to YGFloatOptional
Summary: Change the type of flex to YGFloatOptional internally, but keeping the public facing API the same as before

Reviewed By: emilsjolander

Differential Revision: D7211327

fbshipit-source-id: 0d979b6ba00317317b98bbc6e63979c7f1feb2da
2018-03-14 04:36:52 -07:00
Pritesh Nandgaonkar
b3f8851bc2 Changed the return type of YGResolveValue
Summary: Changed the return type of YGResolveValue

Reviewed By: emilsjolander

Differential Revision: D7195099

fbshipit-source-id: 72c4163cd08691cf6e40df05394cc52e83b0de14
2018-03-14 04:36:52 -07:00
Pritesh Nandgaonkar
47ad3f63cf Remove the usage of YGUndefined in the default values of Border in YGStyle
Summary: Remove the usage of YGUndefined in the default values of Border in YGStyle. In the getter of Border function, YGUndefined is used just to keep it logically consistent. The proper solution would be to change the api in `Yoga.h` to accept `YGFloatOptional`, but that would require to change lot of the code in client of this library. Will make a separate diff for that.

Reviewed By: emilsjolander

Differential Revision: D7195115

fbshipit-source-id: e635cf55ac94d8a90caef6cafce281579da2cbfc
2018-03-14 04:36:52 -07:00
Tomer Shalev
c75adb0671 solves the Android pixel bug
Summary:
emilsjolander hi,
this PR solves the following common and probable layout pixel scenario:
the older code is presented for reference:

```java
view.measure(
    View.MeasureSpec.makeMeasureSpec(
        Math.round(node.getLayoutWidth()),
        View.MeasureSpec.EXACTLY),
    View.MeasureSpec.makeMeasureSpec(
        Math.round(node.getLayoutHeight()),
        View.MeasureSpec.EXACTLY));
view.layout(
    Math.round(xOffset + node.getLayoutX()),
    Math.round(yOffset + node.getLayoutY()),
    Math.round(xOffset + node.getLayoutX() + node.getLayoutWidth()),
    Math.round(yOffset + node.getLayoutY() + node.getLayoutHeight()));

```

suppose now the following:
- `xOffset + node.getLayoutX() = 2.2`
- `node.getLayoutWidth() = 0.4` ==> `Math.round(node.getLayoutWidth()) = 0`
- `Math.round(xOffset + node.getLayoutX() + node.getLayoutWidth()) = Math.round(2.2 + 0.4) = 3`

this induces, the following measurements:
```java
view.measure(
    View.MeasureSpec.makeMeasureSpec(
        0,
        View.MeasureSpec.EXACTLY),
    View.MeasureSpec.makeMeasureSpec(
        Math.round(node.getLayoutHeight()),
        View.MeasureSpec.EXACTLY));
view.layout(
    2,
    Math.round(yOffset + node.getLayoutY()),
    3,
    Math.round(yOffset + node.getLayoutY() + node.getLayoutHeight()));

```

the width measurement of the view is 0, while the layout is `(3 - 2 = 1)`.
my proposed solution is to measure the view the way it is now, but when layouting
I use the `#getMeasuredWidth/Height()` methods, this will stop this problem
from happening.

I also want to note that this bug happens with high probability.
Closes https://github.com/facebook/yoga/pull/712

Reviewed By: emilsjolander

Differential Revision: D7231798

Pulled By: priteshrnandgaonkar

fbshipit-source-id: 171da519639dbecd75416a574bccc4456aa22f31
2018-03-13 03:13:00 -07:00
Héctor Ramos
178b8f5f64 Update config files to use LICENSE-examples
Summary: Use examples license in config files.

Reviewed By: sophiebits

Differential Revision: D7174444

fbshipit-source-id: 50c2369b18abd9d7fff9b4a66788fd67a5b40a0c
2018-03-08 10:21:51 -08:00
29 changed files with 1012 additions and 247 deletions

View File

@@ -1,10 +1,3 @@
# 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.
language: node_js
node_js:
- "8"

View File

@@ -1,9 +1,9 @@
Pod::Spec.new do |spec|
spec.name = 'Yoga'
spec.version = '1.7.0'
spec.version = '1.8.0'
spec.license = { :type => 'MIT', :file => "LICENSE" }
spec.homepage = 'https://facebook.github.io/yoga/'
spec.documentation_url = 'https://facebook.github.io/yoga/docs/api/c/'
spec.homepage = 'https://yogalayout.com/'
spec.documentation_url = 'https://yogalayout.com/docs'
spec.summary = 'Yoga is a cross-platform layout engine which implements Flexbox.'
spec.description = 'Yoga is a cross-platform layout engine enabling maximum collaboration within your team by implementing an API many designers are familiar with, and opening it up to developers across different platforms.'
@@ -11,9 +11,9 @@ Pod::Spec.new do |spec|
spec.authors = 'Facebook'
spec.source = {
:git => 'https://github.com/facebook/yoga.git',
:tag => '1.7.0',
:tag => '1.8.0',
}
spec.osx.deployment_target = '10.13'
spec.module_name = 'yoga'
spec.requires_arc = false
spec.compiler_flags = [
@@ -25,4 +25,6 @@ Pod::Spec.new do |spec|
'-fPIC'
]
spec.source_files = 'yoga/**/*.{c,h,cpp}'
spec.public_header_files = 'yoga/{Yoga,YGEnums,YGMacros}.h'
end

View File

@@ -1,9 +1,7 @@
# 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.
# This source code is licensed under the license found in the
# LICENSE-examples file in the root directory of this source tree.
load("//:yoga_defs.bzl", "ANDROID_JAVA_TARGET", "ANDROID_SAMPLE_RES_TARGET", "ANDROID_SUPPORT_TARGET", "APPCOMPAT_TARGET", "SOLOADER_TARGET", "android_library")

View File

@@ -7,9 +7,6 @@
package com.facebook.yoga.android;
import java.util.HashMap;
import java.util.Map;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -21,9 +18,6 @@ import android.util.SparseArray;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.util.Log;
import com.facebook.yoga.android.R;
import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaConstants;
import com.facebook.yoga.YogaDirection;
@@ -35,10 +29,11 @@ import com.facebook.yoga.YogaMeasureFunction;
import com.facebook.yoga.YogaMeasureMode;
import com.facebook.yoga.YogaMeasureOutput;
import com.facebook.yoga.YogaNode;
import com.facebook.yoga.YogaNode;
import com.facebook.yoga.YogaOverflow;
import com.facebook.yoga.YogaPositionType;
import com.facebook.yoga.YogaWrap;
import java.util.HashMap;
import java.util.Map;
/**
* A {@code ViewGroup} based on the Yoga layout engine.
@@ -291,6 +286,8 @@ public class YogaLayout extends ViewGroup {
if (view.getVisibility() == GONE) {
return;
}
int left = Math.round(xOffset + node.getLayoutX());
int top = Math.round(yOffset + node.getLayoutY());
view.measure(
View.MeasureSpec.makeMeasureSpec(
Math.round(node.getLayoutWidth()),
@@ -298,11 +295,7 @@ public class YogaLayout extends ViewGroup {
View.MeasureSpec.makeMeasureSpec(
Math.round(node.getLayoutHeight()),
View.MeasureSpec.EXACTLY));
view.layout(
Math.round(xOffset + node.getLayoutX()),
Math.round(yOffset + node.getLayoutY()),
Math.round(xOffset + node.getLayoutX() + node.getLayoutWidth()),
Math.round(yOffset + node.getLayoutY() + node.getLayoutHeight()));
view.layout(left, top, left + view.getMeasuredWidth(), top + view.getMeasuredHeight());
}
final int childrenCount = node.getChildCount();

View File

@@ -104,5 +104,58 @@ namespace Facebook.Yoga
Assert.AreEqual(100f, root_child0_child0.LayoutHeight);
}
[Test]
public void Test_zero_size_with_child()
{
YogaConfig config = new YogaConfig();
YogaNode root = new YogaNode(config);
YogaNode root_child0 = new YogaNode(config);
root_child0.Width = 0;
root_child0.Height = 0;
root.Insert(0, root_child0);
YogaNode root_child0_child0 = new YogaNode(config);
root_child0_child0.Width = 100;
root_child0_child0.Height = 100;
root_child0.Insert(0, root_child0_child0);
root.StyleDirection = YogaDirection.LTR;
root.CalculateLayout();
Assert.AreEqual(0f, root.LayoutX);
Assert.AreEqual(0f, root.LayoutY);
Assert.AreEqual(0f, root.LayoutWidth);
Assert.AreEqual(0f, root.LayoutHeight);
Assert.AreEqual(0f, root_child0.LayoutX);
Assert.AreEqual(0f, root_child0.LayoutY);
Assert.AreEqual(0f, root_child0.LayoutWidth);
Assert.AreEqual(0f, root_child0.LayoutHeight);
Assert.AreEqual(0f, root_child0_child0.LayoutX);
Assert.AreEqual(0f, root_child0_child0.LayoutY);
Assert.AreEqual(100f, root_child0_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0_child0.LayoutHeight);
root.StyleDirection = YogaDirection.RTL;
root.CalculateLayout();
Assert.AreEqual(0f, root.LayoutX);
Assert.AreEqual(0f, root.LayoutY);
Assert.AreEqual(0f, root.LayoutWidth);
Assert.AreEqual(0f, root.LayoutHeight);
Assert.AreEqual(0f, root_child0.LayoutX);
Assert.AreEqual(0f, root_child0.LayoutY);
Assert.AreEqual(0f, root_child0.LayoutWidth);
Assert.AreEqual(0f, root_child0.LayoutHeight);
Assert.AreEqual(-100f, root_child0_child0.LayoutX);
Assert.AreEqual(0f, root_child0_child0.LayoutY);
Assert.AreEqual(100f, root_child0_child0.LayoutWidth);
Assert.AreEqual(100f, root_child0_child0.LayoutHeight);
}
}
}

View File

@@ -7,3 +7,9 @@
<div style="width: 100px; height: 100px;"></div>
</div>
</div>
<div id="zero_size_with_child">
<div style="width: 0px; height: 0px;">
<div style="width: 100px; height: 100px;"></div>
</div>
</div>

View File

@@ -411,6 +411,8 @@ function getDefaultStyleValue(style) {
case 'bottom':
case 'start':
case 'end':
case 'width':
case 'height':
return 'undefined';
}
var node = document.getElementById('default');

View File

@@ -74,6 +74,19 @@ public class YogaConfig {
jni_YGConfigSetUseLegacyStretchBehaviour(mNativePointer, useLegacyStretchBehaviour);
}
private native void jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
long nativePointer, boolean shouldDiffLayoutWithoutLegacyStretchBehaviour);
/**
* If this flag is set then yoga would diff the layout without legacy flag and would set a bool in
* YogaNode(mDoesLegacyStretchFlagAffectsLayout) with true if the layouts were different and false
* if not
*/
public void setShouldDiffLayoutWithoutLegacyStretchBehaviour(
boolean shouldDiffLayoutWithoutLegacyStretchBehaviour) {
jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
mNativePointer, shouldDiffLayoutWithoutLegacyStretchBehaviour);
}
private native void jni_YGConfigSetLogger(long nativePointer, Object logger);
public void setLogger(YogaLogger logger) {
mLogger = logger;

View File

@@ -82,6 +82,7 @@ public class YogaNode implements Cloneable {
private int mLayoutDirection = 0;
@DoNotStrip
private boolean mHasNewLayout = true;
@DoNotStrip private boolean mDoesLegacyStretchFlagAffectsLayout = false;
private native long jni_YGNodeNew();
public YogaNode() {
@@ -136,6 +137,7 @@ public class YogaNode implements Cloneable {
mMeasureFunction = null;
mBaselineFunction = null;
mData = null;
mDoesLegacyStretchFlagAffectsLayout = false;
jni_YGNodeReset(mNativePointer);
}
@@ -573,6 +575,10 @@ public class YogaNode implements Cloneable {
return mHeight;
}
public boolean getDoesLegacyStretchFlagAffectsLayout() {
return mDoesLegacyStretchFlagAffectsLayout;
}
public float getLayoutMargin(YogaEdge edge) {
switch (edge) {
case LEFT:

View File

@@ -67,6 +67,9 @@ static void YGTransferLayoutOutputsRecursive(YGNodeRef root) {
static auto edgeSetFlagField = obj->getClass()->getField<jint>("mEdgeSetFlag");
static auto hasNewLayoutField = obj->getClass()->getField<jboolean>("mHasNewLayout");
static auto doesLegacyStretchBehaviour =
obj->getClass()->getField<jboolean>(
"mDoesLegacyStretchFlagAffectsLayout");
/* Those flags needs be in sync with YogaNode.java */
const int MARGIN = 1;
@@ -79,12 +82,19 @@ static void YGTransferLayoutOutputsRecursive(YGNodeRef root) {
obj->setFieldValue(heightField, YGNodeLayoutGetHeight(root));
obj->setFieldValue(leftField, YGNodeLayoutGetLeft(root));
obj->setFieldValue(topField, YGNodeLayoutGetTop(root));
obj->setFieldValue<jboolean>(
doesLegacyStretchBehaviour,
YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(root));
if ((hasEdgeSetFlag & MARGIN) == MARGIN) {
obj->setFieldValue(marginLeftField, YGNodeLayoutGetMargin(root, YGEdgeLeft));
obj->setFieldValue(marginTopField, YGNodeLayoutGetMargin(root, YGEdgeTop));
obj->setFieldValue(marginRightField, YGNodeLayoutGetMargin(root, YGEdgeRight));
obj->setFieldValue(marginBottomField, YGNodeLayoutGetMargin(root, YGEdgeBottom));
obj->setFieldValue(
marginLeftField, YGNodeLayoutGetMargin(root, YGEdgeLeft));
obj->setFieldValue(
marginTopField, YGNodeLayoutGetMargin(root, YGEdgeTop));
obj->setFieldValue(
marginRightField, YGNodeLayoutGetMargin(root, YGEdgeRight));
obj->setFieldValue(
marginBottomField, YGNodeLayoutGetMargin(root, YGEdgeBottom));
}
if ((hasEdgeSetFlag & PADDING) == PADDING) {
@@ -467,6 +477,14 @@ void jni_YGConfigSetExperimentalFeatureEnabled(alias_ref<jobject>,
enabled);
}
void jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
alias_ref<jobject>,
jlong nativePointer,
jboolean enabled) {
const YGConfigRef config = _jlong2YGConfigRef(nativePointer);
YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(config, enabled);
}
void jni_YGConfigSetUseWebDefaults(alias_ref<jobject>,
jlong nativePointer,
jboolean useWebDefaults) {
@@ -624,16 +642,19 @@ jint JNI_OnLoad(JavaVM *vm, void *) {
YGMakeNativeMethod(jni_YGNodePrint),
YGMakeNativeMethod(jni_YGNodeClone),
});
registerNatives("com/facebook/yoga/YogaConfig",
{
YGMakeNativeMethod(jni_YGConfigNew),
YGMakeNativeMethod(jni_YGConfigFree),
YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled),
YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults),
YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor),
YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour),
YGMakeNativeMethod(jni_YGConfigSetLogger),
YGMakeNativeMethod(jni_YGConfigSetHasNodeClonedFunc),
});
registerNatives(
"com/facebook/yoga/YogaConfig",
{
YGMakeNativeMethod(jni_YGConfigNew),
YGMakeNativeMethod(jni_YGConfigFree),
YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled),
YGMakeNativeMethod(jni_YGConfigSetUseWebDefaults),
YGMakeNativeMethod(jni_YGConfigSetPointScaleFactor),
YGMakeNativeMethod(jni_YGConfigSetUseLegacyStretchBehaviour),
YGMakeNativeMethod(jni_YGConfigSetLogger),
YGMakeNativeMethod(jni_YGConfigSetHasNodeClonedFunc),
YGMakeNativeMethod(
jni_YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour),
});
});
}

View File

@@ -101,4 +101,56 @@ public class YGDimensionTest {
assertEquals(100f, root_child0_child0.getLayoutHeight(), 0.0f);
}
@Test
public void test_zero_size_with_child() {
YogaConfig config = new YogaConfig();
final YogaNode root = new YogaNode(config);
final YogaNode root_child0 = new YogaNode(config);
root_child0.setWidth(0f);
root_child0.setHeight(0f);
root.addChildAt(root_child0, 0);
final YogaNode root_child0_child0 = new YogaNode(config);
root_child0_child0.setWidth(100f);
root_child0_child0.setHeight(100f);
root_child0.addChildAt(root_child0_child0, 0);
root.setDirection(YogaDirection.LTR);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertEquals(0f, root.getLayoutX(), 0.0f);
assertEquals(0f, root.getLayoutY(), 0.0f);
assertEquals(0f, root.getLayoutWidth(), 0.0f);
assertEquals(0f, root.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0.getLayoutY(), 0.0f);
assertEquals(0f, root_child0.getLayoutWidth(), 0.0f);
assertEquals(0f, root_child0.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutHeight(), 0.0f);
root.setDirection(YogaDirection.RTL);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertEquals(0f, root.getLayoutX(), 0.0f);
assertEquals(0f, root.getLayoutY(), 0.0f);
assertEquals(0f, root.getLayoutWidth(), 0.0f);
assertEquals(0f, root.getLayoutHeight(), 0.0f);
assertEquals(0f, root_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0.getLayoutY(), 0.0f);
assertEquals(0f, root_child0.getLayoutWidth(), 0.0f);
assertEquals(0f, root_child0.getLayoutHeight(), 0.0f);
assertEquals(-100f, root_child0_child0.getLayoutX(), 0.0f);
assertEquals(0f, root_child0_child0.getLayoutY(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutWidth(), 0.0f);
assertEquals(100f, root_child0_child0.getLayoutHeight(), 0.0f);
}
}

View File

@@ -8,6 +8,7 @@
package com.facebook.yoga;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -109,21 +110,23 @@ public class YogaNodeTest {
}
@Test
public void testMeasureFloatMax() {
public void testMeasureFloatBigNumber() {
final YogaNode node = new YogaNode();
node.setMeasureFunction(new YogaMeasureFunction() {
public long measure(
YogaNode node,
float width,
YogaMeasureMode widthMode,
float height,
YogaMeasureMode heightMode) {
return YogaMeasureOutput.make(Float.MAX_VALUE, Float.MAX_VALUE);
}
});
final float bigNumber = (float) 10E5;
node.setMeasureFunction(
new YogaMeasureFunction() {
public long measure(
YogaNode node,
float width,
YogaMeasureMode widthMode,
float height,
YogaMeasureMode heightMode) {
return YogaMeasureOutput.make(bigNumber, bigNumber);
}
});
node.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertEquals(Float.MAX_VALUE, node.getLayoutWidth(), 0.01f);
assertEquals(Float.MAX_VALUE, node.getLayoutHeight(), 0.01f);
assertEquals(bigNumber, node.getLayoutWidth(), 0.01f);
assertEquals(bigNumber, node.getLayoutHeight(), 0.01f);
}
@Test
@@ -302,4 +305,27 @@ public class YogaNodeTest {
}
fail("YogaConfig leaked");
}
@Test
public void testFlagShouldDiffLayoutWithoutLegacyStretchBehaviour() throws Exception {
YogaConfig config = new YogaConfig();
config.setShouldDiffLayoutWithoutLegacyStretchBehaviour(true);
config.setUseLegacyStretchBehaviour(true);
YogaNode root = new YogaNode(config);
root.setWidth(500);
root.setHeight(500);
YogaNode root_child0 = new YogaNode(config);
root_child0.setAlignItems(YogaAlign.FLEX_START);
root.addChildAt(root_child0, 0);
YogaNode root_child0_child0 = new YogaNode(config);
root_child0_child0.setFlexGrow(1);
root_child0_child0.setFlexShrink(1);
root_child0.addChildAt(root_child0_child0, 0);
YogaNode root_child0_child0_child0 = new YogaNode(config);
root_child0_child0_child0.setFlexGrow(1);
root_child0_child0_child0.setFlexShrink(1);
root_child0_child0.addChildAt(root_child0_child0_child0, 0);
root.calculateLayout(YogaConstants.UNDEFINED, YogaConstants.UNDEFINED);
assertFalse(root.getDoesLegacyStretchFlagAffectsLayout());
}
}

View File

@@ -104,3 +104,59 @@ it("wrap_grandchild", function () {
config.free();
}
});
it("zero_size_with_child", function () {
var config = Yoga.Config.create();
try {
var root = Yoga.Node.create(config);
var root_child0 = Yoga.Node.create(config);
root_child0.setWidth(0);
root_child0.setHeight(0);
root.insertChild(root_child0, 0);
var root_child0_child0 = Yoga.Node.create(config);
root_child0_child0.setWidth(100);
root_child0_child0.setHeight(100);
root_child0.insertChild(root_child0_child0, 0);
root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_LTR);
console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")");
console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")");
console.assert(0 === root.getComputedWidth(), "0 === root.getComputedWidth() (" + root.getComputedWidth() + ")");
console.assert(0 === root.getComputedHeight(), "0 === root.getComputedHeight() (" + root.getComputedHeight() + ")");
console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")");
console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")");
console.assert(0 === root_child0.getComputedWidth(), "0 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")");
console.assert(0 === root_child0.getComputedHeight(), "0 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")");
console.assert(0 === root_child0_child0.getComputedLeft(), "0 === root_child0_child0.getComputedLeft() (" + root_child0_child0.getComputedLeft() + ")");
console.assert(0 === root_child0_child0.getComputedTop(), "0 === root_child0_child0.getComputedTop() (" + root_child0_child0.getComputedTop() + ")");
console.assert(100 === root_child0_child0.getComputedWidth(), "100 === root_child0_child0.getComputedWidth() (" + root_child0_child0.getComputedWidth() + ")");
console.assert(100 === root_child0_child0.getComputedHeight(), "100 === root_child0_child0.getComputedHeight() (" + root_child0_child0.getComputedHeight() + ")");
root.calculateLayout(Yoga.UNDEFINED, Yoga.UNDEFINED, Yoga.DIRECTION_RTL);
console.assert(0 === root.getComputedLeft(), "0 === root.getComputedLeft() (" + root.getComputedLeft() + ")");
console.assert(0 === root.getComputedTop(), "0 === root.getComputedTop() (" + root.getComputedTop() + ")");
console.assert(0 === root.getComputedWidth(), "0 === root.getComputedWidth() (" + root.getComputedWidth() + ")");
console.assert(0 === root.getComputedHeight(), "0 === root.getComputedHeight() (" + root.getComputedHeight() + ")");
console.assert(0 === root_child0.getComputedLeft(), "0 === root_child0.getComputedLeft() (" + root_child0.getComputedLeft() + ")");
console.assert(0 === root_child0.getComputedTop(), "0 === root_child0.getComputedTop() (" + root_child0.getComputedTop() + ")");
console.assert(0 === root_child0.getComputedWidth(), "0 === root_child0.getComputedWidth() (" + root_child0.getComputedWidth() + ")");
console.assert(0 === root_child0.getComputedHeight(), "0 === root_child0.getComputedHeight() (" + root_child0.getComputedHeight() + ")");
console.assert(-100 === root_child0_child0.getComputedLeft(), "-100 === root_child0_child0.getComputedLeft() (" + root_child0_child0.getComputedLeft() + ")");
console.assert(0 === root_child0_child0.getComputedTop(), "0 === root_child0_child0.getComputedTop() (" + root_child0_child0.getComputedTop() + ")");
console.assert(100 === root_child0_child0.getComputedWidth(), "100 === root_child0_child0.getComputedWidth() (" + root_child0_child0.getComputedWidth() + ")");
console.assert(100 === root_child0_child0.getComputedHeight(), "100 === root_child0_child0.getComputedHeight() (" + root_child0_child0.getComputedHeight() + ")");
} finally {
if (typeof root !== "undefined") {
root.freeRecursive();
}
config.free();
}
});

View File

@@ -98,3 +98,56 @@ TEST(YogaTest, wrap_grandchild) {
YGConfigFree(config);
}
TEST(YogaTest, zero_size_with_child) {
const YGConfigRef config = YGConfigNew();
const YGNodeRef root = YGNodeNewWithConfig(config);
const YGNodeRef root_child0 = YGNodeNewWithConfig(config);
YGNodeStyleSetWidth(root_child0, 0);
YGNodeStyleSetHeight(root_child0, 0);
YGNodeInsertChild(root, root_child0, 0);
const YGNodeRef root_child0_child0 = YGNodeNewWithConfig(config);
YGNodeStyleSetWidth(root_child0_child0, 100);
YGNodeStyleSetHeight(root_child0_child0, 100);
YGNodeInsertChild(root_child0, root_child0_child0, 0);
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionLTR);
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
YGNodeCalculateLayout(root, YGUndefined, YGUndefined, YGDirectionRTL);
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetLeft(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetWidth(root_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetHeight(root_child0));
ASSERT_FLOAT_EQ(-100, YGNodeLayoutGetLeft(root_child0_child0));
ASSERT_FLOAT_EQ(0, YGNodeLayoutGetTop(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetWidth(root_child0_child0));
ASSERT_FLOAT_EQ(100, YGNodeLayoutGetHeight(root_child0_child0));
YGNodeFreeRecursive(root);
YGConfigFree(config);
}

View File

@@ -57,3 +57,26 @@ TEST(YogaTest, copy_style_modified_same) {
YGNodeFree(node0);
YGNodeFree(node1);
}
TEST(YogaTest, initialise_flexShrink_flexGrow) {
const YGNodeRef node0 = YGNodeNew();
YGNodeStyleSetFlexShrink(node0, 1);
ASSERT_EQ(1, YGNodeStyleGetFlexShrink(node0));
YGNodeStyleSetFlexShrink(node0, YGUndefined);
YGNodeStyleSetFlexGrow(node0, 3);
ASSERT_EQ(
0,
YGNodeStyleGetFlexShrink(
node0)); // Default value is Zero, if flex shrink is not defined
ASSERT_EQ(3, YGNodeStyleGetFlexGrow(node0));
YGNodeStyleSetFlexGrow(node0, YGUndefined);
YGNodeStyleSetFlexShrink(node0, 3);
ASSERT_EQ(
0,
YGNodeStyleGetFlexGrow(
node0)); // Default value is Zero, if flex grow is not defined
ASSERT_EQ(3, YGNodeStyleGetFlexShrink(node0));
YGNodeFree(node0);
}

34
tests/YGTraversalTest.cpp Normal file
View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <yoga/Yoga.h>
TEST(YogaTest, pre_order_traversal) {
YGNodeRef const root = YGNodeNew();
YGNodeRef const root_child0 = YGNodeNew();
YGNodeRef const root_child1 = YGNodeNew();
YGNodeRef const root_child0_child0 = YGNodeNew();
YGNodeSetChildren(root, {root_child0, root_child1});
YGNodeInsertChild(root_child0, root_child0_child0, 0);
std::vector<YGNodeRef> visited;
YGTraversePreOrder(root, [&visited](YGNodeRef node) {
visited.push_back(node);
});
const std::vector<YGNodeRef> expected = {
root,
root_child0,
root_child0_child0,
root_child1
};
ASSERT_EQ(visited, expected);
YGNodeFreeRecursive(root);
}

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <yoga/Yoga.h>
static std::vector<YGNodeRef> getChildren(YGNodeRef const node)
{
const uint32_t count = YGNodeGetChildCount(node);
std::vector<YGNodeRef> children;
children.reserve(count);
for (uint32_t i = 0 ; i < count ; i++) {
children.push_back(YGNodeGetChild(node, i));
}
return children;
}
TEST(YogaTest, set_children_adds_children_to_parent) {
YGNodeRef const root = YGNodeNew();
YGNodeRef const root_child0 = YGNodeNew();
YGNodeRef const root_child1 = YGNodeNew();
YGNodeSetChildren(root, {root_child0, root_child1});
const std::vector<YGNodeRef> children = getChildren(root);
const std::vector<YGNodeRef> expectedChildren = {root_child0, root_child1};
ASSERT_EQ(children, expectedChildren);
const std::vector<YGNodeRef> parents = {YGNodeGetParent(root_child0), YGNodeGetParent(root_child1)};
const std::vector<YGNodeRef> expectedParents = {root, root};
ASSERT_EQ(parents, expectedParents);
YGNodeFreeRecursive(root);
}
TEST(YogaTest, set_children_to_empty_removes_old_children) {
YGNodeRef const root = YGNodeNew();
YGNodeRef const root_child0 = YGNodeNew();
YGNodeRef const root_child1 = YGNodeNew();
YGNodeSetChildren(root, {root_child0, root_child1});
YGNodeSetChildren(root, {});
const std::vector<YGNodeRef> children = getChildren(root);
const std::vector<YGNodeRef> expectedChildren = {};
ASSERT_EQ(children, expectedChildren);
const std::vector<YGNodeRef> parents = {YGNodeGetParent(root_child0), YGNodeGetParent(root_child1)};
const std::vector<YGNodeRef> expectedParents = {nullptr, nullptr};
ASSERT_EQ(parents, expectedParents);
YGNodeFreeRecursive(root);
}
TEST(YogaTest, set_children_replaces_non_common_children) {
YGNodeRef const root = YGNodeNew();
YGNodeRef const root_child0 = YGNodeNew();
YGNodeRef const root_child1 = YGNodeNew();
YGNodeSetChildren(root, {root_child0, root_child1});
YGNodeRef const root_child2 = YGNodeNew();
YGNodeRef const root_child3 = YGNodeNew();
YGNodeSetChildren(root, {root_child2, root_child3});
const std::vector<YGNodeRef> children = getChildren(root);
const std::vector<YGNodeRef> expectedChildren = {root_child2, root_child3};
ASSERT_EQ(children, expectedChildren);
const std::vector<YGNodeRef> parents = {YGNodeGetParent(root_child0), YGNodeGetParent(root_child1)};
const std::vector<YGNodeRef> expectedParents = {nullptr, nullptr};
ASSERT_EQ(parents, expectedParents);
YGNodeFreeRecursive(root);
YGNodeFree(root_child0);
YGNodeFree(root_child1);
}
TEST(YogaTest, set_children_keeps_and_reorders_common_children) {
YGNodeRef const root = YGNodeNew();
YGNodeRef const root_child0 = YGNodeNew();
YGNodeRef const root_child1 = YGNodeNew();
YGNodeRef const root_child2 = YGNodeNew();
YGNodeSetChildren(root, {root_child0, root_child1, root_child2});
YGNodeRef const root_child3 = YGNodeNew();
YGNodeSetChildren(root, {root_child2, root_child1, root_child3});
const std::vector<YGNodeRef> children = getChildren(root);
const std::vector<YGNodeRef> expectedChildren = {root_child2, root_child1, root_child3};
ASSERT_EQ(children, expectedChildren);
const std::vector<YGNodeRef> parents = {
YGNodeGetParent(root_child0),
YGNodeGetParent(root_child1),
YGNodeGetParent(root_child2),
YGNodeGetParent(root_child3)
};
const std::vector<YGNodeRef> expectedParents = {nullptr, root, root, root};
ASSERT_EQ(parents, expectedParents);
YGNodeFreeRecursive(root);
YGNodeFree(root_child0);
}

View File

@@ -18,10 +18,45 @@ dependencies {
### Javascript
The JavaScript bindings for Yoga can be used from node.js and within the browser.
When using Yoga from node.js the native library is used, in browesers a pure JS
version is used (corss-compiled using [emscripten](http://kripken.github.io/emscripten-site/)).
```
$> yarn add yoga-layout
```
This is an example on how to use Yoga in JavaScript, for a full API reference,
have a look at the [flow-type definitions](https://github.com/facebook/yoga/blob/master/javascript/sources/entry-common.js#L123).
```js
import yoga, {Node} from 'yoga-layout';
const root = Node.create();
root.setWidth(500);
root.setHeight(300);
root.setJustifyContent(yoga.JUSTIFY_CENTER);
const node1 = Node.create();
node1.setWidth(100);
node1.setHeight(100);
const node2 = Node.create();
node2.setWidth(100);
node2.setHeight(100);
root.insertChild(node1, 0);
root.insertChild(node2, 1);
root.calculateLayout(500, 300, yoga.DIRECTION_LTR);
console.log(root.getComputedLayout());
// {left: 0, top: 0, width: 500, height: 300}
console.log(node1.getComputedLayout());
// {left: 150, top: 0, width: 100, height: 100}
console.log(node2.getComputedLayout());
// {left: 250, top: 0, width: 100, height: 100}
```
### iOS
```

View File

@@ -49,3 +49,17 @@ bool YGFloatsEqual(const float a, const float b) {
}
return YGFloatIsUndefined(a) && YGFloatIsUndefined(b);
}
float YGFloatSanitize(const float& val) {
return YGFloatIsUndefined(val) ? 0 : val;
}
float YGUnwrapFloatOptional(const YGFloatOptional& op) {
return op.isUndefined() ? YGUndefined : op.getValue();
}
bool YGFloatOptionalFloatEquals(
const YGFloatOptional& optional,
const float& val) {
return YGUnwrapFloatOptional(optional) == val;
}

View File

@@ -86,6 +86,20 @@ bool YGFloatArrayEqual(
return areEqual;
}
// This function returns 0 if YGFloatIsUndefined(val) is true and val otherwise
float YGFloatSanitize(const float& val);
// This function unwraps optional and returns YGUndefined if not defined or
// op.value otherwise
// TODO: Get rid off this function
float YGUnwrapFloatOptional(const YGFloatOptional& op);
// This function returns true if val and optional both are undefined or if val
// and optional.val is true, otherwise its false.
bool YGFloatOptionalFloatEquals(
const YGFloatOptional& optional,
const float& val);
YGFlexDirection YGFlexDirectionCross(
const YGFlexDirection flexDirection,
const YGDirection direction);
@@ -95,17 +109,18 @@ inline bool YGFlexDirectionIsRow(const YGFlexDirection flexDirection) {
flexDirection == YGFlexDirectionRowReverse;
}
inline float YGResolveValue(const YGValue value, const float parentSize) {
inline YGFloatOptional YGResolveValue(const YGValue value, const float parentSize) {
switch (value.unit) {
case YGUnitUndefined:
case YGUnitAuto:
return YGUndefined;
return YGFloatOptional();
case YGUnitPoint:
return value.value;
return YGFloatOptional(value.value);
case YGUnitPercent:
return value.value * parentSize * 0.01;
return YGFloatOptional(
static_cast<float>(value.value * parentSize * 0.01));
}
return YGUndefined;
return YGFloatOptional();
}
inline bool YGFlexDirectionIsColumn(const YGFlexDirection flexDirection) {
@@ -130,5 +145,5 @@ inline YGFlexDirection YGResolveFlexDirection(
static inline float YGResolveValueMargin(
const YGValue value,
const float parentSize) {
return value.unit == YGUnitAuto ? 0 : YGResolveValue(value, parentSize);
return value.unit == YGUnitAuto ? 0 : YGUnwrapFloatOptional(YGResolveValue(value, parentSize));
}

32
yoga/YGFloatOptional.cpp Normal file
View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "YGFloatOptional.h"
#include <cstdlib>
#include <iostream>
YGFloatOptional::YGFloatOptional(const float& value)
: value_(value), isUndefined_(false) {}
YGFloatOptional::YGFloatOptional() : value_(0), isUndefined_(true) {}
float YGFloatOptional::getValue() const {
if (isUndefined_) {
// Abort, accessing a value of an undefined float optional
std::cerr << "Tried to get value of an undefined YGFloatOptional\n";
std::exit(EXIT_FAILURE);
}
return value_;
}
void YGFloatOptional::setValue(const float& val) {
value_ = val;
isUndefined_ = false;
}
bool YGFloatOptional::isUndefined() const {
return isUndefined_;
}

26
yoga/YGFloatOptional.h Normal file
View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
struct YGFloatOptional {
private:
float value_;
bool isUndefined_;
public:
YGFloatOptional(const float& value);
YGFloatOptional();
// Program will terminate if the value of an undefined is accessed. Please
// make sure to check if the optional is defined before calling this function.
// To check if float optional is defined, use `isUndefined()`.
float getValue() const;
// Sets the value of float optional, and thus isUndefined is assigned false.
void setValue(const float& val);
bool isUndefined() const;
};

View File

@@ -87,12 +87,12 @@ std::array<YGValue, 2> YGNode::getResolvedDimensions() const {
float YGNode::getLeadingPosition(
const YGFlexDirection axis,
const float axisSize) {
const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) {
const YGValue* leadingPosition =
YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined);
if (leadingPosition->unit != YGUnitUndefined) {
return YGResolveValue(*leadingPosition, axisSize);
return YGUnwrapFloatOptional(YGResolveValue(*leadingPosition, axisSize));
}
}
@@ -101,17 +101,17 @@ float YGNode::getLeadingPosition(
return leadingPosition->unit == YGUnitUndefined
? 0.0f
: YGResolveValue(*leadingPosition, axisSize);
: YGUnwrapFloatOptional(YGResolveValue(*leadingPosition, axisSize));
}
float YGNode::getTrailingPosition(
const YGFlexDirection axis,
const float axisSize) {
const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) {
const YGValue* trailingPosition =
YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined);
if (trailingPosition->unit != YGUnitUndefined) {
return YGResolveValue(*trailingPosition, axisSize);
return YGUnwrapFloatOptional(YGResolveValue(*trailingPosition, axisSize));
}
}
@@ -120,10 +120,10 @@ float YGNode::getTrailingPosition(
return trailingPosition->unit == YGUnitUndefined
? 0.0f
: YGResolveValue(*trailingPosition, axisSize);
: YGUnwrapFloatOptional(YGResolveValue(*trailingPosition, axisSize));
}
bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) {
bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) &&
YGComputedEdgeValue(style_.position, YGEdgeStart, &YGValueUndefined)
->unit != YGUnitUndefined) ||
@@ -131,7 +131,7 @@ bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) {
->unit != YGUnitUndefined;
}
bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) {
bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) &&
YGComputedEdgeValue(style_.position, YGEdgeEnd, &YGValueUndefined)
->unit != YGUnitUndefined) ||
@@ -141,7 +141,7 @@ bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) {
float YGNode::getLeadingMargin(
const YGFlexDirection axis,
const float widthSize) {
const float widthSize) const {
if (YGFlexDirectionIsRow(axis) &&
style_.margin[YGEdgeStart].unit != YGUnitUndefined) {
return YGResolveValueMargin(style_.margin[YGEdgeStart], widthSize);
@@ -154,7 +154,7 @@ float YGNode::getLeadingMargin(
float YGNode::getTrailingMargin(
const YGFlexDirection axis,
const float widthSize) {
const float widthSize) const {
if (YGFlexDirectionIsRow(axis) &&
style_.margin[YGEdgeEnd].unit != YGUnitUndefined) {
return YGResolveValueMargin(style_.margin[YGEdgeEnd], widthSize);
@@ -167,7 +167,7 @@ float YGNode::getTrailingMargin(
float YGNode::getMarginForAxis(
const YGFlexDirection axis,
const float widthSize) {
const float widthSize) const {
return getLeadingMargin(axis, widthSize) + getTrailingMargin(axis, widthSize);
}
@@ -225,11 +225,11 @@ void YGNode::setDirtiedFunc(YGDirtiedFunc dirtiedFunc) {
dirtied_ = dirtiedFunc;
}
void YGNode::setStyle(YGStyle style) {
void YGNode::setStyle(const YGStyle& style) {
style_ = style;
}
void YGNode::setLayout(YGLayout layout) {
void YGNode::setLayout(const YGLayout& layout) {
layout_ = layout;
}
@@ -241,7 +241,7 @@ void YGNode::setParent(YGNodeRef parent) {
parent_ = parent;
}
void YGNode::setChildren(YGVector children) {
void YGNode::setChildren(const YGVector& children) {
children_ = children;
}
@@ -423,10 +423,10 @@ YGNode::YGNode(
YGBaselineFunc baseline,
YGDirtiedFunc dirtied,
YGStyle style,
YGLayout layout,
const YGLayout& layout,
uint32_t lineIndex,
YGNodeRef parent,
YGVector children,
const YGVector& children,
YGNodeRef nextChild,
YGConfigRef config,
bool isDirty,
@@ -500,7 +500,7 @@ YGValue YGNode::resolveFlexBasisPtr() const {
if (flexBasis.unit != YGUnitAuto && flexBasis.unit != YGUnitUndefined) {
return flexBasis;
}
if (!YGFloatIsUndefined(style_.flex) && style_.flex > 0.0f) {
if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
return config_->useWebDefaults ? YGValueAuto : YGValueZero;
}
return YGValueAuto;
@@ -592,11 +592,11 @@ float YGNode::resolveFlexGrow() {
if (parent_ == nullptr) {
return 0.0;
}
if (!YGFloatIsUndefined(style_.flexGrow)) {
return style_.flexGrow;
if (!style_.flexGrow.isUndefined()) {
return style_.flexGrow.getValue();
}
if (!YGFloatIsUndefined(style_.flex) && style_.flex > 0.0f) {
return style_.flex;
if (!style_.flex.isUndefined() && style_.flex.getValue() > 0.0f) {
return style_.flex.getValue();
}
return kDefaultFlexGrow;
}
@@ -605,12 +605,12 @@ float YGNode::resolveFlexShrink() {
if (parent_ == nullptr) {
return 0.0;
}
if (!YGFloatIsUndefined(style_.flexShrink)) {
return style_.flexShrink;
if (!style_.flexShrink.isUndefined()) {
return style_.flexShrink.getValue();
}
if (!config_->useWebDefaults && !YGFloatIsUndefined(style_.flex) &&
style_.flex < 0.0f) {
return -style_.flex;
if (!config_->useWebDefaults && !style_.flex.isUndefined() &&
style_.flex.getValue() < 0.0f) {
return -style_.flex.getValue();
}
return config_->useWebDefaults ? kWebDefaultFlexShrink : kDefaultFlexShrink;
}
@@ -621,7 +621,7 @@ bool YGNode::isNodeFlexible() {
(resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
}
float YGNode::getLeadingBorder(const YGFlexDirection axis) {
float YGNode::getLeadingBorder(const YGFlexDirection axis) const {
if (YGFlexDirectionIsRow(axis) &&
style_.border[YGEdgeStart].unit != YGUnitUndefined &&
!YGFloatIsUndefined(style_.border[YGEdgeStart].value) &&
@@ -634,7 +634,7 @@ float YGNode::getLeadingBorder(const YGFlexDirection axis) {
return YGFloatMax(computedEdgeValue, 0.0f);
}
float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) {
float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const {
if (YGFlexDirectionIsRow(flexDirection) &&
style_.border[YGEdgeEnd].unit != YGUnitUndefined &&
!YGFloatIsUndefined(style_.border[YGEdgeEnd].value) &&
@@ -650,48 +650,48 @@ float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) {
float YGNode::getLeadingPadding(
const YGFlexDirection axis,
const float widthSize) {
const float widthSize) const {
if (YGFlexDirectionIsRow(axis) &&
style_.padding[YGEdgeStart].unit != YGUnitUndefined &&
!YGFloatIsUndefined(
YGResolveValue(style_.padding[YGEdgeStart], widthSize)) &&
YGResolveValue(style_.padding[YGEdgeStart], widthSize) > 0.0f) {
return YGResolveValue(style_.padding[YGEdgeStart], widthSize);
!YGResolveValue(style_.padding[YGEdgeStart], widthSize).isUndefined() &&
YGUnwrapFloatOptional(
YGResolveValue(style_.padding[YGEdgeStart], widthSize)) > 0.0f) {
return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeStart], widthSize));
}
float resolvedValue = YGResolveValue(
float resolvedValue = YGUnwrapFloatOptional(YGResolveValue(
*YGComputedEdgeValue(style_.padding, leading[axis], &YGValueZero),
widthSize);
widthSize));
return YGFloatMax(resolvedValue, 0.0f);
}
float YGNode::getTrailingPadding(
const YGFlexDirection axis,
const float widthSize) {
const float widthSize) const {
if (YGFlexDirectionIsRow(axis) &&
style_.padding[YGEdgeEnd].unit != YGUnitUndefined &&
!YGFloatIsUndefined(
YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) &&
YGResolveValue(style_.padding[YGEdgeEnd], widthSize) >= 0.0f) {
return YGResolveValue(style_.padding[YGEdgeEnd], widthSize);
!YGResolveValue(style_.padding[YGEdgeEnd], widthSize).isUndefined() &&
YGUnwrapFloatOptional(
YGResolveValue(style_.padding[YGEdgeEnd], widthSize)) >= 0.0f) {
return YGUnwrapFloatOptional(YGResolveValue(style_.padding[YGEdgeEnd], widthSize));
}
float resolvedValue = YGResolveValue(
float resolvedValue = YGUnwrapFloatOptional(YGResolveValue(
*YGComputedEdgeValue(style_.padding, trailing[axis], &YGValueZero),
widthSize);
widthSize));
return YGFloatMax(resolvedValue, 0.0f);
}
float YGNode::getLeadingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) {
const float widthSize) const {
return getLeadingPadding(axis, widthSize) + getLeadingBorder(axis);
}
float YGNode::getTrailingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize) {
const float widthSize) const {
return getTrailingPadding(axis, widthSize) + getTrailingBorder(axis);
}

View File

@@ -47,10 +47,10 @@ struct YGNode {
YGBaselineFunc baseline,
YGDirtiedFunc dirtied,
YGStyle style,
YGLayout layout,
const YGLayout& layout,
uint32_t lineIndex,
YGNodeRef parent,
YGVector children,
const YGVector& children,
YGNodeRef nextChild,
YGConfigRef config,
bool isDirty,
@@ -80,23 +80,23 @@ struct YGNode {
YGValue getResolvedDimension(int index);
// Methods related to positions, margin, padding and border
float getLeadingPosition(const YGFlexDirection axis, const float axisSize);
bool isLeadingPositionDefined(const YGFlexDirection axis);
bool isTrailingPosDefined(const YGFlexDirection axis);
float getTrailingPosition(const YGFlexDirection axis, const float axisSize);
float getLeadingMargin(const YGFlexDirection axis, const float widthSize);
float getTrailingMargin(const YGFlexDirection axis, const float widthSize);
float getLeadingBorder(const YGFlexDirection flexDirection);
float getTrailingBorder(const YGFlexDirection flexDirection);
float getLeadingPadding(const YGFlexDirection axis, const float widthSize);
float getTrailingPadding(const YGFlexDirection axis, const float widthSize);
float getLeadingPosition(const YGFlexDirection axis, const float axisSize) const;
bool isLeadingPositionDefined(const YGFlexDirection axis) const;
bool isTrailingPosDefined(const YGFlexDirection axis) const;
float getTrailingPosition(const YGFlexDirection axis, const float axisSize) const;
float getLeadingMargin(const YGFlexDirection axis, const float widthSize) const;
float getTrailingMargin(const YGFlexDirection axis, const float widthSize) const;
float getLeadingBorder(const YGFlexDirection flexDirection) const;
float getTrailingBorder(const YGFlexDirection flexDirection) const;
float getLeadingPadding(const YGFlexDirection axis, const float widthSize) const;
float getTrailingPadding(const YGFlexDirection axis, const float widthSize) const;
float getLeadingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize);
const float widthSize) const;
float getTrailingPaddingAndBorder(
const YGFlexDirection axis,
const float widthSize);
float getMarginForAxis(const YGFlexDirection axis, const float widthSize);
const float widthSize) const;
float getMarginForAxis(const YGFlexDirection axis, const float widthSize) const;
// Setters
void setContext(void* context);
@@ -106,13 +106,13 @@ struct YGNode {
void setMeasureFunc(YGMeasureFunc measureFunc);
void setBaseLineFunc(YGBaselineFunc baseLineFunc);
void setDirtiedFunc(YGDirtiedFunc dirtiedFunc);
void setStyle(YGStyle style);
void setStyle(const YGStyle& style);
void setStyleFlexDirection(YGFlexDirection direction);
void setStyleAlignContent(YGAlign alignContent);
void setLayout(YGLayout layout);
void setLayout(const YGLayout& layout);
void setLineIndex(uint32_t lineIndex);
void setParent(YGNodeRef parent);
void setChildren(YGVector children);
void setChildren(const YGVector& children);
void setNextChild(YGNodeRef nextChild);
void setConfig(YGConfigRef config);
void setDirty(bool isDirty);

View File

@@ -39,10 +39,12 @@ static void appendFormatedString(string* str, const char* fmt, ...) {
str->append(result);
}
static void
appendFloatIfNotUndefined(string* base, const string key, const float num) {
if (!YGFloatIsUndefined(num)) {
appendFormatedString(base, "%s: %g; ", key.c_str(), num);
static void appendFloatOptionalIfDefined(
string* base,
const string key,
const YGFloatOptional num) {
if (!num.isUndefined()) {
appendFormatedString(base, "%s: %g; ", key.c_str(), num.getValue());
}
}
@@ -70,7 +72,10 @@ appendNumberIfNotAuto(string* base, const string& key, const YGValue number) {
static void
appendNumberIfNotZero(string* base, const string& str, const YGValue number) {
if (!YGFloatsEqual(number.value, 0)) {
if (number.unit == YGUnitAuto) {
base->append(str + ": auto; ");
} else if (!YGFloatsEqual(number.value, 0)) {
appendNumberIfNotUndefined(base, str, number);
}
}
@@ -152,10 +157,11 @@ void YGNodeToString(
appendFormatedString(
str, "align-self: %s; ", YGAlignToString(node->getStyle().alignSelf));
}
appendFloatIfNotUndefined(str, "flex-grow", node->getStyle().flexGrow);
appendFloatIfNotUndefined(str, "flex-shrink", node->getStyle().flexShrink);
appendFloatOptionalIfDefined(str, "flex-grow", node->getStyle().flexGrow);
appendFloatOptionalIfDefined(
str, "flex-shrink", node->getStyle().flexShrink);
appendNumberIfNotAuto(str, "flex-basis", node->getStyle().flexBasis);
appendFloatIfNotUndefined(str, "flex", node->getStyle().flex);
appendFloatOptionalIfDefined(str, "flex", node->getStyle().flex);
if (node->getStyle().flexWrap != YGNode().getStyle().flexWrap) {
appendFormatedString(

View File

@@ -7,7 +7,7 @@
#include "YGStyle.h"
const YGValue kYGValueUndefined = {YGUndefined, YGUnitUndefined};
const YGValue kYGValueUndefined = {0, YGUnitUndefined};
const YGValue kYGValueAuto = {YGUndefined, YGUnitAuto};
@@ -39,10 +39,10 @@ YGStyle::YGStyle()
flexWrap(YGWrapNoWrap),
overflow(YGOverflowVisible),
display(YGDisplayFlex),
flex(YGUndefined),
flexGrow(YGUndefined),
flexShrink(YGUndefined),
flexBasis(kYGValueAuto),
flex(YGFloatOptional()),
flexGrow(YGFloatOptional()),
flexShrink(YGFloatOptional()),
flexBasis({0, YGUnitAuto}),
margin(kYGDefaultEdgeValuesUnit),
position(kYGDefaultEdgeValuesUnit),
padding(kYGDefaultEdgeValuesUnit),
@@ -69,19 +69,26 @@ bool YGStyle::operator==(const YGStyle& style) {
YGValueArrayEqual(minDimensions, style.minDimensions) &&
YGValueArrayEqual(maxDimensions, style.maxDimensions);
if (!(YGFloatIsUndefined(flex) && YGFloatIsUndefined(style.flex))) {
areNonFloatValuesEqual = areNonFloatValuesEqual && flex == style.flex;
areNonFloatValuesEqual =
areNonFloatValuesEqual && flex.isUndefined() == style.flex.isUndefined();
if (areNonFloatValuesEqual && !flex.isUndefined() &&
!style.flex.isUndefined()) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && flex.getValue() == style.flex.getValue();
}
if (!(YGFloatIsUndefined(flexGrow) && YGFloatIsUndefined(style.flexGrow))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && flexGrow == style.flexGrow;
areNonFloatValuesEqual = areNonFloatValuesEqual &&
flexGrow.isUndefined() == style.flexGrow.isUndefined();
if (areNonFloatValuesEqual && !flexGrow.isUndefined()) {
areNonFloatValuesEqual = areNonFloatValuesEqual &&
flexGrow.getValue() == style.flexGrow.getValue();
}
if (!(YGFloatIsUndefined(flexShrink) &&
YGFloatIsUndefined(style.flexShrink))) {
areNonFloatValuesEqual =
areNonFloatValuesEqual && flexShrink == style.flexShrink;
areNonFloatValuesEqual = areNonFloatValuesEqual &&
flexShrink.isUndefined() == style.flexShrink.isUndefined();
if (areNonFloatValuesEqual && !style.flexShrink.isUndefined()) {
areNonFloatValuesEqual = areNonFloatValuesEqual &&
flexShrink.getValue() == style.flexShrink.getValue();
}
if (!(YGFloatIsUndefined(aspectRatio) &&

View File

@@ -6,6 +6,7 @@
*/
#pragma once
#include "YGFloatOptional.h"
#include "Yoga-internal.h"
#include "Yoga.h"
@@ -20,9 +21,9 @@ struct YGStyle {
YGWrap flexWrap;
YGOverflow overflow;
YGDisplay display;
float flex;
float flexGrow;
float flexShrink;
YGFloatOptional flex;
YGFloatOptional flexGrow;
YGFloatOptional flexShrink;
YGValue flexBasis;
std::array<YGValue, YGEdgeCount> margin;
std::array<YGValue, YGEdgeCount> position;

View File

@@ -6,13 +6,13 @@
*/
#include "Yoga.h"
#include <float.h>
#include <string.h>
#include <algorithm>
#include "Utils.h"
#include "YGNode.h"
#include "YGNodePrint.h"
#include "Yoga-internal.h"
#ifdef _MSC_VER
#include <float.h>
@@ -295,8 +295,8 @@ static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
}
void YGNodeFree(const YGNodeRef node) {
if (node->getParent()) {
node->getParent()->removeChild(node);
if (YGNodeRef parent = node->getParent()) {
parent->removeChild(node);
node->setParent(nullptr);
}
@@ -477,6 +477,48 @@ void YGNodeRemoveAllChildren(const YGNodeRef parent) {
parent->markDirtyAndPropogate();
}
static void YGNodeSetChildrenInternal(YGNodeRef const parent, const std::vector<YGNodeRef> &children)
{
if (!parent) {
return;
}
if (children.size() == 0) {
if (YGNodeGetChildCount(parent) > 0) {
for (YGNodeRef const child : parent->getChildren()) {
child->setLayout(YGLayout());
child->setParent(nullptr);
}
parent->setChildren(YGVector());
parent->markDirtyAndPropogate();
}
} else {
if (YGNodeGetChildCount(parent) > 0) {
for (YGNodeRef const oldChild : parent->getChildren()) {
// Our new children may have nodes in common with the old children. We don't reset these common nodes.
if (std::find(children.begin(), children.end(), oldChild) == children.end()) {
oldChild->setLayout(YGLayout());
oldChild->setParent(nullptr);
}
}
}
parent->setChildren(children);
for (YGNodeRef child : children) {
child->setParent(parent);
}
parent->markDirtyAndPropogate();
}
}
void YGNodeSetChildren(YGNodeRef const parent, const YGNodeRef c[], const uint32_t count) {
const YGVector children = {c, c + count};
YGNodeSetChildrenInternal(parent, children);
}
void YGNodeSetChildren(YGNodeRef const parent, const std::vector<YGNodeRef> &children)
{
YGNodeSetChildrenInternal(parent, children);
}
YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) {
if (index < node->getChildren().size()) {
return node->getChild(index);
@@ -510,16 +552,16 @@ void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) {
}
float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
return YGFloatIsUndefined(node->getStyle().flexGrow)
return node->getStyle().flexGrow.isUndefined()
? kDefaultFlexGrow
: node->getStyle().flexGrow;
: node->getStyle().flexGrow.getValue();
}
float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
return YGFloatIsUndefined(node->getStyle().flexShrink)
return node->getStyle().flexShrink.isUndefined()
? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
: kDefaultFlexShrink)
: node->getStyle().flexShrink;
: node->getStyle().flexShrink.getValue();
}
#define YG_NODE_STYLE_PROPERTY_SETTER_IMPL( \
@@ -537,7 +579,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
type, name, paramName, instanceName) \
void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
YGValue value = { \
.value = paramName, \
.value = YGFloatSanitize(paramName), \
.unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
}; \
if ((node->getStyle().instanceName.value != value.value && \
@@ -553,7 +595,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
void YGNodeStyleSet##name##Percent( \
const YGNodeRef node, const type paramName) { \
YGValue value = { \
.value = paramName, \
.value = YGFloatSanitize(paramName), \
.unit = \
YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
}; \
@@ -620,7 +662,11 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
float, name, paramName, instanceName) \
\
type YGNodeStyleGet##name(const YGNodeRef node) { \
return node->getStyle().instanceName; \
YGValue value = node->getStyle().instanceName; \
if (value.unit == YGUndefined || value.unit == YGUnitAuto) { \
value.value = YGUndefined; \
} \
return value; \
}
#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \
@@ -636,7 +682,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
if (node->getStyle().instanceName[edge].unit != YGUnitAuto) { \
YGStyle style = node->getStyle(); \
style.instanceName[edge].value = YGUndefined; \
style.instanceName[edge].value = 0; \
style.instanceName[edge].unit = YGUnitAuto; \
node->setStyle(style); \
node->markDirtyAndPropogate(); \
@@ -648,7 +694,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
void YGNodeStyleSet##name( \
const YGNodeRef node, const YGEdge edge, const float paramName) { \
YGValue value = { \
.value = paramName, \
.value = YGFloatSanitize(paramName), \
.unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
}; \
if ((node->getStyle().instanceName[edge].value != value.value && \
@@ -664,7 +710,7 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
void YGNodeStyleSet##name##Percent( \
const YGNodeRef node, const YGEdge edge, const float paramName) { \
YGValue value = { \
.value = paramName, \
.value = YGFloatSanitize(paramName), \
.unit = \
YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
}; \
@@ -680,28 +726,11 @@ float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
\
WIN_STRUCT(type) \
YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \
return WIN_STRUCT_REF(node->getStyle().instanceName[edge]); \
}
#define YG_NODE_STYLE_EDGE_PROPERTY_IMPL(type, name, paramName, instanceName) \
void YGNodeStyleSet##name( \
const YGNodeRef node, const YGEdge edge, const float paramName) { \
YGValue value = { \
.value = paramName, \
.unit = YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
}; \
if ((node->getStyle().instanceName[edge].value != value.value && \
value.unit != YGUnitUndefined) || \
node->getStyle().instanceName[edge].unit != value.unit) { \
YGStyle style = node->getStyle(); \
style.instanceName[edge] = value; \
node->setStyle(style); \
node->markDirtyAndPropogate(); \
YGValue value = node->getStyle().instanceName[edge]; \
if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
value.value = YGUndefined; \
} \
} \
\
float YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \
return node->getStyle().instanceName[edge].value; \
return WIN_STRUCT_REF(value); \
}
#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
@@ -751,16 +780,136 @@ YG_NODE_STYLE_PROPERTY_IMPL(YGWrap, FlexWrap, flexWrap, flexWrap);
YG_NODE_STYLE_PROPERTY_IMPL(YGOverflow, Overflow, overflow, overflow);
YG_NODE_STYLE_PROPERTY_IMPL(YGDisplay, Display, display, display);
YG_NODE_STYLE_PROPERTY_IMPL(float, Flex, flex, flex);
YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexGrow, flexGrow, flexGrow);
YG_NODE_STYLE_PROPERTY_SETTER_IMPL(float, FlexShrink, flexShrink, flexShrink);
YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, FlexBasis, flexBasis, flexBasis);
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
if (!YGFloatOptionalFloatEquals(node->getStyle().flex, flex)) {
YGStyle style = node->getStyle();
if (YGFloatIsUndefined(flex)) {
style.flex = YGFloatOptional();
} else {
style.flex = YGFloatOptional(flex);
}
node->setStyle(style);
node->markDirtyAndPropogate();
}
}
// TODO(T26792433): Change the API to accept YGFloatOptional.
float YGNodeStyleGetFlex(const YGNodeRef node) {
return node->getStyle().flex.isUndefined() ? YGUndefined
: node->getStyle().flex.getValue();
}
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
if (!YGFloatOptionalFloatEquals(node->getStyle().flexGrow, flexGrow)) {
YGStyle style = node->getStyle();
if (YGFloatIsUndefined(flexGrow)) {
style.flexGrow = YGFloatOptional();
} else {
style.flexGrow = YGFloatOptional(flexGrow);
}
node->setStyle(style);
node->markDirtyAndPropogate();
}
}
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
if (!YGFloatOptionalFloatEquals(node->getStyle().flexShrink, flexShrink)) {
YGStyle style = node->getStyle();
if (YGFloatIsUndefined(flexShrink)) {
style.flexShrink = YGFloatOptional();
} else {
style.flexShrink = YGFloatOptional(flexShrink);
}
node->setStyle(style);
node->markDirtyAndPropogate();
}
}
YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) {
YGValue flexBasis = node->getStyle().flexBasis;
if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) {
// TODO(T26792433): Get rid off the use of YGUndefined at client side
flexBasis.value = YGUndefined;
}
return flexBasis;
}
void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
YGValue value = {
.value = YGFloatSanitize(flexBasis),
.unit = YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint,
};
if ((node->getStyle().flexBasis.value != value.value &&
value.unit != YGUnitUndefined) ||
node->getStyle().flexBasis.unit != value.unit) {
YGStyle style = node->getStyle();
style.flexBasis = value;
node->setStyle(style);
node->markDirtyAndPropogate();
}
}
void YGNodeStyleSetFlexBasisPercent(
const YGNodeRef node,
const float flexBasisPercent) {
if (node->getStyle().flexBasis.value != flexBasisPercent ||
node->getStyle().flexBasis.unit != YGUnitPercent) {
YGStyle style = node->getStyle();
style.flexBasis.value = YGFloatSanitize(flexBasisPercent);
style.flexBasis.unit =
YGFloatIsUndefined(flexBasisPercent) ? YGUnitAuto : YGUnitPercent;
node->setStyle(style);
node->markDirtyAndPropogate();
}
}
void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
if (node->getStyle().flexBasis.unit != YGUnitAuto) {
YGStyle style = node->getStyle();
style.flexBasis.value = 0;
style.flexBasis.unit = YGUnitAuto;
node->setStyle(style);
node->markDirtyAndPropogate();
}
}
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position);
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin);
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin);
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding);
YG_NODE_STYLE_EDGE_PROPERTY_IMPL(float, Border, border, border);
// TODO(T26792433): Change the API to accept YGFloatOptional.
void YGNodeStyleSetBorder(
const YGNodeRef node,
const YGEdge edge,
const float border) {
YGValue value = {
.value = YGFloatSanitize(border),
.unit = YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint,
};
if ((node->getStyle().border[edge].value != value.value &&
value.unit != YGUnitUndefined) ||
node->getStyle().border[edge].unit != value.unit) {
YGStyle style = node->getStyle();
style.border[edge] = value;
node->setStyle(style);
node->markDirtyAndPropogate();
}
}
float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
if (node->getStyle().border[edge].unit == YGUnitUndefined ||
node->getStyle().border[edge].unit == YGUnitAuto) {
// TODO(T26792433): Rather than returning YGUndefined, change the api to
// return YGFloatOptional.
return YGUndefined;
}
return node->getStyle().border[edge].value;
}
YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Width, width, dimensions[YGDimensionWidth]);
YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Height, height, dimensions[YGDimensionHeight]);
@@ -785,6 +934,10 @@ YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding);
bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
return node->getLayout().doesLegacyStretchFlagAffectsLayout;
}
uint32_t gCurrentGenerationCount = 0;
bool YGLayoutNodeInternal(const YGNodeRef node,
@@ -939,15 +1092,15 @@ static float YGNodeBoundAxisWithinMinAndMax(const YGNodeRef node,
float max = YGUndefined;
if (YGFlexDirectionIsColumn(axis)) {
min = YGResolveValue(
node->getStyle().minDimensions[YGDimensionHeight], axisSize);
max = YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight], axisSize);
min = YGUnwrapFloatOptional(YGResolveValue(
node->getStyle().minDimensions[YGDimensionHeight], axisSize));
max = YGUnwrapFloatOptional(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight], axisSize));
} else if (YGFlexDirectionIsRow(axis)) {
min = YGResolveValue(
node->getStyle().minDimensions[YGDimensionWidth], axisSize);
max = YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], axisSize);
min = YGUnwrapFloatOptional(YGResolveValue(
node->getStyle().minDimensions[YGDimensionWidth], axisSize));
max = YGUnwrapFloatOptional(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], axisSize));
}
float boundValue = value;
@@ -993,8 +1146,8 @@ static void YGConstrainMaxSizeForMode(const YGNodeRef node,
YGMeasureMode *mode,
float *size) {
const float maxSize =
YGResolveValue(
node->getStyle().maxDimensions[dim[axis]], parentAxisSize) +
YGUnwrapFloatOptional(YGResolveValue(
node->getStyle().maxDimensions[dim[axis]], parentAxisSize)) +
node->getMarginForAxis(axis, parentWidth);
switch (*mode) {
case YGMeasureModeExactly:
@@ -1032,7 +1185,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
YGMeasureMode childHeightMeasureMode;
const float resolvedFlexBasis =
YGResolveValue(child->resolveFlexBasisPtr(), mainAxisParentSize);
YGUnwrapFloatOptional(YGResolveValue(child->resolveFlexBasisPtr(), mainAxisParentSize));
const bool isRowStyleDimDefined = YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, parentWidth);
const bool isColumnStyleDimDefined =
YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, parentHeight);
@@ -1050,14 +1203,14 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
} else if (isMainAxisRow && isRowStyleDimDefined) {
// The width is definite, so use that as the flex basis.
child->setLayoutComputedFlexBasis(YGFloatMax(
YGResolveValue(
child->getResolvedDimension(YGDimensionWidth), parentWidth),
YGUnwrapFloatOptional(YGResolveValue(
child->getResolvedDimension(YGDimensionWidth), parentWidth)),
YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, parentWidth)));
} else if (!isMainAxisRow && isColumnStyleDimDefined) {
// The height is definite, so use that as the flex basis.
child->setLayoutComputedFlexBasis(YGFloatMax(
YGResolveValue(
child->getResolvedDimension(YGDimensionHeight), parentHeight),
YGUnwrapFloatOptional(YGResolveValue(
child->getResolvedDimension(YGDimensionHeight), parentHeight)),
YGNodePaddingAndBorderForAxis(
child, YGFlexDirectionColumn, parentWidth)));
} else {
@@ -1075,15 +1228,15 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node,
if (isRowStyleDimDefined) {
childWidth =
YGResolveValue(
child->getResolvedDimension(YGDimensionWidth), parentWidth) +
YGUnwrapFloatOptional(YGResolveValue(
child->getResolvedDimension(YGDimensionWidth), parentWidth)) +
marginRow;
childWidthMeasureMode = YGMeasureModeExactly;
}
if (isColumnStyleDimDefined) {
childHeight =
YGResolveValue(
child->getResolvedDimension(YGDimensionHeight), parentHeight) +
YGUnwrapFloatOptional(YGResolveValue(
child->getResolvedDimension(YGDimensionHeight), parentHeight)) +
marginColumn;
childHeightMeasureMode = YGMeasureModeExactly;
}
@@ -1200,7 +1353,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
childWidth =
YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width) +
YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionWidth), width)) +
marginRow;
} else {
// If the child doesn't have a specified width, compute the width based
@@ -1219,7 +1372,7 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node,
if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
childHeight =
YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height) +
YGUnwrapFloatOptional(YGResolveValue(child->getResolvedDimension(YGDimensionHeight), height)) +
marginColumn;
} else {
// If the child doesn't have a specified height, compute the height
@@ -1556,15 +1709,16 @@ static float YGNodeCalculateAvailableInnerDim(
if (!YGFloatIsUndefined(availableInnerDim)) {
// We want to make sure our available height does not violate min and max
// constraints
const float minInnerDim =
YGFloatIsUndefined(YGResolveValue(
node->getStyle().minDimensions[dimension], parentDim))
const YGFloatOptional minDimensionOptional = YGResolveValue(node->getStyle().minDimensions[dimension], parentDim);
const float minInnerDim = minDimensionOptional.isUndefined()
? 0.0f
: YGResolveValue(node->getStyle().minDimensions[dimension], parentDim) -
paddingAndBorder;
const float maxInnerDim =
YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) -
paddingAndBorder;
: minDimensionOptional.getValue() - paddingAndBorder;
const YGFloatOptional maxDimensionOptional = YGResolveValue(node->getStyle().maxDimensions[dimension], parentDim) ;
const float maxInnerDim = maxDimensionOptional.isUndefined()
? FLT_MAX
: maxDimensionOptional.getValue() - paddingAndBorder;
availableInnerDim =
YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
}
@@ -1853,9 +2007,9 @@ static float YGDistributeFreeSpaceSecondPass(
: YGMeasureModeAtMost;
} else {
childCrossSize =
YGResolveValue(
YGUnwrapFloatOptional(YGResolveValue(
currentRelativeChild->getResolvedDimension(dim[crossAxis]),
availableInnerCrossDim) +
availableInnerCrossDim)) +
marginCross;
const bool isLoosePercentageMeasurement =
currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
@@ -2096,12 +2250,12 @@ static void YGJustifyMainAxis(
if (measureModeMainDim == YGMeasureModeAtMost &&
collectedFlexItemsValues.remainingFreeSpace > 0) {
if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
!YGFloatIsUndefined(YGResolveValue(
style.minDimensions[dim[mainAxis]], mainAxisParentSize))) {
!YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisParentSize)
.isUndefined()) {
collectedFlexItemsValues.remainingFreeSpace = YGFloatMax(
0,
YGResolveValue(
style.minDimensions[dim[mainAxis]], mainAxisParentSize) -
YGUnwrapFloatOptional(YGResolveValue(
style.minDimensions[dim[mainAxis]], mainAxisParentSize)) -
(availableInnerMainDim -
collectedFlexItemsValues.remainingFreeSpace));
} else {
@@ -2459,20 +2613,17 @@ static void YGNodelayoutImpl(const YGNodeRef node,
node->getMarginForAxis(YGFlexDirectionColumn, parentWidth);
const float minInnerWidth =
YGResolveValue(
node->getStyle().minDimensions[YGDimensionWidth], parentWidth) -
YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionWidth], parentWidth)) -
paddingAndBorderAxisRow;
const float maxInnerWidth =
YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], parentWidth) -
YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionWidth], parentWidth)) -
paddingAndBorderAxisRow;
const float minInnerHeight =
YGResolveValue(
node->getStyle().minDimensions[YGDimensionHeight], parentHeight) -
YGUnwrapFloatOptional(YGResolveValue(node->getStyle().minDimensions[YGDimensionHeight], parentHeight)) -
paddingAndBorderAxisColumn;
const float maxInnerHeight =
YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight], parentHeight) -
YGUnwrapFloatOptional(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight], parentHeight)) -
paddingAndBorderAxisColumn;
const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
@@ -3601,15 +3752,15 @@ void YGNodeCalculateLayout(
YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, parentWidth)) {
width =
YGResolveValue(
node->getResolvedDimension(dim[YGFlexDirectionRow]), parentWidth) +
YGUnwrapFloatOptional(YGResolveValue(
node->getResolvedDimension(dim[YGFlexDirectionRow]), parentWidth)) +
node->getMarginForAxis(YGFlexDirectionRow, parentWidth);
widthMeasureMode = YGMeasureModeExactly;
} else if (!YGFloatIsUndefined(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth],
parentWidth))) {
width = YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], parentWidth);
} else if (!YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], parentWidth)
.isUndefined()) {
width = YGUnwrapFloatOptional(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionWidth], parentWidth));
widthMeasureMode = YGMeasureModeAtMost;
} else {
width = parentWidth;
@@ -3620,16 +3771,16 @@ void YGNodeCalculateLayout(
float height = YGUndefined;
YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, parentHeight)) {
height = YGResolveValue(
height = YGUnwrapFloatOptional(YGResolveValue(
node->getResolvedDimension(dim[YGFlexDirectionColumn]),
parentHeight) +
parentHeight)) +
node->getMarginForAxis(YGFlexDirectionColumn, parentWidth);
heightMeasureMode = YGMeasureModeExactly;
} else if (!YGFloatIsUndefined(YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight],
parentHeight))) {
height = YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight], parentHeight);
} else if (!YGResolveValue(
node->getStyle().maxDimensions[YGDimensionHeight],
parentHeight)
.isUndefined()) {
height = YGUnwrapFloatOptional(YGResolveValue(node->getStyle().maxDimensions[YGDimensionHeight], parentHeight));
heightMeasureMode = YGMeasureModeAtMost;
} else {
height = parentHeight;
@@ -3729,6 +3880,12 @@ void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
}
}
void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
const YGConfigRef config,
const bool shouldDiffLayout) {
config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout;
}
static void YGVLog(const YGConfigRef config,
const YGNodeRef node,
YGLogLevel level,
@@ -3810,3 +3967,18 @@ void *YGConfigGetContext(const YGConfigRef config) {
void YGConfigSetNodeClonedFunc(const YGConfigRef config, const YGNodeClonedFunc callback) {
config->cloneNodeCallback = callback;
}
static void YGTraverseChildrenPreOrder(const YGVector& children, const std::function<void(YGNodeRef node)>& f) {
for (YGNodeRef node : children) {
f(node);
YGTraverseChildrenPreOrder(node->getChildren(), f);
}
}
void YGTraversePreOrder(YGNodeRef const node, std::function<void(YGNodeRef node)>&& f) {
if (!node) {
return;
}
f(node);
YGTraverseChildrenPreOrder(node->getChildren(), f);
}

View File

@@ -84,6 +84,7 @@ WIN_EXPORT void YGNodeRemoveAllChildren(const YGNodeRef node);
WIN_EXPORT YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index);
WIN_EXPORT YGNodeRef YGNodeGetParent(const YGNodeRef node);
WIN_EXPORT uint32_t YGNodeGetChildCount(const YGNodeRef node);
WIN_EXPORT void YGNodeSetChildren(YGNodeRef const parent, const YGNodeRef children[], const uint32_t count);
WIN_EXPORT void YGNodeCalculateLayout(const YGNodeRef node,
const float availableWidth,
@@ -190,7 +191,6 @@ YG_NODE_STYLE_PROPERTY(YGPositionType, PositionType, positionType);
YG_NODE_STYLE_PROPERTY(YGWrap, FlexWrap, flexWrap);
YG_NODE_STYLE_PROPERTY(YGOverflow, Overflow, overflow);
YG_NODE_STYLE_PROPERTY(YGDisplay, Display, display);
YG_NODE_STYLE_PROPERTY(float, Flex, flex);
YG_NODE_STYLE_PROPERTY(float, FlexGrow, flexGrow);
YG_NODE_STYLE_PROPERTY(float, FlexShrink, flexShrink);
@@ -232,6 +232,7 @@ YG_NODE_LAYOUT_PROPERTY(float, Width);
YG_NODE_LAYOUT_PROPERTY(float, Height);
YG_NODE_LAYOUT_PROPERTY(YGDirection, Direction);
YG_NODE_LAYOUT_PROPERTY(bool, HadOverflow);
bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node);
// Get the computed values for these nodes after performing layout. If they were set using
// point values then the returned value will be the same as YGNodeStyleGetXXX. However if
@@ -249,10 +250,12 @@ WIN_EXPORT void YGAssertWithNode(const YGNodeRef node, const bool condition, con
WIN_EXPORT void YGAssertWithConfig(const YGConfigRef config,
const bool condition,
const char *message);
// Set this to number of pixels in 1 point to round calculation results
// If you want to avoid rounding - set PointScaleFactor to 0
WIN_EXPORT void YGConfigSetPointScaleFactor(const YGConfigRef config, const float pixelsInPoint);
void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
const YGConfigRef config,
const bool shouldDiffLayout);
// Yoga previously had an error where containers would take the maximum space possible instead of
// the minimum
@@ -296,3 +299,15 @@ WIN_EXPORT float YGRoundValueToPixelGrid(
const bool forceFloor);
YG_EXTERN_C_END
#ifdef __cplusplus
#include <functional>
#include <vector>
// Calls f on each node in the tree including the given node argument.
extern void YGTraversePreOrder(YGNodeRef const node, std::function<void(YGNodeRef node)>&& f);
extern void YGNodeSetChildren(YGNodeRef const parent, const std::vector<YGNodeRef> &children);
#endif