diff --git a/csharp/Facebook.Yoga/Native.cs b/csharp/Facebook.Yoga/Native.cs index 2c0d25ac..5b81b013 100644 --- a/csharp/Facebook.Yoga/Native.cs +++ b/csharp/Facebook.Yoga/Native.cs @@ -58,6 +58,14 @@ namespace Facebook.Yoga [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern int YGNodeGetInstanceCount(); +#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(YGNodeHandle node, IntPtr managed); +#endif + [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] public static extern void YGSetExperimentalFeatureEnabled( YogaExperimentalFeature feature, @@ -68,16 +76,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 +117,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)] diff --git a/csharp/Facebook.Yoga/YogaLogger.cs b/csharp/Facebook.Yoga/YogaLogger.cs index e5d79b79..bd3af941 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,30 @@ namespace Facebook.Yoga public delegate void Func(YogaLogLevel level, string message); private static bool _initialized; - private static Func _managedLogger = null; 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..2ae2b54f 100644 --- a/csharp/Facebook.Yoga/YogaNode.cs +++ b/csharp/Facebook.Yoga/YogaNode.cs @@ -12,6 +12,11 @@ using System.Collections; using System.Collections.Generic; using System.Text; +#if __IOS__ +using System.Runtime.InteropServices; +using ObjCRuntime; +#endif + namespace Facebook.Yoga { public partial class YogaNode : IEnumerable @@ -20,10 +25,11 @@ 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 GCHandle _managed; +#endif public YogaNode() { @@ -542,18 +548,58 @@ namespace Facebook.Yoga return _children != null ? _children.IndexOf(node) : -1; } +#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__ + private void SetContext() + { + if (!_managed.IsAllocated) + { + _managed = GCHandle.Alloc(this, GCHandleType.Weak); + Native.YGNodeSetContext(_ygNode, GCHandle.ToIntPtr(_managed)); + } + } + + private 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 + 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__ + SetContext(); + func = MeasureInternalIOS; +#else + 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__ + SetContext(); + func = BaselineInternalIOS; +#else + func = BaselineInternal; +#endif + } + Native.YGNodeSetBaselineFunc(_ygNode, func); } public void CalculateLayout() @@ -565,6 +611,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 = GetManaged(ygNodePtr); + return node.MeasureInternal(IntPtr.Zero, width, widthMode, height, heightMode); + } +#endif + private YogaSize MeasureInternal( IntPtr node, float width, @@ -572,6 +632,7 @@ namespace Facebook.Yoga float height, YogaMeasureMode heightMode) { + if (_measureFunction == null) { throw new InvalidOperationException("Measure function is not defined."); @@ -580,6 +641,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 = GetManaged(ygNodePtr); + return node.BaselineInternal(IntPtr.Zero, width, height); + } +#endif + private float BaselineInternal(IntPtr node, float width, float height) { if (_baselineFunction == null)