Fix for when skia returns a counted reference to the same object

This commit is contained in:
Matthew Leibowitz 2017-02-26 00:48:05 +02:00
Родитель 0fd9080031
Коммит 979c1e0c22
5 изменённых файлов: 48 добавлений и 11 удалений

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

@ -326,7 +326,7 @@ namespace SkiaSharp
}
public SKColorTable ColorTable {
get { return GetObject<SKColorTable> (SkiaApi.sk_bitmap_get_colortable (Handle)); }
get { return GetObject<SKColorTable> (SkiaApi.sk_bitmap_get_colortable (Handle), false); }
}
public static SKImageInfo DecodeBounds (SKStream stream)

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

@ -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<IntPtr, WeakReference> instances = new Dictionary<IntPtr, WeakReference>();
private readonly List<SKObject> ownedObjects = new List<SKObject>();
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<TSkiaObject>(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;
}
/// <summary>
@ -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()

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

@ -338,7 +338,7 @@ namespace SkiaSharp
public SKPathEffect PathEffect {
get {
return GetObject<SKPathEffect> (SkiaApi.sk_paint_get_path_effect (Handle));
return GetObject<SKPathEffect> (SkiaApi.sk_paint_get_path_effect (Handle), false);
}
set {
SkiaApi.sk_paint_set_path_effect (Handle, value == null ? IntPtr.Zero : value.Handle);

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

@ -101,7 +101,7 @@ namespace SkiaSharp
}
public SKColorTable ColorTable {
get { return GetObject<SKColorTable> (SkiaApi.sk_pixmap_get_colortable (Handle)); }
get { return GetObject<SKColorTable> (SkiaApi.sk_pixmap_get_colortable (Handle), false); }
}
public static bool Resize (SKPixmap dst, SKPixmap src, SKBitmapResizeMethod method)

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

@ -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.");