Skip to content

Commit

Permalink
[.NET/CoreGraphics] Use [UnmanagedCallersOnly] instead of [MonoPInvok…
Browse files Browse the repository at this point in the history
…eCallback] Partial Fix for #10470 (#15906)

Completed the work for CoreGraphics.
One exception is PDFArray.cs which uses `SetupBlockUnsafe` (noted in the
issue)

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>
  • Loading branch information
stephen-hawley and mandel-macaque committed Sep 12, 2022
1 parent 1552a1e commit 2a37989
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 3 deletions.
37 changes: 37 additions & 0 deletions src/CoreGraphics/CGDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,29 +144,48 @@ public CGDataProvider (NSData data)
{
}

#if NET
[DllImport (Constants.CoreGraphicsLibrary)]
extern static unsafe IntPtr CGDataProviderCreateWithData (/* void* */ IntPtr info, /* const void* */ IntPtr data, /* size_t */ nint size, /* CGDataProviderReleaseDataCallback */ delegate* unmanaged<IntPtr, IntPtr, nint, void> releaseData);
#else
[DllImport (Constants.CoreGraphicsLibrary)]
extern static IntPtr CGDataProviderCreateWithData (/* void* */ IntPtr info, /* const void* */ IntPtr data, /* size_t */ nint size, /* CGDataProviderReleaseDataCallback */ CGDataProviderReleaseDataCallback releaseData);
#endif

#if !NET
delegate void CGDataProviderReleaseDataCallback (IntPtr info, IntPtr data, nint size);
static CGDataProviderReleaseDataCallback release_gchandle_callback = ReleaseGCHandle;
static CGDataProviderReleaseDataCallback release_buffer_callback = ReleaseBuffer;
static CGDataProviderReleaseDataCallback release_func_callback = ReleaseFunc;
#endif

#if NET
[UnmanagedCallersOnly]
#else
[MonoPInvokeCallback (typeof (CGDataProviderReleaseDataCallback))]
#endif
private static void ReleaseGCHandle (IntPtr info, IntPtr data, nint size)
{
var gch = GCHandle.FromIntPtr (info);
gch.Free ();
}

#if NET
[UnmanagedCallersOnly]
#else
[MonoPInvokeCallback (typeof (CGDataProviderReleaseDataCallback))]
#endif
private static void ReleaseBuffer (IntPtr info, IntPtr data, nint size)
{
if (data != IntPtr.Zero)
Marshal.FreeHGlobal (data);
}

#if NET
[UnmanagedCallersOnly]
#else
[MonoPInvokeCallback (typeof (CGDataProviderReleaseDataCallback))]
#endif
private static void ReleaseFunc (IntPtr info, IntPtr data, nint size)
{
var gch = GCHandle.FromIntPtr (info);
Expand All @@ -188,7 +207,13 @@ static IntPtr Create (IntPtr memoryBlock, int size, bool ownBuffer)
{
if (!ownBuffer)
memoryBlock = Runtime.CloneMemory (memoryBlock, size);
#if NET
unsafe {
return CGDataProviderCreateWithData (IntPtr.Zero, memoryBlock, size, &ReleaseBuffer);
}
#else
return CGDataProviderCreateWithData (IntPtr.Zero, memoryBlock, size, release_buffer_callback);
#endif
}

public CGDataProvider (IntPtr memoryBlock, int size, bool ownBuffer)
Expand All @@ -202,7 +227,13 @@ static IntPtr Create (IntPtr memoryBlock, int size, Action<IntPtr> releaseMemory
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (releaseMemoryBlockCallback));

var gch = GCHandle.Alloc (releaseMemoryBlockCallback);
#if NET
unsafe {
return CGDataProviderCreateWithData (GCHandle.ToIntPtr (gch), memoryBlock, size, &ReleaseFunc);
}
#else
return CGDataProviderCreateWithData (GCHandle.ToIntPtr (gch), memoryBlock, size, release_func_callback);
#endif
}

public CGDataProvider (IntPtr memoryBlock, int size, Action<IntPtr> releaseMemoryBlockCallback)
Expand All @@ -221,7 +252,13 @@ static IntPtr Create (byte [] buffer, int offset, int count)

var gch = GCHandle.Alloc (buffer, GCHandleType.Pinned); // This requires a pinned GCHandle, because unsafe code is scoped to the current block, and the address of the byte array will be used after this function returns.
var ptr = gch.AddrOfPinnedObject () + offset;
#if NET
unsafe {
return CGDataProviderCreateWithData (GCHandle.ToIntPtr (gch), ptr, count, &ReleaseGCHandle);
}
#else
return CGDataProviderCreateWithData (GCHandle.ToIntPtr (gch), ptr, count, release_gchandle_callback);
#endif
}

