Added C# binding for SKData.Create without copy

This commit is contained in:
Matthew Leibowitz 2017-02-24 11:05:54 +02:00
Родитель 69130e70b5
Коммит 5905fac6d9
4 изменённых файлов: 72 добавлений и 1 удалений

Просмотреть файл

@ -14,10 +14,26 @@ using System.Text;
namespace SkiaSharp
{
// public delegates
public delegate void SKDataReleaseDelegate (IntPtr address, object context);
// internal proxy delegates
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
internal delegate void SKDataReleaseDelegateInternal (IntPtr address, IntPtr context);
public class SKData : SKObject
{
private const int CopyBufferSize = 8192;
// so the GC doesn't collect the delegate
private static readonly SKDataReleaseDelegateInternal releaseDelegateInternal;
private static readonly IntPtr releaseDelegate;
static SKData ()
{
releaseDelegateInternal = new SKDataReleaseDelegateInternal (ReleaseInternal);
releaseDelegate = Marshal.GetFunctionPointerForDelegate (releaseDelegateInternal);
}
protected override void Dispose (bool disposing)
{
if (Handle != IntPtr.Zero && OwnsHandle) {
@ -65,6 +81,26 @@ namespace SkiaSharp
}
}
public static SKData Create (IntPtr address, int length)
{
return Create (address, length, null, null);
}
public static SKData Create (IntPtr address, int length, SKDataReleaseDelegate releaseProc)
{
return Create (address, length, releaseProc, null);
}
public static SKData Create (IntPtr address, int length, SKDataReleaseDelegate releaseProc, object context)
{
if (releaseProc == null) {
return GetObject<SKData> (SkiaApi.sk_data_new_with_proc (address, (IntPtr) length, IntPtr.Zero, IntPtr.Zero));
} else {
var ctx = new NativeDelegateContext (context, releaseProc);
return GetObject<SKData> (SkiaApi.sk_data_new_with_proc (address, (IntPtr) length, releaseDelegate, ctx.NativeContext));
}
}
public static SKData FromMallocMemory (IntPtr bytes, ulong length)
{
if (SizeOf <IntPtr> () == 4 && length > UInt32.MaxValue)
@ -135,6 +171,17 @@ namespace SkiaSharp
}
}
// internal proxy
#if __IOS__
[ObjCRuntime.MonoPInvokeCallback (typeof (SKDataReleaseDelegateInternal))]
#endif
private static void ReleaseInternal (IntPtr address, IntPtr context)
{
using (var ctx = NativeDelegateContext.Unwrap (context)) {
ctx.GetDelegate<SKDataReleaseDelegate> () (address, ctx.ManagedContext);
}
}
private class SKDataStream : UnmanagedMemoryStream
{
private SKData host;

Просмотреть файл

@ -810,6 +810,9 @@ namespace SkiaSharp
public extern static sk_data_t sk_data_new_from_file(string path);
[DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)]
public extern static sk_data_t sk_data_new_from_stream(sk_stream_t stream, IntPtr length);
[DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)]
public extern static sk_data_t sk_data_new_with_proc(IntPtr ptr, IntPtr length, IntPtr proc, IntPtr ctx);
[DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)]
public extern static void sk_data_unref(sk_data_t d);
[DllImport(SKIA, CallingConvention = CallingConvention.Cdecl)]

2
externals/skia поставляемый

@ -1 +1 @@
Subproject commit 379184f0ab1dfc9f2364043b70c5f65b9a3bc084
Subproject commit 009e372b71021c6bbe5a05ec96843b2c2d554507

Просмотреть файл

@ -17,6 +17,27 @@ namespace SkiaSharp.Tests
Assert.AreEqual(OddData, data.ToArray());
}
[Test]
public void ReleaseDataWasInvoked()
{
bool released = false;
var onRelease = new SKDataReleaseDelegate((addr, ctx) => {
Marshal.FreeCoTaskMem(addr);
released = true;
Assert.AreEqual("RELEASING!", ctx);
});
var memory = Marshal.AllocCoTaskMem(10);
using (var data = SKData.Create(memory, 10, onRelease, "RELEASING!")) {
Assert.AreEqual(memory, data.Data);
Assert.AreEqual(10, data.Size);
}
Assert.True(released, "The SKDataReleaseDelegate was not called.");
}
[Test]
[Ignore("Doesn't work as it relies on memory being overwritten by an external process.")]
public void DataDisposedReturnsInvalidStream()