using CPF.Mac.Foundation; using CPF.Mac.ObjCRuntime; using System; using System.Runtime.InteropServices; namespace CPF.Mac.CoreGraphics { public class CGFunction : INativeObject, IDisposable { private unsafe delegate void CGFunctionEvaluateCallback(IntPtr info, double* data, double* outData); private struct CGFunctionCallbacks { public uint version; public CGFunctionEvaluateCallback evaluate; public IntPtr release; } public unsafe delegate void CGFunctionEvaluate(double* data, double* outData); internal IntPtr handle; private GCHandle gch; private CGFunctionEvaluate evaluate; public IntPtr Handle => handle; internal CGFunction(IntPtr handle) : this(handle, owns: false) { this.handle = handle; } [Preserve(Conditional = true)] internal CGFunction(IntPtr handle, bool owns) { this.handle = handle; if (!owns) { CGFunctionRetain(handle); } } ~CGFunction() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } [DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")] private static extern void CGFunctionRelease(IntPtr handle); [DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")] private static extern void CGFunctionRetain(IntPtr handle); protected unsafe virtual void Dispose(bool disposing) { if (handle != IntPtr.Zero) { CGFunctionRelease(handle); handle = IntPtr.Zero; gch.Free(); evaluate = null; } } [DllImport("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/CoreGraphics.framework/CoreGraphics")] private static extern IntPtr CGFunctionCreate(IntPtr data, IntPtr domainCount, double[] domain, IntPtr rangeDomain, double[] range, ref CGFunctionCallbacks callbacks); public unsafe CGFunction(double[] domain, double[] range, CGFunctionEvaluate callback) { if (domain != null && domain.Length % 2 != 0) { throw new ArgumentException("The domain array must consist of pairs of values", "domain"); } if (range != null && range.Length % 2 != 0) { throw new ArgumentException("The range array must consist of pairs of values", "range"); } if (callback == null) { throw new ArgumentNullException("callback"); } evaluate = callback; CGFunctionCallbacks callbacks = default(CGFunctionCallbacks); callbacks.version = 0u; callbacks.evaluate = EvaluateCallback; callbacks.release = IntPtr.Zero; gch = GCHandle.Alloc(this); handle = CGFunctionCreate(GCHandle.ToIntPtr(gch), (domain != null) ? new IntPtr(domain.Length / 2) : IntPtr.Zero, domain, (range != null) ? new IntPtr(range.Length / 2) : IntPtr.Zero, range, ref callbacks); } private unsafe static void EvaluateCallback(IntPtr info, double* input, double* output) { ((CGFunction)GCHandle.FromIntPtr(info).Target).evaluate(input, output); } } }