[C#][iOS] Fix callbacks on AOT #388

Closed
splhack wants to merge 5 commits from aot into master
4 changed files with 145 additions and 25 deletions

View File

@@ -22,6 +22,10 @@ namespace Facebook.Yoga
internal class YGNodeHandle : SafeHandle internal class YGNodeHandle : SafeHandle
{ {
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
private GCHandle _managed;
#endif
private YGNodeHandle() : base(IntPtr.Zero, true) private YGNodeHandle() : base(IntPtr.Zero, true)
{ {
} }
@@ -36,10 +40,39 @@ namespace Facebook.Yoga
protected override bool ReleaseHandle() protected override bool ReleaseHandle()
{ {
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
if (_managed.IsAllocated)
{
_managed.Free();
}
#endif
Native.YGNodeFree(this.handle); Native.YGNodeFree(this.handle);
GC.KeepAlive(this); GC.KeepAlive(this);
return true; 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)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
@@ -68,13 +101,17 @@ namespace Facebook.Yoga
YogaExperimentalFeature feature); YogaExperimentalFeature feature);
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [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)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGNodeRemoveChild(YGNodeHandle node, YGNodeHandle child); public static extern void YGNodeRemoveChild(YGNodeHandle node, YGNodeHandle child);
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGNodeCalculateLayout(YGNodeHandle node, public static extern void YGNodeCalculateLayout(
YGNodeHandle node,
float availableWidth, float availableWidth,
float availableHeight, float availableHeight,
YogaDirection parentDirection); YogaDirection parentDirection);
@@ -105,7 +142,9 @@ namespace Facebook.Yoga
[MarshalAs(UnmanagedType.FunctionPtr)] YogaBaselineFunc baselineFunc); [MarshalAs(UnmanagedType.FunctionPtr)] YogaBaselineFunc baselineFunc);
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [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)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
@@ -328,5 +367,17 @@ namespace Facebook.Yoga
public static extern YogaDirection YGNodeLayoutGetDirection(YGNodeHandle node); public static extern YogaDirection YGNodeLayoutGetDirection(YGNodeHandle node);
#endregion #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
} }
} }

View File

@@ -10,6 +10,10 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#if __IOS__
using ObjCRuntime;
#endif
namespace Facebook.Yoga namespace Facebook.Yoga
{ {
internal static class YogaLogger internal static class YogaLogger
@@ -18,15 +22,15 @@ namespace Facebook.Yoga
public delegate void Func(YogaLogLevel level, string message); public delegate void Func(YogaLogLevel level, string message);
private static bool _initialized; private static bool _initialized;
private static Func _managedLogger = null;
public static Func _loggerInternal = LoggerInternal;
public static Func Logger = null; public static Func Logger = null;
public static void Initialize() #if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
[MonoPInvokeCallback(typeof(Func))]
#endif
public static void LoggerInternal(YogaLogLevel level, string message)
{ {
if (!_initialized)
{
_managedLogger = (level, message) => {
if (Logger != null) if (Logger != null)
{ {
Logger(level, message); Logger(level, message);
@@ -36,8 +40,13 @@ namespace Facebook.Yoga
{ {
throw new InvalidOperationException(message); throw new InvalidOperationException(message);
} }
}; }
Native.YGInteropSetLogger(_managedLogger);
public static void Initialize()
{
if (!_initialized)
{
Native.YGInteropSetLogger(_loggerInternal);
_initialized = true; _initialized = true;
} }
} }

View File

@@ -12,6 +12,13 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
using System.Runtime.InteropServices;
#endif
#if __IOS__
using ObjCRuntime;
#endif
namespace Facebook.Yoga namespace Facebook.Yoga
{ {
public partial class YogaNode : IEnumerable<YogaNode> public partial class YogaNode : IEnumerable<YogaNode>
@@ -20,10 +27,15 @@ namespace Facebook.Yoga
private WeakReference _parent; private WeakReference _parent;
private List<YogaNode> _children; private List<YogaNode> _children;
private MeasureFunction _measureFunction; private MeasureFunction _measureFunction;
private YogaMeasureFunc _ygMeasureFunc;
private BaselineFunction _baselineFunction; private BaselineFunction _baselineFunction;
private YogaBaselineFunc _ygBaselineFunc;
private object _data; 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() public YogaNode()
{ {
@@ -545,15 +557,35 @@ namespace Facebook.Yoga
public void SetMeasureFunction(MeasureFunction measureFunction) public void SetMeasureFunction(MeasureFunction measureFunction)
{ {
_measureFunction = measureFunction; _measureFunction = measureFunction;
_ygMeasureFunc = measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null; YogaMeasureFunc func = null;
Native.YGNodeSetMeasureFunc(_ygNode, _ygMeasureFunc); 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) public void SetBaselineFunction(BaselineFunction baselineFunction)
{ {
_baselineFunction = baselineFunction; _baselineFunction = baselineFunction;
_ygBaselineFunc = baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null; YogaBaselineFunc func = null;
Native.YGNodeSetBaselineFunc(_ygNode, _ygBaselineFunc); 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() public void CalculateLayout()
@@ -565,6 +597,20 @@ namespace Facebook.Yoga
Native.YGNodeStyleGetDirection(_ygNode)); 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( private YogaSize MeasureInternal(
IntPtr node, IntPtr node,
float width, float width,
@@ -580,6 +626,18 @@ namespace Facebook.Yoga
return _measureFunction(this, width, widthMode, height, heightMode); 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) private float BaselineInternal(IntPtr node, float width, float height)
{ {
if (_baselineFunction == null) if (_baselineFunction == null)

View File

@@ -365,6 +365,7 @@ namespace Facebook.Yoga
child = null; child = null;
} }
#if !__IOS__
[Test] [Test]
public void TestParentDestructor() public void TestParentDestructor()
{ {
@@ -386,6 +387,7 @@ namespace Facebook.Yoga
Assert.AreEqual(instanceCount + 1, YogaNode.GetInstanceCount()); Assert.AreEqual(instanceCount + 1, YogaNode.GetInstanceCount());
parent.Insert(0, child); parent.Insert(0, child);
} }
#endif
[Test] [Test]
public void TestClearWithChildDestructor() public void TestClearWithChildDestructor()