From f90633cec59e07de19344e5f51a4ea9ecda957c9 Mon Sep 17 00:00:00 2001 From: Rui Marinho Date: Fri, 10 Feb 2017 15:45:15 +0000 Subject: [PATCH] [csharp] Implement static methods for callbacks so they work on aot on iOS, use YogaRef to store pointer to managed YogaNode --- csharp/Facebook.Yoga/Native.cs | 7 +++++ csharp/Facebook.Yoga/YogaLogger.cs | 22 +++++++++++++++ csharp/Facebook.Yoga/YogaNode.cs | 45 ++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/csharp/Facebook.Yoga/Native.cs b/csharp/Facebook.Yoga/Native.cs index 2c0d25ac..d00679bc 100644 --- a/csharp/Facebook.Yoga/Native.cs +++ b/csharp/Facebook.Yoga/Native.cs @@ -111,6 +111,13 @@ namespace Facebook.Yoga [return: MarshalAs(UnmanagedType.I1)] 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 #region YG_NODE_STYLE_PROPERTY diff --git a/csharp/Facebook.Yoga/YogaLogger.cs b/csharp/Facebook.Yoga/YogaLogger.cs index e5d79b79..52731af7 100644 --- a/csharp/Facebook.Yoga/YogaLogger.cs +++ b/csharp/Facebook.Yoga/YogaLogger.cs @@ -37,9 +37,31 @@ namespace Facebook.Yoga throw new InvalidOperationException(message); } }; +#if __IOS__ + Native.YGInteropSetLogger(ManagedLogger); +#else Native.YGInteropSetLogger(_managedLogger); +#endif _initialized = true; } } + +#if __IOS__ + delegate void ManagedLoggerCallback(YogaLogLevel level, string message); + + [ObjCRuntime.MonoPInvokeCallback(typeof(ManagedLoggerCallback))] + public static void ManagedLogger(YogaLogLevel level, string message) + { + if (Logger != null) + { + Logger(level, message); + } + + if (level == YogaLogLevel.Error) + { + throw new InvalidOperationException(message); + } + } +#endif } } diff --git a/csharp/Facebook.Yoga/YogaNode.cs b/csharp/Facebook.Yoga/YogaNode.cs index 59b6ae08..02d51c28 100644 --- a/csharp/Facebook.Yoga/YogaNode.cs +++ b/csharp/Facebook.Yoga/YogaNode.cs @@ -10,6 +10,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; namespace Facebook.Yoga @@ -532,7 +533,7 @@ namespace Facebook.Yoga { while (_children.Count > 0) { - RemoveAt(_children.Count-1); + RemoveAt(_children.Count - 1); } } } @@ -546,6 +547,10 @@ namespace Facebook.Yoga { _measureFunction = measureFunction; _ygMeasureFunc = measureFunction != null ? MeasureInternal : (YogaMeasureFunc)null; + + var handle = GCHandle.Alloc(this); + Native.YGNodeSetContext(_ygNode, GCHandle.ToIntPtr(handle)); + Native.YGNodeSetMeasureFunc(_ygNode, _ygMeasureFunc); } @@ -553,6 +558,10 @@ namespace Facebook.Yoga { _baselineFunction = baselineFunction; _ygBaselineFunc = baselineFunction != null ? BaselineInternal : (YogaBaselineFunc)null; + + var handle = GCHandle.Alloc(this); + Native.YGNodeSetContext(_ygNode, GCHandle.ToIntPtr(handle)); + Native.YGNodeSetBaselineFunc(_ygNode, _ygBaselineFunc); } @@ -565,37 +574,55 @@ namespace Facebook.Yoga Native.YGNodeStyleGetDirection(_ygNode)); } - private YogaSize MeasureInternal( +#if __IOS__ + [ObjCRuntime.MonoPInvokeCallback(typeof(YogaMeasureFunc))] +#endif + private static YogaSize MeasureInternal( IntPtr node, float width, YogaMeasureMode widthMode, float height, 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."); } - return _measureFunction(this, width, widthMode, height, heightMode); + return measureFunction(yogaNode, width, widthMode, height, heightMode); } - private float BaselineInternal(IntPtr node, float width, float height) + +#if __IOS__ + [ObjCRuntime.MonoPInvokeCallback(typeof(YogaBaselineFunc))] +#endif + private static float BaselineInternal(IntPtr node, float width, float height) { - if (_baselineFunction == null) + var yogaNodePointer = Native.YGNodeGetContext(node); + + YogaNode yogaNode = GCHandle.FromIntPtr(yogaNodePointer).Target as YogaNode; + + var baselineFunction = yogaNode._baselineFunction; + if (baselineFunction == null) { throw new InvalidOperationException("Baseline function is not defined."); } - return _baselineFunction(this, width, height); + return baselineFunction(yogaNode, width, height); } public string Print(YogaPrintOptions options = - YogaPrintOptions.Layout|YogaPrintOptions.Style|YogaPrintOptions.Children) + YogaPrintOptions.Layout | YogaPrintOptions.Style | YogaPrintOptions.Children) { StringBuilder sb = new StringBuilder(); YogaLogger.Func orig = YogaLogger.Logger; - YogaLogger.Logger = (level, message) => {sb.Append(message);}; + YogaLogger.Logger = (level, message) => { sb.Append(message); }; Native.YGNodePrint(_ygNode, options); YogaLogger.Logger = orig; return sb.ToString();