diff --git a/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems b/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems
index 3b51cd9424..c35d035416 100644
--- a/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems
+++ b/csharp/Facebook.Yoga/Facebook.Yoga.Shared.projitems
@@ -15,6 +15,7 @@
+
diff --git a/csharp/Facebook.Yoga/Native.cs b/csharp/Facebook.Yoga/Native.cs
index 6e20fba0d7..9ec74145d9 100644
--- a/csharp/Facebook.Yoga/Native.cs
+++ b/csharp/Facebook.Yoga/Native.cs
@@ -138,6 +138,9 @@ public static extern void YGInteropSetLogger(
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int YGNodeGetInstanceCount();
+ [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ public static extern int YGConfigGetInstanceCount();
+
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGConfigSetExperimentalFeatureEnabled(
YGConfigHandle config,
@@ -149,6 +152,19 @@ public static extern bool YGConfigIsExperimentalFeatureEnabled(
YGConfigHandle config,
YogaExperimentalFeature feature);
+ [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void YGConfigSetUseWebDefaults(
+ YGConfigHandle config,
+ bool useWebDefaults);
+
+ [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ public static extern bool YGConfigGetUseWebDefaults(YGConfigHandle config);
+
+ [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ public static extern void YGConfigSetPointScaleFactor(
+ YGConfigHandle config,
+ float pixelsInPoint);
+
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGNodeInsertChild(
YGNodeHandle node,
diff --git a/csharp/Facebook.Yoga/YogaConfig.cs b/csharp/Facebook.Yoga/YogaConfig.cs
new file mode 100644
index 0000000000..c35773ff75
--- /dev/null
+++ b/csharp/Facebook.Yoga/YogaConfig.cs
@@ -0,0 +1,72 @@
+/**
+ * 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.
+ */
+
+using System;
+
+namespace Facebook.Yoga
+{
+ public class YogaConfig
+ {
+ private Native.YGConfigHandle _ygConfig;
+
+ public YogaConfig()
+ {
+ _ygConfig = Native.YGConfigNew();
+ if (_ygConfig.IsInvalid)
+ {
+ throw new InvalidOperationException("Failed to allocate native memory");
+ }
+ }
+
+ internal Native.YGConfigHandle Handle
+ {
+ get {
+ return _ygConfig;
+ }
+ }
+
+ public void SetExperimentalFeatureEnabled(
+ YogaExperimentalFeature feature,
+ bool enabled)
+ {
+ Native.YGConfigSetExperimentalFeatureEnabled(_ygConfig, feature, enabled);
+ }
+
+ public bool IsExperimentalFeatureEnabled(YogaExperimentalFeature feature)
+ {
+ return Native.YGConfigIsExperimentalFeatureEnabled(_ygConfig, feature);
+ }
+
+ public bool UseWebDefaults
+ {
+ get
+ {
+ return Native.YGConfigGetUseWebDefaults(_ygConfig);
+ }
+
+ set
+ {
+ Native.YGConfigSetUseWebDefaults(_ygConfig, value);
+ }
+ }
+
+ public float PointScaleFactor
+ {
+ set
+ {
+ Native.YGConfigSetPointScaleFactor(_ygConfig, value);
+ }
+ }
+
+ public static int GetInstanceCount()
+ {
+ return Native.YGConfigGetInstanceCount();
+ }
+ }
+}
diff --git a/csharp/Facebook.Yoga/YogaNode.cs b/csharp/Facebook.Yoga/YogaNode.cs
index cf4d7c7825..3717ffe66c 100644
--- a/csharp/Facebook.Yoga/YogaNode.cs
+++ b/csharp/Facebook.Yoga/YogaNode.cs
@@ -24,43 +24,10 @@
namespace Facebook.Yoga
{
- public class YogaConfig
- {
-
- private Native.YGConfigHandle _ygConfig;
-
- public YogaConfig()
- {
- _ygConfig = Native.YGConfigNew();
- if (_ygConfig.IsInvalid)
- {
- throw new InvalidOperationException("Failed to allocate native memory");
- }
- }
-
- internal Native.YGConfigHandle Handle {
- get {
- return _ygConfig;
- }
- }
-
- public void SetExperimentalFeatureEnabled(
- YogaExperimentalFeature feature,
- bool enabled)
- {
- Native.YGConfigSetExperimentalFeatureEnabled(_ygConfig, feature, enabled);
- }
-
- public bool IsExperimentalFeatureEnabled(YogaExperimentalFeature feature)
- {
- return Native.YGConfigIsExperimentalFeatureEnabled(_ygConfig, feature);
- }
-
- }
-
public partial class YogaNode : IEnumerable
{
private Native.YGNodeHandle _ygNode;
+ private YogaConfig _config;
private WeakReference _parent;
private List _children;
private MeasureFunction _measureFunction;
@@ -89,7 +56,15 @@ public YogaNode(YogaConfig config)
{
YogaLogger.Initialize();
- _ygNode = Native.YGNodeNewWithConfig(config.Handle);
+ if (config != null)
+ {
+ _config = config;
+ _ygNode = Native.YGNodeNewWithConfig(_config.Handle);
+ }
+ else
+ {
+ _ygNode = Native.YGNodeNew();
+ }
if (_ygNode.IsInvalid)
{
throw new InvalidOperationException("Failed to allocate native memory");
@@ -97,7 +72,7 @@ public YogaNode(YogaConfig config)
}
public YogaNode(YogaNode srcNode)
- : this()
+ : this(srcNode._config)
{
CopyStyle(srcNode);
}
diff --git a/csharp/tests/Facebook.Yoga/Facebook.Yoga.Shared.Tests.projitems b/csharp/tests/Facebook.Yoga/Facebook.Yoga.Shared.Tests.projitems
index 0afe5e630a..3bbfd97013 100644
--- a/csharp/tests/Facebook.Yoga/Facebook.Yoga.Shared.Tests.projitems
+++ b/csharp/tests/Facebook.Yoga/Facebook.Yoga.Shared.Tests.projitems
@@ -22,6 +22,7 @@
+
diff --git a/csharp/tests/Facebook.Yoga/YogaConfigTest.cs b/csharp/tests/Facebook.Yoga/YogaConfigTest.cs
new file mode 100644
index 0000000000..0f678da62b
--- /dev/null
+++ b/csharp/tests/Facebook.Yoga/YogaConfigTest.cs
@@ -0,0 +1,136 @@
+/**
+ * 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.
+ */
+
+using NUnit.Framework;
+using System;
+
+/**
+ * Tests for {@link YogaConfig}.
+ */
+namespace Facebook.Yoga
+{
+ [TestFixture]
+ public class YogaConfigTest
+ {
+ [Test]
+ public void TestUseWebDefaults()
+ {
+ YogaNode node0 = new YogaNode(new YogaConfig{UseWebDefaults = true});
+ Assert.AreEqual(YogaFlexDirection.Row, node0.FlexDirection);
+
+ node0.Reset();
+ Assert.AreEqual(YogaFlexDirection.Row, node0.FlexDirection);
+
+ YogaConfig config = new YogaConfig();
+ config.UseWebDefaults = true;
+ YogaNode node1 = new YogaNode(config);
+ Assert.AreEqual(YogaFlexDirection.Row, node1.FlexDirection);
+
+ node1.Reset();
+ Assert.AreEqual(YogaFlexDirection.Row, node1.FlexDirection);
+ }
+
+ [Test]
+ public void TestDefaultConfig()
+ {
+ YogaNode node0 = new YogaNode();
+ Assert.AreEqual(YogaFlexDirection.Column, node0.FlexDirection);
+
+ YogaNode node1 = new YogaNode(new YogaConfig());
+ Assert.AreEqual(YogaFlexDirection.Column, node1.FlexDirection);
+ }
+
+ [Test]
+ public void TestCopyConstructor()
+ {
+ YogaNode srcNode = new YogaNode(new YogaConfig{UseWebDefaults = true});
+ YogaNode node0 = new YogaNode(srcNode);
+ Assert.AreEqual(YogaFlexDirection.Row, node0.FlexDirection);
+
+ node0.FlexDirection = YogaFlexDirection.Column;
+ Assert.AreEqual(YogaFlexDirection.Column, node0.FlexDirection);
+
+ node0.Reset();
+ Assert.AreEqual(YogaFlexDirection.Row, node0.FlexDirection);
+
+ YogaNode node1 = new YogaNode(srcNode)
+ {
+ FlexDirection = YogaFlexDirection.Column
+ };
+ Assert.AreEqual(YogaFlexDirection.Column, node1.FlexDirection);
+
+ node1.Reset();
+ Assert.AreEqual(YogaFlexDirection.Row, node1.FlexDirection);
+ }
+
+ public static void ForceGC()
+ {
+ YogaNodeTest.ForceGC();
+ }
+
+ [Test]
+ public void TestDestructor()
+ {
+ ForceGC();
+ int instanceCount = YogaConfig.GetInstanceCount();
+ TestDestructorForGC(instanceCount);
+ ForceGC();
+ Assert.AreEqual(instanceCount, YogaConfig.GetInstanceCount());
+ }
+
+ private void TestDestructorForGC(int instanceCount)
+ {
+ YogaConfig config = new YogaConfig();
+ Assert.IsNotNull(config);
+ Assert.AreEqual(instanceCount + 1, YogaConfig.GetInstanceCount());
+ config = null;
+ }
+
+ [Test]
+ public void TestRetainConfig()
+ {
+ ForceGC();
+ int nodeInstanceCount = YogaNode.GetInstanceCount();
+ int configInstanceCount = YogaConfig.GetInstanceCount();
+ TestRetainConfigForGC(nodeInstanceCount, configInstanceCount);
+ ForceGC();
+
+ Assert.AreEqual(nodeInstanceCount, YogaNode.GetInstanceCount());
+ Assert.AreEqual(configInstanceCount, YogaConfig.GetInstanceCount());
+ }
+
+ private void TestRetainConfigForGC(int nodeInstanceCount, int configInstanceCount)
+ {
+ ForceGC();
+ Assert.AreEqual(nodeInstanceCount, YogaNode.GetInstanceCount());
+ Assert.AreEqual(configInstanceCount, YogaConfig.GetInstanceCount());
+ YogaNode node = TestRetainConfigForGC2(nodeInstanceCount, configInstanceCount);
+ ForceGC();
+ Assert.IsNotNull(node);
+ Assert.AreEqual(configInstanceCount + 1, YogaConfig.GetInstanceCount());
+ Assert.AreEqual(nodeInstanceCount + 1, YogaNode.GetInstanceCount());
+ node = null;
+ }
+
+ private YogaNode TestRetainConfigForGC2(int nodeInstanceCount, int configInstanceCount)
+ {
+ YogaConfig config = new YogaConfig();
+ Assert.IsNotNull(config);
+ Assert.AreEqual(configInstanceCount + 1, YogaConfig.GetInstanceCount());
+
+ YogaNode node = new YogaNode(config);
+ Assert.IsNotNull(node);
+ Assert.AreEqual(nodeInstanceCount + 1, YogaNode.GetInstanceCount());
+
+ config = null;
+
+ return node;
+ }
+ }
+}
diff --git a/csharp/tests/Facebook.Yoga/YogaNodeTest.cs b/csharp/tests/Facebook.Yoga/YogaNodeTest.cs
index 6ffdeb32e7..7e75d5f5f9 100644
--- a/csharp/tests/Facebook.Yoga/YogaNodeTest.cs
+++ b/csharp/tests/Facebook.Yoga/YogaNodeTest.cs
@@ -301,7 +301,7 @@ public void TestCopyConstructor()
Assert.AreEqual(90.Pt(), node4.MaxHeight);
}
- private void ForceGC()
+ public static void ForceGC()
{
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
diff --git a/yoga/Yoga.c b/yoga/Yoga.c
index 52999d2b51..37554e00fe 100644
--- a/yoga/Yoga.c
+++ b/yoga/Yoga.c
@@ -308,6 +308,7 @@ static inline float YGResolveValueMargin(const YGValue *const value, const float
}
int32_t gNodeInstanceCount = 0;
+int32_t gConfigInstanceCount = 0;
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
const YGNodeRef node = gYGMalloc(sizeof(YGNode));
@@ -373,15 +374,21 @@ int32_t YGNodeGetInstanceCount(void) {
return gNodeInstanceCount;
}
+int32_t YGConfigGetInstanceCount(void) {
+ return gConfigInstanceCount;
+}
+
YGConfigRef YGConfigNew(void) {
const YGConfigRef config = gYGMalloc(sizeof(YGConfig));
YG_ASSERT(config, "Could not allocate memory for config");
+ gConfigInstanceCount++;
memcpy(config, &gYGConfigDefaults, sizeof(YGConfig));
return config;
}
void YGConfigFree(const YGConfigRef config) {
gYGFree(config);
+ gConfigInstanceCount--;
}
static void YGNodeMarkDirtyInternal(const YGNodeRef node) {
@@ -3468,7 +3475,8 @@ bool YGConfigGetUseWebDefaults(const YGConfigRef config) {
}
void YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree) {
- YG_ASSERT(gNodeInstanceCount == 0, "Cannot set memory functions: all node must be freed first");
+ YG_ASSERT(gNodeInstanceCount == 0 && gConfigInstanceCount == 0,
+ "Cannot set memory functions: all node must be freed first");
YG_ASSERT((ygmalloc == NULL && yccalloc == NULL && ygrealloc == NULL && ygfree == NULL) ||
(ygmalloc != NULL && yccalloc != NULL && ygrealloc != NULL && ygfree != NULL),
"Cannot set memory functions: functions must be all NULL or Non-NULL");