From 9ed0ca64792f8134c8e16611d1ceb74764f99623 Mon Sep 17 00:00:00 2001 From: Nick Kovalsky Date: Fri, 13 Jun 2025 13:30:17 +0300 Subject: [PATCH 1/4] SKAutoCanvasRestore avoid crash at Dispose when canvas was already disposed --- binding/SkiaSharp/SKCanvas.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/binding/SkiaSharp/SKCanvas.cs b/binding/SkiaSharp/SKCanvas.cs index 81966b9a459..78a461d1a77 100644 --- a/binding/SkiaSharp/SKCanvas.cs +++ b/binding/SkiaSharp/SKCanvas.cs @@ -1065,7 +1065,10 @@ public SKAutoCanvasRestore (SKCanvas canvas, bool doSave) public void Dispose () { - Restore (); + //canvas can be GC-ed before us + if (canvas != null && canvas.Handle != IntPtr.Zero) { + Restore (); + } } /// From 25a4490b78b95653188d5fd91446aa44bf156b9a Mon Sep 17 00:00:00 2001 From: Nick Kovalsky Date: Tue, 17 Jun 2025 12:07:56 +0300 Subject: [PATCH 2/4] add safety checks to mappers --- .../SKCanvasView/SKCanvasViewHandler.Apple.cs | 9 +++++++++ .../SKCanvasView/SKCanvasViewHandler.Tizen.cs | 9 +++++++++ .../SKCanvasView/SKCanvasViewHandler.Windows.cs | 8 +++++++- .../Handlers/SKGLView/SKGLViewHandler.Android.cs | 11 ++++++++++- .../Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs | 11 ++++++++++- .../Handlers/SKGLView/SKGLViewHandler.Windows.cs | 10 ++++++++-- .../Handlers/SKGLView/SKGLViewHandler.iOS.cs | 11 ++++++++++- 7 files changed, 63 insertions(+), 6 deletions(-) diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs index ce56e098a29..5e47a2b0883 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs @@ -36,16 +36,25 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.SetNeedsDisplay(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) { + if (handler?.PlatformView == null) + return; + handler.touchProxy?.UpdateEnableTouchEvents(handler.PlatformView, canvasView.EnableTouchEvents); } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs index ad5bd55ce1c..cdc7bfd8455 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs @@ -33,16 +33,25 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) { + if (handler?.PlatformView == null) + return; + handler.touchHandler ??= new SKTouchHandler( args => canvasView.OnTouch(args), (x, y) => handler.OnGetScaledCoord(x, y)); diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs index 8518413d5df..b008ad56ba2 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Windows.cs @@ -33,17 +33,23 @@ protected override void DisconnectHandler(SKXamlCanvas platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - if (handler.PlatformView == null) + if (handler?.PlatformView == null) return; handler.touchHandler ??= new SKTouchHandler( diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs index aff64caa15d..921d8893a2d 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs @@ -42,13 +42,16 @@ protected override void DisconnectHandler(SKGLTextureView platformView) public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { + if (handler?.PlatformView == null) + return; + if (handler.PlatformView.RenderMode == Rendermode.WhenDirty) handler.PlatformView.RequestRender(); } public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { - if (handler.PlatformView is not MauiSKGLTextureView pv) + if (handler?.PlatformView is not MauiSKGLTextureView pv) return; pv.IgnorePixelScaling = view.IgnorePixelScaling; @@ -57,6 +60,9 @@ public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.RenderMode = view.HasRenderLoop ? Rendermode.Continuously : Rendermode.WhenDirty; @@ -64,6 +70,9 @@ public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { + if (handler?.PlatformView == null) + return; + handler.touchHandler ??= new SKTouchHandler( args => view.OnTouch(args), (x, y) => handler.OnGetScaledCoord(x, y)); diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs index 58307c2a29e..1c413a1a184 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs @@ -42,13 +42,16 @@ protected override void DisconnectHandler(SKMetalView platformView) public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { + if (handler?.PlatformView == null) + return; + if (handler.PlatformView.Paused && handler.PlatformView.EnableSetNeedsDisplay) handler.PlatformView.SetNeedsDisplay(); } public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { - if (handler.PlatformView is MauiSKMetalView pv) + if (handler?.PlatformView is MauiSKMetalView pv) { pv.IgnorePixelScaling = view.IgnorePixelScaling; handler.PlatformView.SetNeedsDisplay(); @@ -57,12 +60,18 @@ public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.Paused = !view.HasRenderLoop; handler.PlatformView.EnableSetNeedsDisplay = !view.HasRenderLoop; } public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { + if (handler?.PlatformView == null) + return; + handler.touchProxy?.UpdateEnableTouchEvents(handler.PlatformView, view.EnableTouchEvents); } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs index 58026f6a593..e03c75d9112 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs @@ -33,13 +33,16 @@ protected override void DisconnectHandler(SKSwapChainPanel platformView) public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { + if (handler?.PlatformView == null) + return; + if (!handler.PlatformView.EnableRenderLoop) handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { - if (handler.PlatformView is not MauiSKSwapChainPanel pv) + if (handler?.PlatformView is not MauiSKSwapChainPanel pv) return; pv.IgnorePixelScaling = view.IgnorePixelScaling; @@ -48,12 +51,15 @@ public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { + if (handler?.PlatformView == null) + return; + handler.PlatformView.EnableRenderLoop = view.HasRenderLoop; } public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { - if (handler.PlatformView == null) + if (handler?.PlatformView == null) return; handler.touchHandler ??= new SKTouchHandler( diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs index 3bb8450343f..b87a0e9342f 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs @@ -53,12 +53,15 @@ protected override void DisconnectHandler(SKGLView platformView) public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { + if (handler?.PlatformView == null) + return; + handler.renderLoopManager?.RequestDisplay(); } public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { - if (handler.PlatformView is MauiSKGLView pv) + if (handler?.PlatformView is MauiSKGLView pv) { pv.IgnorePixelScaling = view.IgnorePixelScaling; handler.renderLoopManager?.RequestDisplay(); @@ -67,6 +70,9 @@ public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { + if (handler?.PlatformView == null) + return; + if (view.HasRenderLoop) handler.renderLoopManager?.RequestRenderLoop(); else @@ -75,6 +81,9 @@ public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { + if (handler?.PlatformView == null) + return; + handler.touchProxy?.UpdateEnableTouchEvents(handler.PlatformView, view.EnableTouchEvents); } From e77da1305530021432f2c3f4d628b285d66d01ae Mon Sep 17 00:00:00 2001 From: Nick Kovalsky Date: Tue, 17 Jun 2025 12:39:36 +0300 Subject: [PATCH 3/4] add null check to dispatch System.NullReferenceException: Object reference not set to an instance of an object. at SkiaSharp.Views.Windows.SKXamlCanvas.Invalidate() --- source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKXamlCanvas.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKXamlCanvas.cs b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKXamlCanvas.cs index cf9c01233d7..d7767fcf508 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKXamlCanvas.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.WinUI/SKXamlCanvas.cs @@ -161,9 +161,9 @@ private void OnUnloaded(object sender, RoutedEventArgs e) public void Invalidate() { #if WINDOWS - DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, DoInvalidate); + DispatcherQueue?.TryEnqueue(DispatcherQueuePriority.Normal, DoInvalidate); #else - Dispatcher.RunAsync(CoreDispatcherPriority.Normal, DoInvalidate); + Dispatcher?.RunAsync(CoreDispatcherPriority.Normal, DoInvalidate); #endif } From ee447372020116950964f01d1241a6cefd4d887d Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 24 Jun 2025 18:10:36 +0200 Subject: [PATCH 4/4] Update SKCanvas.cs --- binding/SkiaSharp/SKCanvas.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/binding/SkiaSharp/SKCanvas.cs b/binding/SkiaSharp/SKCanvas.cs index 06a087652d6..16e5be1e8a1 100644 --- a/binding/SkiaSharp/SKCanvas.cs +++ b/binding/SkiaSharp/SKCanvas.cs @@ -1069,10 +1069,7 @@ public SKAutoCanvasRestore (SKCanvas canvas, bool doSave) public void Dispose () { - //canvas can be GC-ed before us - if (canvas != null && canvas.Handle != IntPtr.Zero) { - Restore (); - } + Restore (); } /// @@ -1081,10 +1078,11 @@ public void Dispose () /// public void Restore () { - if (canvas != null) { + // canvas can be GC-ed before us + if (canvas != null && canvas.Handle != IntPtr.Zero) { canvas.RestoreToCount (saveCount); - canvas = null; } + canvas = null; } }