[C#][iOS] Fix callbacks on AOT

Based on the idea of #386
This commit is contained in:
Kazuki Sakamoto
2017-02-10 11:13:45 -08:00
parent 55fe6f0bc9
commit 376ab71bb0
3 changed files with 120 additions and 25 deletions

View File

@@ -58,6 +58,14 @@ namespace Facebook.Yoga
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int YGNodeGetInstanceCount(); 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)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGSetExperimentalFeatureEnabled( public static extern void YGSetExperimentalFeatureEnabled(
YogaExperimentalFeature feature, YogaExperimentalFeature feature,
@@ -68,16 +76,20 @@ 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(
float availableWidth, YGNodeHandle node,
float availableHeight, float availableWidth,
YogaDirection parentDirection); float availableHeight,
YogaDirection parentDirection);
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGNodeMarkDirty(YGNodeHandle node); public static extern void YGNodeMarkDirty(YGNodeHandle node);
@@ -105,7 +117,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)]

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,26 +22,30 @@ 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 Logger = 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() public static void Initialize()
{ {
if (!_initialized) if (!_initialized)
{ {
_managedLogger = (level, message) => { Native.YGInteropSetLogger(LoggerInternal);
if (Logger != null)
{
Logger(level, message);
}
if (level == YogaLogLevel.Error)
{
throw new InvalidOperationException(message);
}
};
Native.YGInteropSetLogger(_managedLogger);
_initialized = true; _initialized = true;
} }
} }

View File

@@ -12,6 +12,11 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
#if __IOS__
using System.Runtime.InteropServices;
using ObjCRuntime;
#endif
namespace Facebook.Yoga namespace Facebook.Yoga
{ {
public partial class YogaNode : IEnumerable<YogaNode> public partial class YogaNode : IEnumerable<YogaNode>
@@ -20,10 +25,11 @@ 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 GCHandle _managed;
#endif
public YogaNode() public YogaNode()
{ {
@@ -542,18 +548,58 @@ namespace Facebook.Yoga
return _children != null ? _children.IndexOf(node) : -1; 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) 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__
SetContext();
func = MeasureInternalIOS;
#else
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__
SetContext();
func = BaselineInternalIOS;
#else
func = BaselineInternal;
#endif
}
Native.YGNodeSetBaselineFunc(_ygNode, func);
} }
public void CalculateLayout() public void CalculateLayout()
@@ -565,6 +611,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 = 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,
@@ -572,6 +632,7 @@ namespace Facebook.Yoga
float height, float height,
YogaMeasureMode heightMode) YogaMeasureMode heightMode)
{ {
if (_measureFunction == null) if (_measureFunction == null)
{ {
throw new InvalidOperationException("Measure function is not defined."); throw new InvalidOperationException("Measure function is not defined.");
@@ -580,6 +641,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 = 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)