Fix callbacks on AOT

Summary:
Based on the idea of #386 by rmarinho
Closes https://github.com/facebook/yoga/pull/388

Reviewed By: emilsjolander

Differential Revision: D4570778

Pulled By: splhack

fbshipit-source-id: 362983deaf6f040c42b3db8205b711e7e5e60eaf
This commit is contained in:
Kazuki Sakamoto
2017-02-16 11:07:51 -08:00
committed by Facebook Github Bot
parent 8deed174f5
commit 4fe0b810e1
3 changed files with 139 additions and 65 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,16 +101,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,19 +142,14 @@ 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)]
public static extern bool YGNodeGetHasNewLayout(YGNodeHandle node); public static extern bool YGNodeGetHasNewLayout(YGNodeHandle node);
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGNodeSetContext(YGNodeHandle node, IntPtr context);
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr YGNodeGetContext(IntPtr node);
#endregion #endregion
#region YG_NODE_STYLE_PROPERTY #region YG_NODE_STYLE_PROPERTY
@@ -347,5 +379,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

@@ -8,29 +8,26 @@
*/ */
using System; using System;
using System.Runtime.InteropServices;
#if __IOS__
using ObjCRuntime;
#endif
namespace Facebook.Yoga namespace Facebook.Yoga
{ {
internal static class YogaLogger internal static class YogaLogger
{ {
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
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 = LoggerInternal;
public static Func Logger = null; public static Func Logger = null;
public static void Initialize() #if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
{ [MonoPInvokeCallback(typeof(Func))]
if (!_initialized)
{
Native.YGInteropSetLogger(LoggerInternal);
_initialized = true;
}
}
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(Func))]
#endif #endif
public static void LoggerInternal(YogaLogLevel level, string message) public static void LoggerInternal(YogaLogLevel level, string message)
{ {
@@ -45,5 +42,13 @@ namespace Facebook.Yoga
} }
} }
public static void Initialize()
{
if (!_initialized)
{
Native.YGInteropSetLogger(_managedLogger);
_initialized = true;
}
}
} }
} }

View File

@@ -10,9 +10,15 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
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>
@@ -21,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 _managedMeasure = MeasureInternalIOS;
private static YogaBaselineFunc _managedBaseline = BaselineInternalIOS;
#else
private YogaMeasureFunc _managedMeasure;
private YogaBaselineFunc _managedBaseline;
#endif
public YogaNode() public YogaNode()
{ {
@@ -545,7 +556,7 @@ namespace Facebook.Yoga
{ {
while (_children.Count > 0) while (_children.Count > 0)
{ {
RemoveAt(_children.Count - 1); RemoveAt(_children.Count-1);
} }
} }
} }
@@ -558,23 +569,29 @@ namespace Facebook.Yoga
public void SetMeasureFunction(MeasureFunction measureFunction) public void SetMeasureFunction(MeasureFunction measureFunction)
{ {
_measureFunction = measureFunction; _measureFunction = measureFunction;
_ygMeasureFunc = measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null; if (measureFunction != null)
{
var handle = GCHandle.Alloc(this); #if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
Native.YGNodeSetContext(_ygNode, GCHandle.ToIntPtr(handle)); _ygNode.SetContext(this);
#else
Native.YGNodeSetMeasureFunc(_ygNode, _ygMeasureFunc); _managedMeasure = MeasureInternal;
#endif
}
Native.YGNodeSetMeasureFunc(_ygNode, _managedMeasure);
} }
public void SetBaselineFunction(BaselineFunction baselineFunction) public void SetBaselineFunction(BaselineFunction baselineFunction)
{ {
_baselineFunction = baselineFunction; _baselineFunction = baselineFunction;
_ygBaselineFunc = baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null; if (baselineFunction != null)
{
var handle = GCHandle.Alloc(this); #if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
Native.YGNodeSetContext(_ygNode, GCHandle.ToIntPtr(handle)); _ygNode.SetContext(this);
#else
Native.YGNodeSetBaselineFunc(_ygNode, _ygBaselineFunc); _managedBaseline = BaselineInternal;
#endif
}
Native.YGNodeSetBaselineFunc(_ygNode, _managedBaseline);
} }
public void CalculateLayout() public void CalculateLayout()
@@ -586,55 +603,63 @@ namespace Facebook.Yoga
Native.YGNodeStyleGetDirection(_ygNode)); Native.YGNodeStyleGetDirection(_ygNode));
} }
#if __IOS__ #if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
[ObjCRuntime.MonoPInvokeCallback(typeof(YogaMeasureFunc))] [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 #endif
private static YogaSize MeasureInternal(
private YogaSize MeasureInternal(
IntPtr node, IntPtr node,
float width, float width,
YogaMeasureMode widthMode, YogaMeasureMode widthMode,
float height, float height,
YogaMeasureMode heightMode) YogaMeasureMode heightMode)
{ {
if (_measureFunction == null)
var yogaNodePointer = Native.YGNodeGetContext(node);
YogaNode yogaNode = GCHandle.FromIntPtr(yogaNodePointer).Target as YogaNode;
var measureFunction = yogaNode._measureFunction;
if (measureFunction == null)
{ {
throw new InvalidOperationException("Measure function is not defined."); throw new InvalidOperationException("Measure function is not defined.");
} }
return measureFunction(yogaNode, width, widthMode, height, heightMode); return _measureFunction(this, width, widthMode, height, heightMode);
} }
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
#if __IOS__ [MonoPInvokeCallback(typeof(YogaBaselineFunc))]
[ObjCRuntime.MonoPInvokeCallback(typeof(YogaBaselineFunc))] private static float BaselineInternalIOS(
#endif IntPtr ygNodePtr,
private static float BaselineInternal(IntPtr node, float width, float height) float width,
float height)
{ {
var yogaNodePointer = Native.YGNodeGetContext(node); var node = Native.YGNodeHandle.GetManaged(ygNodePtr);
return node.BaselineInternal(IntPtr.Zero, width, height);
}
#endif
YogaNode yogaNode = GCHandle.FromIntPtr(yogaNodePointer).Target as YogaNode; private float BaselineInternal(IntPtr node, float width, float height)
{
var baselineFunction = yogaNode._baselineFunction; if (_baselineFunction == null)
if (baselineFunction == null)
{ {
throw new InvalidOperationException("Baseline function is not defined."); throw new InvalidOperationException("Baseline function is not defined.");
} }
return baselineFunction(yogaNode, width, height); return _baselineFunction(this, width, height);
} }
public string Print(YogaPrintOptions options = public string Print(YogaPrintOptions options =
YogaPrintOptions.Layout | YogaPrintOptions.Style | YogaPrintOptions.Children) YogaPrintOptions.Layout|YogaPrintOptions.Style|YogaPrintOptions.Children)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
YogaLogger.Func orig = YogaLogger.Logger; YogaLogger.Func orig = YogaLogger.Logger;
YogaLogger.Logger = (level, message) => { sb.Append(message); }; YogaLogger.Logger = (level, message) => {sb.Append(message);};
Native.YGNodePrint(_ygNode, options); Native.YGNodePrint(_ygNode, options);
YogaLogger.Logger = orig; YogaLogger.Logger = orig;
return sb.ToString(); return sb.ToString();