public CGDataProvider (byte [] buffer, int offset, int count)
Expand Down
21 changes: 19 additions & 2 deletions src/CoreGraphics/CGFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,13 @@ public class CGFunction : NativeObject {
unsafe static CGFunction ()
{
cbacks.version = 0;
#if NET
cbacks.evaluate = &EvaluateCallback;
cbacks.release = &ReleaseCallback;
#else
cbacks.evaluate = new CGFunctionEvaluateCallback (EvaluateCallback);
cbacks.release = new CGFunctionReleaseCallback (ReleaseCallback);
#endif
}

#if !NET
Expand Down Expand Up @@ -103,12 +108,17 @@ protected internal override void Release ()
// Apple's documentation says 'float', the header files say 'CGFloat'
unsafe delegate void CGFunctionEvaluateCallback (/* void* */ IntPtr info, /* CGFloat* */ nfloat *data, /* CGFloat* */ nfloat *outData);
delegate void CGFunctionReleaseCallback (IntPtr info);

[StructLayout (LayoutKind.Sequential)]
struct CGFunctionCallbacks {
public /* unsigned int */ uint version;
#if NET
public unsafe delegate* unmanaged<IntPtr, nfloat*, nfloat*, void> evaluate;
public unsafe delegate* unmanaged<IntPtr, void> release;
#else
public CGFunctionEvaluateCallback? evaluate;
public CGFunctionReleaseCallback? release;
#endif
}

[DllImport (Constants.CoreGraphicsLibrary)]
Expand Down Expand Up @@ -136,17 +146,24 @@ public unsafe CGFunction (nfloat []? domain, nfloat []? range, CGFunctionEvaluat
var handle = CGFunctionCreate (GCHandle.ToIntPtr (gch), domain is not null ? domain.Length / 2 : 0, domain, range is not null ? range.Length / 2 : 0, range, ref cbacks);
InitializeHandle (handle);
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (CGFunctionReleaseCallback))]
#endif
#endif
static void ReleaseCallback (IntPtr info)
{
GCHandle.FromIntPtr (info).Free ();
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (CGFunctionEvaluateCallback))]
#endif
#endif
unsafe static void EvaluateCallback (IntPtr info, nfloat *input, nfloat *output)
{
Expand Down
15 changes: 14 additions & 1 deletion src/CoreGraphics/CGPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -478,9 +478,12 @@ public unsafe bool ContainsPoint (CGPoint point, bool eoFill)
public delegate void ApplierFunction (CGPathElement element);

delegate void CGPathApplierFunction (/* void* */ IntPtr info, /* const CGPathElement* */ IntPtr element);

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (CGPathApplierFunction))]
#endif
#endif
static void ApplierCallback (IntPtr info, IntPtr element_ptr)
{
Expand Down Expand Up @@ -520,12 +523,22 @@ static void ApplierCallback (IntPtr info, IntPtr element_ptr)


[DllImport (Constants.CoreGraphicsLibrary)]
#if NET
extern unsafe static void CGPathApply (/* CGPathRef */ IntPtr path, /* void* */ IntPtr info, delegate* unmanaged<IntPtr, IntPtr, void> function);
#else
extern static void CGPathApply (/* CGPathRef */ IntPtr path, /* void* */ IntPtr info, CGPathApplierFunction function);
#endif

public void Apply (ApplierFunction func)
{
GCHandle gch = GCHandle.Alloc (func);
#if NET
unsafe {
CGPathApply (Handle, GCHandle.ToIntPtr (gch), &ApplierCallback);
}
#else
CGPathApply (Handle, GCHandle.ToIntPtr (gch), ApplierCallback);
#endif
gch.Free ();
}

Expand Down
27 changes: 27 additions & 0 deletions src/CoreGraphics/CGPattern.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,13 @@ public enum CGPatternTiling {
[StructLayout (LayoutKind.Sequential)]
struct CGPatternCallbacks {
internal /* unsigned int */ uint version;
#if NET
internal unsafe delegate* unmanaged<IntPtr, IntPtr, void> draw;
internal unsafe delegate* unmanaged<IntPtr, void> release;
#else
internal DrawPatternCallback draw;
internal ReleaseInfoCallback release;
#endif
}


Expand Down Expand Up @@ -95,11 +100,25 @@ internal CGPattern (NativeHandle handle, bool owns)
/* CGFloat */ nfloat xStep, /* CGFloat */ nfloat yStep, CGPatternTiling tiling, [MarshalAs (UnmanagedType.I1)] bool isColored,
/* const CGPatternCallbacks* */ ref CGPatternCallbacks callbacks);

#if NET
static CGPatternCallbacks callbacks;

static CGPattern () {
unsafe {
callbacks = new CGPatternCallbacks () {
version = 0,
draw = &DrawCallback,
release = &ReleaseCallback,
};
}
}
#else
static CGPatternCallbacks callbacks = new CGPatternCallbacks () {
version = 0,
draw = DrawCallback,
release = ReleaseCallback,
};
#endif
GCHandle gch;

public CGPattern (CGRect bounds, CGAffineTransform matrix, nfloat xStep, nfloat yStep, CGPatternTiling tiling, bool isColored, DrawPattern drawPattern)
Expand All @@ -111,8 +130,12 @@ public CGPattern (CGRect bounds, CGAffineTransform matrix, nfloat xStep, nfloat
Handle = CGPatternCreate (GCHandle.ToIntPtr (gch), bounds, matrix, xStep, yStep, tiling, isColored, ref callbacks);
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (DrawPatternCallback))]
#endif
#endif
static void DrawCallback (IntPtr voidptr, IntPtr cgcontextptr)
{
Expand All @@ -123,8 +146,12 @@ static void DrawCallback (IntPtr voidptr, IntPtr cgcontextptr)
}
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (ReleaseInfoCallback))]
#endif
#endif
static void ReleaseCallback (IntPtr voidptr)
{
Expand Down

5 comments on commit 2a37989

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

Please sign in to comment.