diff --git a/csharp/Facebook.Yoga/Native.cs b/csharp/Facebook.Yoga/Native.cs index 2c0d25ac..59dd84c7 100644 --- a/csharp/Facebook.Yoga/Native.cs +++ b/csharp/Facebook.Yoga/Native.cs @@ -22,6 +22,10 @@ namespace Facebook.Yoga internal class YGNodeHandle : SafeHandle { +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + private GCHandle _managed; +#endif + private YGNodeHandle() : base(IntPtr.Zero, true) { } @@ -36,10 +40,39 @@ namespace Facebook.Yoga protected override bool ReleaseHandle() { +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + if (_managed.IsAllocated) + { + _managed.Free(); + } +#endif Native.YGNodeFree(this.handle); GC.KeepAlive(this); return true; } + +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + public void SetContext(YogaNode node) + { + if (!_managed.IsAllocated) + { + _managed = GCHandle.Alloc(node, GCHandleType.Weak); + Native.YGNodeSetContext(this.handle, GCHandle.ToIntPtr(_managed)); + } + } + + public static YogaNode GetManaged(IntPtr ygNodePtr) + { + var node = + GCHandle.FromIntPtr(Native.YGNodeGetContext(ygNodePtr)).Target as YogaNode; + if (node == null) + { + throw new InvalidOperationException("YogaNode is already deallocated"); + } + + return node; + } +#endif } [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] @@ -68,16 +101,20 @@ namespace Facebook.Yoga YogaExperimentalFeature feature); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] - public static extern void YGNodeInsertChild(YGNodeHandle node, YGNodeHandle child, uint index); + public static extern void YGNodeInsertChild( + YGNodeHandle node, + YGNodeHandle child, + uint index); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern void YGNodeRemoveChild(YGNodeHandle node, YGNodeHandle child); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] - public static extern void YGNodeCalculateLayout(YGNodeHandle node, - float availableWidth, - float availableHeight, - YogaDirection parentDirection); + public static extern void YGNodeCalculateLayout( + YGNodeHandle node, + float availableWidth, + float availableHeight, + YogaDirection parentDirection); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern void YGNodeMarkDirty(YGNodeHandle node); @@ -105,7 +142,9 @@ namespace Facebook.Yoga [MarshalAs(UnmanagedType.FunctionPtr)] YogaBaselineFunc baselineFunc); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] - public static extern void YGNodeSetHasNewLayout(YGNodeHandle node, [MarshalAs(UnmanagedType.I1)] bool hasNewLayout); + public static extern void YGNodeSetHasNewLayout( + YGNodeHandle node, + [MarshalAs(UnmanagedType.I1)] bool hasNewLayout); [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] @@ -328,5 +367,17 @@ namespace Facebook.Yoga public static extern YogaDirection YGNodeLayoutGetDirection(YGNodeHandle node); #endregion + + #region IOS + +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr YGNodeGetContext(IntPtr node); + + [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + public static extern void YGNodeSetContext(IntPtr node, IntPtr managed); +#endif + + #endregion } } diff --git a/csharp/Facebook.Yoga/YogaLogger.cs b/csharp/Facebook.Yoga/YogaLogger.cs index e5d79b79..b05ad381 100644 --- a/csharp/Facebook.Yoga/YogaLogger.cs +++ b/csharp/Facebook.Yoga/YogaLogger.cs @@ -10,6 +10,10 @@ using System; using System.Runtime.InteropServices; +#if __IOS__ +using ObjCRuntime; +#endif + namespace Facebook.Yoga { internal static class YogaLogger @@ -18,26 +22,31 @@ namespace Facebook.Yoga public delegate void Func(YogaLogLevel level, string message); private static bool _initialized; - private static Func _managedLogger = null; + public static Func _loggerInternal = LoggerInternal; public static Func Logger = null; +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + [MonoPInvokeCallback(typeof(Func))] +#endif + public static void LoggerInternal(YogaLogLevel level, string message) + { + if (Logger != null) + { + Logger(level, message); + } + + if (level == YogaLogLevel.Error) + { + throw new InvalidOperationException(message); + } + } + public static void Initialize() { if (!_initialized) { - _managedLogger = (level, message) => { - if (Logger != null) - { - Logger(level, message); - } - - if (level == YogaLogLevel.Error) - { - throw new InvalidOperationException(message); - } - }; - Native.YGInteropSetLogger(_managedLogger); + Native.YGInteropSetLogger(_loggerInternal); _initialized = true; } } diff --git a/csharp/Facebook.Yoga/YogaNode.cs b/csharp/Facebook.Yoga/YogaNode.cs index 59b6ae08..b748a35e 100644 --- a/csharp/Facebook.Yoga/YogaNode.cs +++ b/csharp/Facebook.Yoga/YogaNode.cs @@ -12,6 +12,13 @@ using System.Collections; using System.Collections.Generic; using System.Text; +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ +using System.Runtime.InteropServices; +#endif +#if __IOS__ +using ObjCRuntime; +#endif + namespace Facebook.Yoga { public partial class YogaNode : IEnumerable @@ -20,10 +27,15 @@ namespace Facebook.Yoga private WeakReference _parent; private List _children; private MeasureFunction _measureFunction; - private YogaMeasureFunc _ygMeasureFunc; private BaselineFunction _baselineFunction; - private YogaBaselineFunc _ygBaselineFunc; private object _data; +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + private static YogaMeasureFunc _measureInternalIOS = MeasureInternalIOS; + private static YogaBaselineFunc _baselineInternalIOS = BaselineInternalIOS; +#else + private YogaMeasureFunc _measureInternal; + private YogaBaselineFunc _baselineInternal; +#endif public YogaNode() { @@ -545,15 +557,35 @@ namespace Facebook.Yoga public void SetMeasureFunction(MeasureFunction measureFunction) { _measureFunction = measureFunction; - _ygMeasureFunc = measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null; - Native.YGNodeSetMeasureFunc(_ygNode, _ygMeasureFunc); + YogaMeasureFunc func = null; + if (measureFunction != null) + { +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + _ygNode.SetContext(this); + func = _measureInternalIOS; +#else + _measureInternal = MeasureInternal; + func = _measureInternal; +#endif + } + Native.YGNodeSetMeasureFunc(_ygNode, func); } public void SetBaselineFunction(BaselineFunction baselineFunction) { _baselineFunction = baselineFunction; - _ygBaselineFunc = baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null; - Native.YGNodeSetBaselineFunc(_ygNode, _ygBaselineFunc); + YogaBaselineFunc func = null; + if (baselineFunction != null) + { +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + _ygNode.SetContext(this); + func = _baselineInternalIOS; +#else + _baselineInternal = BaselineInternal; + func = _baselineInternal; +#endif + } + Native.YGNodeSetBaselineFunc(_ygNode, func); } public void CalculateLayout() @@ -565,6 +597,20 @@ namespace Facebook.Yoga Native.YGNodeStyleGetDirection(_ygNode)); } +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + [MonoPInvokeCallback(typeof(YogaMeasureFunc))] + private static YogaSize MeasureInternalIOS( + IntPtr ygNodePtr, + float width, + YogaMeasureMode widthMode, + float height, + YogaMeasureMode heightMode) + { + var node = Native.YGNodeHandle.GetManaged(ygNodePtr); + return node.MeasureInternal(IntPtr.Zero, width, widthMode, height, heightMode); + } +#endif + private YogaSize MeasureInternal( IntPtr node, float width, @@ -580,6 +626,18 @@ namespace Facebook.Yoga return _measureFunction(this, width, widthMode, height, heightMode); } +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + [MonoPInvokeCallback(typeof(YogaBaselineFunc))] + private static float BaselineInternalIOS( + IntPtr ygNodePtr, + float width, + float height) + { + var node = Native.YGNodeHandle.GetManaged(ygNodePtr); + return node.BaselineInternal(IntPtr.Zero, width, height); + } +#endif + private float BaselineInternal(IntPtr node, float width, float height) { if (_baselineFunction == null) diff --git a/csharp/tests/Facebook.Yoga/YogaNodeTest.cs b/csharp/tests/Facebook.Yoga/YogaNodeTest.cs index 291fb4af..ac505845 100644 --- a/csharp/tests/Facebook.Yoga/YogaNodeTest.cs +++ b/csharp/tests/Facebook.Yoga/YogaNodeTest.cs @@ -365,6 +365,7 @@ namespace Facebook.Yoga child = null; } +#if !__IOS__ [Test] public void TestParentDestructor() { @@ -386,6 +387,7 @@ namespace Facebook.Yoga Assert.AreEqual(instanceCount + 1, YogaNode.GetInstanceCount()); parent.Insert(0, child); } +#endif [Test] public void TestClearWithChildDestructor()