[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 a5b94ebd0c
commit 471d439654
7 changed files with 154 additions and 31 deletions

View File

@@ -58,6 +58,11 @@ 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 void YGNodeSetManaged(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,13 +73,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);
@@ -99,13 +108,29 @@ namespace Facebook.Yoga
YGNodeHandle node, YGNodeHandle node,
[MarshalAs(UnmanagedType.FunctionPtr)] YogaMeasureFunc measureFunc); [MarshalAs(UnmanagedType.FunctionPtr)] YogaMeasureFunc measureFunc);
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGInteropSetMeasureFunc(
YGNodeHandle node,
[MarshalAs(UnmanagedType.FunctionPtr)] YogaMeasureFunc measureFunc);
#endif
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] [DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
public static extern void YGNodeSetBaselineFunc( public static extern void YGNodeSetBaselineFunc(
YGNodeHandle node, YGNodeHandle node,
[MarshalAs(UnmanagedType.FunctionPtr)] YogaBaselineFunc baselineFunc); [MarshalAs(UnmanagedType.FunctionPtr)] YogaBaselineFunc baselineFunc);
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
[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 YGInteropSetBaselineFunc(
YGNodeHandle node,
[MarshalAs(UnmanagedType.FunctionPtr)] YogaBaselineFunc baselineFunc);
#endif
[DllImport(DllName, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
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,15 +22,14 @@ 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;
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 +39,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,10 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
#if __IOS__
using ObjCRuntime;
#endif
namespace Facebook.Yoga namespace Facebook.Yoga
{ {
public partial class YogaNode : IEnumerable<YogaNode> public partial class YogaNode : IEnumerable<YogaNode>
@@ -20,9 +24,7 @@ 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;
public YogaNode() public YogaNode()
@@ -34,6 +36,11 @@ namespace Facebook.Yoga
{ {
throw new InvalidOperationException("Failed to allocate native memory"); throw new InvalidOperationException("Failed to allocate native memory");
} }
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
var managed = GCHandle.Alloc(this, GCHandleType.Weak);
Native.YGNodeSetManaged(GCHandle.ToIntPtr(managed));
#endif
} }
public YogaNode(YogaNode srcNode) public YogaNode(YogaNode srcNode)
@@ -545,15 +552,23 @@ namespace Facebook.Yoga
public void SetMeasureFunction(MeasureFunction measureFunction) public void SetMeasureFunction(MeasureFunction measureFunction)
{ {
_measureFunction = measureFunction; _measureFunction = measureFunction;
_ygMeasureFunc = measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null; #if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
Native.YGNodeSetMeasureFunc(_ygNode, _ygMeasureFunc); Native.YGInteropNodeSetMeasureFunc(_ygNode, MeasureInternalIOS);
#else
Native.YGNodeSetMeasureFunc(_ygNode,
measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null);
#endif
} }
public void SetBaselineFunction(BaselineFunction baselineFunction) public void SetBaselineFunction(BaselineFunction baselineFunction)
{ {
_baselineFunction = baselineFunction; _baselineFunction = baselineFunction;
_ygBaselineFunc = baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null; #if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
Native.YGNodeSetBaselineFunc(_ygNode, _ygBaselineFunc); Native.YGInteropNodeSetBaselineFunc(_ygNode, BaselineInternalIOS);
#else
Native.YGNodeSetBaselineFunc(_ygNode,
baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null);
#endif
} }
public void CalculateLayout() public void CalculateLayout()
@@ -565,6 +580,25 @@ namespace Facebook.Yoga
Native.YGNodeStyleGetDirection(_ygNode)); Native.YGNodeStyleGetDirection(_ygNode));
} }
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
[MonoPInvokeCallback(typeof(YogaMeasureFunc))]
private static YogaSize MeasureInternalIOS(
IntPtr managed,
float width,
YogaMeasureMode widthMode,
float height,
YogaMeasureMode heightMode)
{
var node = GCHandle.FromIntPtr(managed);
if (node == null)
{
throw new InvalidOperationException("YogaNode is already deallocated");
}
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 +614,20 @@ 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 managed, float width, float height)
{
var node = GCHandle.FromIntPtr(managed);
if (node == null)
{
throw new InvalidOperationException("YogaNode is already deallocated");
}
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

@@ -9,19 +9,56 @@
#include "YGInterop.h" #include "YGInterop.h"
static YGInteropLoggerFunc gManagedFunc; typedef YGSize (*YGInteropMeasureFunc)(void *managed,
float width,
YGMeasureMode widthMode,
float height,
YGMeasureMode heightMode);
typedef float (*YGInteropBaselineFunc)(void *managed, const float width, const float height);
static int unmanagedLogger(YGLogLevel level, const char *format, va_list args) { static YGInteropLoggerFunc gManagedLoggerFunc;
static YGInteropMeasureFunc gManagedMeasureFunc;
static YGInteropBaselineFunc gManagedBaselineFunc;
static int unmanagedLoggerFunc(YGLogLevel level, const char *format, va_list args) {
int result = 0; int result = 0;
if (gManagedFunc) { if (gManagedLoggerFunc) {
char buffer[256]; char buffer[256];
result = vsnprintf(buffer, sizeof(buffer), format, args); result = vsnprintf(buffer, sizeof(buffer), format, args);
(*gManagedFunc)(level, buffer); (*gManagedLoggerFunc)(level, buffer);
} }
return result; return result;
} }
void YGInteropSetLogger(YGInteropLoggerFunc managedFunc) { void YGInteropSetLogger(YGInteropLoggerFunc managedFunc) {
gManagedFunc = managedFunc; gManagedLoggerFunc = managedFunc;
YGSetLogger(&unmanagedLogger); YGSetLogger(&unmanagedLoggerFunc);
}
static YGSize unmanagedMeasureFunc(YGNodeRef node,
float width,
YGMeasureMode widthMode,
float height,
YGMeasureMode heightMode) {
YG_ASSERT(gManagedMeasureFunc, "Expect to set managed measure function");
void *managed = YGNodeGetManaged(node);
YG_ASSERT(managed, "Expect to set managed in node");
return (*gManagedMeasureFunc)(managed, width, widthMode, height, heightMode);
}
void YGInteropNodeSetMeasureFunc(YGNodeRef node, YGInteropMeasureFunc managedFunc) {
gManagedMeasureFunc = managedFunc;
YGNodeSetMeasureFunc(node, &unmanagedMeasureFunc);
}
static float unmanagedBaselineFunc(YGNodeRef node, const float width, const float height) {
YG_ASSERT(gManagedBaselineFunc, "Expect to set managed baseline function");
void *managed = YGNodeGetManaged(node);
YG_ASSERT(managed, "Expect to set managed in node");
return (*gManagedBaselineFunc)(managed, width, height);
}
void YGInteropNodeSetBaselineFunc(YGNodeRef node, YGInteropBaselineFunc managedFunc) {
gManagedBaselineFunc = managedFunc;
YGNodeSetBaselineFunc(node, &unmanagedBaselineFunc);
} }

View File

@@ -16,5 +16,7 @@ YG_EXTERN_C_BEGIN
typedef void (*YGInteropLoggerFunc)(YGLogLevel level, const char *message); typedef void (*YGInteropLoggerFunc)(YGLogLevel level, const char *message);
WIN_EXPORT void YGInteropSetLogger(YGInteropLoggerFunc managedFunc); WIN_EXPORT void YGInteropSetLogger(YGInteropLoggerFunc managedFunc);
WIN_EXPORT void YGInteropNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc);
WIN_EXPORT void YGInteropNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc);
YG_EXTERN_C_END YG_EXTERN_C_END

