246 строки
8.3 KiB
C#
246 строки
8.3 KiB
C#
//
|
|
// SKAbstractManagedStream
|
|
//
|
|
// Author:
|
|
// Matthew Leibowitz
|
|
//
|
|
// Copyright 2017 Xamarin Inc
|
|
//
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
|
|
using NativePointerDictionary = System.Collections.Concurrent.ConcurrentDictionary<System.IntPtr, SkiaSharp.SKAbstractManagedStream>;
|
|
|
|
namespace SkiaSharp
|
|
{
|
|
public abstract class SKAbstractManagedStream : SKStreamAsset
|
|
{
|
|
private static readonly NativePointerDictionary managedStreams = new NativePointerDictionary ();
|
|
|
|
// delegate declarations
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate IntPtr read_delegate (IntPtr managedStreamPtr, IntPtr buffer, IntPtr size);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate IntPtr peek_delegate (IntPtr managedStreamPtr, IntPtr buffer, IntPtr size);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate bool isAtEnd_delegate (IntPtr managedStreamPtr);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate bool hasPosition_delegate (IntPtr managedStreamPtr);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate bool hasLength_delegate (IntPtr managedStreamPtr);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate bool rewind_delegate (IntPtr managedStreamPtr);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate IntPtr getPosition_delegate (IntPtr managedStreamPtr);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate bool seek_delegate (IntPtr managedStreamPtr, IntPtr position);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate bool move_delegate (IntPtr managedStreamPtr, int offset);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate IntPtr getLength_delegate (IntPtr managedStreamPtr);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate IntPtr createNew_delegate (IntPtr managedStreamPtr);
|
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
|
internal delegate void destroy_delegate (IntPtr managedStreamPtr);
|
|
|
|
// delegate fields
|
|
private static readonly read_delegate fRead;
|
|
private static readonly peek_delegate fPeek;
|
|
private static readonly isAtEnd_delegate fIsAtEnd;
|
|
private static readonly hasPosition_delegate fHasPosition;
|
|
private static readonly hasLength_delegate fHasLength;
|
|
private static readonly rewind_delegate fRewind;
|
|
private static readonly getPosition_delegate fGetPosition;
|
|
private static readonly seek_delegate fSeek;
|
|
private static readonly move_delegate fMove;
|
|
private static readonly getLength_delegate fGetLength;
|
|
private static readonly createNew_delegate fCreateNew;
|
|
private static readonly destroy_delegate fDestroy;
|
|
|
|
private int fromNative;
|
|
|
|
static SKAbstractManagedStream ()
|
|
{
|
|
fRead = new read_delegate (ReadInternal);
|
|
fPeek = new peek_delegate (PeekInternal);
|
|
fIsAtEnd = new isAtEnd_delegate (IsAtEndInternal);
|
|
fHasPosition = new hasPosition_delegate (HasPositionInternal);
|
|
fHasLength = new hasLength_delegate (HasLengthInternal);
|
|
fRewind = new rewind_delegate (RewindInternal);
|
|
fGetPosition = new getPosition_delegate (GetPositionInternal);
|
|
fSeek = new seek_delegate (SeekInternal);
|
|
fMove = new move_delegate (MoveInternal);
|
|
fGetLength = new getLength_delegate (GetLengthInternal);
|
|
fCreateNew = new createNew_delegate (CreateNewInternal);
|
|
fDestroy = new destroy_delegate (DestroyInternal);
|
|
|
|
SkiaApi.sk_managedstream_set_delegates (
|
|
Marshal.GetFunctionPointerForDelegate (fRead),
|
|
Marshal.GetFunctionPointerForDelegate (fPeek),
|
|
Marshal.GetFunctionPointerForDelegate (fIsAtEnd),
|
|
Marshal.GetFunctionPointerForDelegate (fHasPosition),
|
|
Marshal.GetFunctionPointerForDelegate (fHasLength),
|
|
Marshal.GetFunctionPointerForDelegate (fRewind),
|
|
Marshal.GetFunctionPointerForDelegate (fGetPosition),
|
|
Marshal.GetFunctionPointerForDelegate (fSeek),
|
|
Marshal.GetFunctionPointerForDelegate (fMove),
|
|
Marshal.GetFunctionPointerForDelegate (fGetLength),
|
|
Marshal.GetFunctionPointerForDelegate (fCreateNew),
|
|
Marshal.GetFunctionPointerForDelegate (fDestroy));
|
|
}
|
|
|
|
protected SKAbstractManagedStream ()
|
|
: this (true)
|
|
{
|
|
}
|
|
|
|
protected SKAbstractManagedStream (bool owns)
|
|
: base (SkiaApi.sk_managedstream_new (), owns)
|
|
{
|
|
if (Handle == IntPtr.Zero) {
|
|
throw new InvalidOperationException ("Unable to create a new SKAbstractManagedStream instance.");
|
|
}
|
|
|
|
managedStreams.TryAdd (Handle, this);
|
|
}
|
|
|
|
private void DisposeFromNative ()
|
|
{
|
|
Interlocked.Exchange (ref fromNative, 1);
|
|
Dispose ();
|
|
}
|
|
|
|
protected override void Dispose (bool disposing)
|
|
{
|
|
if (disposing) {
|
|
SKAbstractManagedStream managedStream;
|
|
managedStreams.TryRemove (Handle, out managedStream);
|
|
}
|
|
|
|
if (Interlocked.CompareExchange (ref fromNative, 0, 0) == 0 && Handle != IntPtr.Zero && OwnsHandle) {
|
|
SkiaApi.sk_managedstream_destroy (Handle);
|
|
}
|
|
|
|
base.Dispose (disposing);
|
|
}
|
|
|
|
protected abstract IntPtr OnRead (IntPtr buffer, IntPtr size);
|
|
|
|
protected abstract IntPtr OnPeek (IntPtr buffer, IntPtr size);
|
|
|
|
protected abstract bool OnIsAtEnd ();
|
|
|
|
protected abstract bool OnHasPosition ();
|
|
|
|
protected abstract bool OnHasLength ();
|
|
|
|
protected abstract bool OnRewind ();
|
|
|
|
protected abstract IntPtr OnGetPosition ();
|
|
|
|
protected abstract IntPtr OnGetLength ();
|
|
|
|
protected abstract bool OnSeek (IntPtr position);
|
|
|
|
protected abstract bool OnMove (int offset);
|
|
|
|
protected abstract IntPtr OnCreateNew ();
|
|
|
|
// unmanaged <-> managed methods (static for iOS)
|
|
|
|
[MonoPInvokeCallback (typeof (read_delegate))]
|
|
private static IntPtr ReadInternal (IntPtr managedStreamPtr, IntPtr buffer, IntPtr size)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnRead (buffer, size);
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(peek_delegate))]
|
|
private static IntPtr PeekInternal (IntPtr managedStreamPtr, IntPtr buffer, IntPtr size)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnPeek (buffer, size);
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(isAtEnd_delegate))]
|
|
private static bool IsAtEndInternal (IntPtr managedStreamPtr)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnIsAtEnd ();
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(hasPosition_delegate))]
|
|
private static bool HasPositionInternal (IntPtr managedStreamPtr)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnHasPosition ();
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(hasLength_delegate))]
|
|
private static bool HasLengthInternal (IntPtr managedStreamPtr)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnHasLength ();
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(rewind_delegate))]
|
|
private static bool RewindInternal (IntPtr managedStreamPtr)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnRewind ();
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(getPosition_delegate))]
|
|
private static IntPtr GetPositionInternal (IntPtr managedStreamPtr)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnGetPosition ();
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(seek_delegate))]
|
|
private static bool SeekInternal (IntPtr managedStreamPtr, IntPtr position)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnSeek (position);
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(move_delegate))]
|
|
private static bool MoveInternal (IntPtr managedStreamPtr, int offset)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnMove (offset);
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(getLength_delegate))]
|
|
private static IntPtr GetLengthInternal (IntPtr managedStreamPtr)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnGetLength ();
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(createNew_delegate))]
|
|
private static IntPtr CreateNewInternal (IntPtr managedStreamPtr)
|
|
{
|
|
return AsManagedStream (managedStreamPtr).OnCreateNew ();
|
|
}
|
|
|
|
[MonoPInvokeCallback(typeof(destroy_delegate))]
|
|
private static void DestroyInternal (IntPtr managedStreamPtr)
|
|
{
|
|
SKAbstractManagedStream managedStream;
|
|
if (AsManagedStream (managedStreamPtr, out managedStream)) {
|
|
managedStream.DisposeFromNative ();
|
|
}
|
|
}
|
|
|
|
private static SKAbstractManagedStream AsManagedStream (IntPtr ptr)
|
|
{
|
|
SKAbstractManagedStream target;
|
|
if (AsManagedStream (ptr, out target)) {
|
|
return target;
|
|
}
|
|
throw new ObjectDisposedException ("SKAbstractManagedStream: " + ptr);
|
|
}
|
|
|
|
private static bool AsManagedStream (IntPtr ptr, out SKAbstractManagedStream target)
|
|
{
|
|
if (managedStreams.TryGetValue (ptr, out target)) {
|
|
return true;
|
|
}
|
|
target = null;
|
|
return false;
|
|
}
|
|
}
|
|
}
|