Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 30 additions & 69 deletions binding/SkiaSharp/SKManagedStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ public class SKManagedStream : SKAbstractManagedStream

private bool isAsEnd;
private bool disposeStream;
private bool wasCopied;

private WeakReference parent;
private WeakReference child;
// Lazily-created snapshot for duplicate/fork. Stored in native memory
// via SKData (ref-counted), so multiple duplicates share one native
// byte buffer with no additional managed byte-buffer allocations per duplicate.
private SKData snapshotData;

public SKManagedStream (Stream managedStream)
: this (managedStream, false)
Expand Down Expand Up @@ -56,28 +57,11 @@ protected override void Dispose (bool disposing) =>

protected override void DisposeManaged ()
{
var childStream = child?.Target as SKManagedStream;
var parentStream = parent?.Target as SKManagedStream;

if (childStream != null && parentStream != null) {
// remove this stream from the list by connecting the parent with the child
childStream.parent = parent;
parentStream.child = child;
} else if (childStream != null) {
// transfer ownership to child
childStream.parent = null;
} else if (parentStream != null) {
// transfer ownership back to parent
parentStream.child = null;
parentStream.wasCopied = false;
parentStream.disposeStream = disposeStream;

disposeStream = false;
if (snapshotData != null) {
snapshotData.Dispose ();
snapshotData = null;
}

parent = null;
child = null;

if (disposeStream && stream != null) {
stream.Dispose ();
stream = null;
Expand Down Expand Up @@ -113,15 +97,11 @@ private IntPtr OnReadManagedStream (IntPtr buffer, IntPtr size)

protected internal override IntPtr OnRead (IntPtr buffer, IntPtr size)
{
VerifyOriginal ();

return OnReadManagedStream (buffer, size);
}

protected internal override IntPtr OnPeek (IntPtr buffer, IntPtr size)
{
VerifyOriginal ();

if (!stream.CanSeek) {
return (IntPtr)0;
}
Expand All @@ -133,8 +113,6 @@ protected internal override IntPtr OnPeek (IntPtr buffer, IntPtr size)

protected internal override bool OnIsAtEnd ()
{
VerifyOriginal ();

if (!stream.CanSeek) {
return isAsEnd;
}
Expand All @@ -143,22 +121,16 @@ protected internal override bool OnIsAtEnd ()

protected internal override bool OnHasPosition ()
{
VerifyOriginal ();

return stream.CanSeek;
}

protected internal override bool OnHasLength ()
{
VerifyOriginal ();

return stream.CanSeek;
}

protected internal override bool OnRewind ()
{
VerifyOriginal ();

if (!stream.CanSeek) {
return false;
}
Expand All @@ -168,8 +140,6 @@ protected internal override bool OnRewind ()

protected internal override IntPtr OnGetPosition ()
{
VerifyOriginal ();

if (!stream.CanSeek) {
return (IntPtr)0;
}
Expand All @@ -178,8 +148,6 @@ protected internal override IntPtr OnGetPosition ()

protected internal override IntPtr OnGetLength ()
{
VerifyOriginal ();

if (!stream.CanSeek) {
return (IntPtr)0;
}
Expand All @@ -188,8 +156,6 @@ protected internal override IntPtr OnGetLength ()

protected internal override bool OnSeek (IntPtr position)
{
VerifyOriginal ();

if (!stream.CanSeek) {
return false;
}
Expand All @@ -199,8 +165,6 @@ protected internal override bool OnSeek (IntPtr position)

protected internal override bool OnMove (int offset)
{
VerifyOriginal ();

if (!stream.CanSeek) {
return false;
}
Expand All @@ -210,46 +174,43 @@ protected internal override bool OnMove (int offset)

protected internal override IntPtr OnCreateNew ()
{
VerifyOriginal ();

return IntPtr.Zero;
}

protected internal override IntPtr OnDuplicate ()
private SKData GetOrCreateSnapshot ()
{
VerifyOriginal ();
if (snapshotData != null)
return snapshotData;

if (!stream.CanSeek)
return IntPtr.Zero;

var newStream = new SKManagedStream (stream, disposeStream);
newStream.parent = new WeakReference (this);

wasCopied = true;
disposeStream = false;
child = new WeakReference (newStream);

stream.Position = 0;
return null;

var pos = stream.Position;
try {
stream.Position = 0;
snapshotData = SKData.Create (stream, stream.Length);
} finally {
stream.Position = pos;
}

return newStream.Handle;
return snapshotData;
}

protected internal override IntPtr OnFork ()
protected internal override IntPtr OnDuplicate ()
{
VerifyOriginal ();

var newStream = new SKManagedStream (stream, disposeStream);

wasCopied = true;
disposeStream = false;
var data = GetOrCreateSnapshot ();
if (data == null)
return IntPtr.Zero;

return newStream.Handle;
return SkiaApi.sk_memorystream_new_with_skdata (data.Handle);
}

private void VerifyOriginal ()
protected internal override IntPtr OnFork ()
{
if (wasCopied)
throw new InvalidOperationException ("This stream was duplicated or forked and cannot be read anymore.");
var duplicate = OnDuplicate ();
if (duplicate != IntPtr.Zero)
SkiaApi.sk_stream_seek (duplicate, (IntPtr)stream.Position);
return duplicate;
}
}
}
Loading
Loading