View File

@@ -108,6 +108,7 @@ typedef struct YGNode {
YGBaselineFunc baseline; YGBaselineFunc baseline;
YGPrintFunc print; YGPrintFunc print;
void *context; void *context;
void *managed;
bool isDirty; bool isDirty;
bool hasNewLayout; bool hasNewLayout;
@@ -565,6 +566,7 @@ void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
} }
YG_NODE_PROPERTY_IMPL(void *, Context, context, context); YG_NODE_PROPERTY_IMPL(void *, Context, context, context);
YG_NODE_PROPERTY_IMPL(void *, Managed, managed, managed);
YG_NODE_PROPERTY_IMPL(YGPrintFunc, PrintFunc, printFunc, print); YG_NODE_PROPERTY_IMPL(YGPrintFunc, PrintFunc, printFunc, print);
YG_NODE_PROPERTY_IMPL(bool, HasNewLayout, hasNewLayout, hasNewLayout); YG_NODE_PROPERTY_IMPL(bool, HasNewLayout, hasNewLayout, hasNewLayout);

View File

@@ -143,6 +143,7 @@ WIN_EXPORT void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode
WIN_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge); WIN_EXPORT type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge);
YG_NODE_PROPERTY(void *, Context, context); YG_NODE_PROPERTY(void *, Context, context);
YG_NODE_PROPERTY(void *, Managed, managed);
YG_NODE_PROPERTY(YGMeasureFunc, MeasureFunc, measureFunc); YG_NODE_PROPERTY(YGMeasureFunc, MeasureFunc, measureFunc);
YG_NODE_PROPERTY(YGBaselineFunc, BaselineFunc, baselineFunc) YG_NODE_PROPERTY(YGBaselineFunc, BaselineFunc, baselineFunc)
YG_NODE_PROPERTY(YGPrintFunc, PrintFunc, printFunc); YG_NODE_PROPERTY(YGPrintFunc, PrintFunc, printFunc);