diff --git a/binding/Binding/SKBitmap.cs b/binding/Binding/SKBitmap.cs index 4b43b9d7..437866f9 100644 --- a/binding/Binding/SKBitmap.cs +++ b/binding/Binding/SKBitmap.cs @@ -326,7 +326,7 @@ namespace SkiaSharp } public SKColorTable ColorTable { - get { return GetObject (SkiaApi.sk_bitmap_get_colortable (Handle)); } + get { return GetObject (SkiaApi.sk_bitmap_get_colortable (Handle), false); } } public static SKImageInfo DecodeBounds (SKStream stream) diff --git a/binding/Binding/SKObject.cs b/binding/Binding/SKObject.cs index 48199eb0..cf735185 100644 --- a/binding/Binding/SKObject.cs +++ b/binding/Binding/SKObject.cs @@ -13,6 +13,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using System.Threading; namespace SkiaSharp { @@ -21,15 +22,31 @@ namespace SkiaSharp private static readonly Dictionary instances = new Dictionary(); private readonly List ownedObjects = new List(); + private int referenceCount = 0; + private bool ownsHandle = false; [Preserve] internal SKObject(IntPtr handle, bool owns) - : base(handle) + : base(handle, false) { OwnsHandle = owns; } - protected bool OwnsHandle { get; private set; } + protected bool OwnsHandle + { + get { return ownsHandle; } + private set + { + if (ownsHandle != value) + { + ownsHandle = value; + if (value) + Interlocked.Increment(ref referenceCount); + else + Interlocked.Decrement(ref referenceCount); + } + } + } public override IntPtr Handle { @@ -53,9 +70,12 @@ namespace SkiaSharp ownedObjects.Clear(); } - DeregisterHandle(Handle, this); + var zero = DeregisterHandle(Handle, this); base.Dispose(disposing); + + if (zero) + Handle = IntPtr.Zero; } internal static TSkiaObject GetObject(IntPtr handle, bool owns = true) @@ -75,6 +95,8 @@ namespace SkiaSharp var instance = reference.Target as TSkiaObject; if (instance != null && instance.Handle != IntPtr.Zero) { + if (owns) + Interlocked.Increment(ref instance.referenceCount); return instance; } } @@ -123,23 +145,25 @@ namespace SkiaSharp } } - internal static void DeregisterHandle(IntPtr handle, SKObject instance) + internal static bool DeregisterHandle(IntPtr handle, SKObject instance) { if (handle == IntPtr.Zero) { - return; + return false; } lock (instances) { // find any references WeakReference reference; - if (instances.TryGetValue(handle, out reference)) + if (Interlocked.Decrement(ref instance.referenceCount) <= 0 && instances.TryGetValue(handle, out reference)) { // remove it if it is dead or the correct object instances.Remove(handle); + return true; } } + return false; } /// @@ -215,9 +239,18 @@ namespace SkiaSharp public class SKNativeObject : IDisposable { + private readonly bool zero; + internal SKNativeObject(IntPtr handle) { Handle = handle; + zero = true; + } + + internal SKNativeObject(IntPtr handle, bool zero) + { + Handle = handle; + this.zero = zero; } ~SKNativeObject() @@ -229,7 +262,8 @@ namespace SkiaSharp protected virtual void Dispose(bool disposing) { - Handle = IntPtr.Zero; + if (zero) + Handle = IntPtr.Zero; } public void Dispose() diff --git a/binding/Binding/SKPaint.cs b/binding/Binding/SKPaint.cs index 9f049acb..b355f280 100644 --- a/binding/Binding/SKPaint.cs +++ b/binding/Binding/SKPaint.cs @@ -338,7 +338,7 @@ namespace SkiaSharp public SKPathEffect PathEffect { get { - return GetObject (SkiaApi.sk_paint_get_path_effect (Handle)); + return GetObject (SkiaApi.sk_paint_get_path_effect (Handle), false); } set { SkiaApi.sk_paint_set_path_effect (Handle, value == null ? IntPtr.Zero : value.Handle); diff --git a/binding/Binding/SKPixmap.cs b/binding/Binding/SKPixmap.cs index 0755b5e5..bda250f1 100644 --- a/binding/Binding/SKPixmap.cs +++ b/binding/Binding/SKPixmap.cs @@ -101,7 +101,7 @@ namespace SkiaSharp } public SKColorTable ColorTable { - get { return GetObject (SkiaApi.sk_pixmap_get_colortable (Handle)); } + get { return GetObject (SkiaApi.sk_pixmap_get_colortable (Handle), false); } } public static bool Resize (SKPixmap dst, SKPixmap src, SKBitmapResizeMethod method) diff --git a/tests/Tests/SKBitmapTest.cs b/tests/Tests/SKBitmapTest.cs index 168c1ddd..ae9e036b 100644 --- a/tests/Tests/SKBitmapTest.cs +++ b/tests/Tests/SKBitmapTest.cs @@ -55,7 +55,10 @@ namespace SkiaSharp.Tests using (var pixmap = new SKPixmap(info, pixels)) using (var image = SKImage.FromPixels(pixmap, onRelease, "RELEASING!")) { Assert.IsFalse(image.IsTextureBacked); - Assert.AreEqual(image, image.ToRasterImage()); + using (var raster = image.ToRasterImage()) { + Assert.AreEqual(image, raster); + } + Assert.False(released, "The SKImageRasterReleaseDelegate was called too soon."); } Assert.True(released, "The SKImageRasterReleaseDelegate was not called.");