From ce2520b64357eb6d0006feeaa06892c207210ef5 Mon Sep 17 00:00:00 2001 From: Matthew Leibowitz Date: Tue, 5 Sep 2023 00:52:39 +0200 Subject: [PATCH] Implemented SKGLView - Mac Catalyst does not support OpenGL and will need a new Metal-based view - Tizen needs the support in the native view --- .../SkiaSharpSample/SkiaSharpSample.csproj | 1 + .../AppHostBuilderExtensions.cs | 1 + .../SKCanvasView.HandlerImpl.cs | 38 --- .../SKCanvasView.cs | 81 ++----- .../SkiaSharp.Views.Maui.Controls/SKGLView.cs | 108 +++------ .../SKImageSource.HandlerImpl.cs | 20 -- .../SKImageSource.cs | 8 +- .../SKCanvasViewHandler.Android.cs | 7 +- ...er.iOS.cs => SKCanvasViewHandler.Apple.cs} | 7 +- .../SKCanvasView/SKCanvasViewHandler.Tizen.cs | 7 +- .../SKCanvasViewHandler.Windows.cs | 5 +- .../SKCanvasView/SKCanvasViewHandler.cs | 2 +- .../SKGLView/SKGLViewHandler.Android.cs | 136 +++++++++++ .../SKGLView/SKGLViewHandler.MacCatalyst.cs | 19 ++ .../Handlers/SKGLView/SKGLViewHandler.Ref.cs | 18 ++ .../SKGLView/SKGLViewHandler.Tizen.cs | 21 ++ .../SKGLView/SKGLViewHandler.Windows.cs | 129 +++++++++++ .../Handlers/SKGLView/SKGLViewHandler.cs | 35 +++ .../Handlers/SKGLView/SKGLViewHandler.iOS.cs | 219 ++++++++++++++++++ ...e.iOS.cs => SKImageSourceService.Apple.cs} | 0 .../SkiaSharp.Views.Maui.Core/ISKGLView.cs | 27 +++ .../Android/SKCanvasViewExtensions.cs | 10 - .../Platform/{iOS => Apple}/SKTouchHandler.cs | 0 .../Platform/Tizen/SKCanvasViewExtensions.cs | 10 - .../Windows/SKCanvasViewExtensions.cs | 10 - .../Platform/iOS/SKCanvasViewExtensions.cs | 10 - .../SKPaintGLSurfaceEventArgs.cs | 21 ++ .../SkiaSharp.Views.Maui.Core.csproj | 12 + .../SkiaSharp.Views/Platform/iOS/SKGLLayer.cs | 7 + .../SkiaSharp.Views/Platform/iOS/SKGLView.cs | 7 + 30 files changed, 710 insertions(+), 266 deletions(-) delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs rename source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/{SKCanvasViewHandler.iOS.cs => SKCanvasViewHandler.Apple.cs} (92%) create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs rename source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/{SKImageSourceService.iOS.cs => SKImageSourceService.Apple.cs} (100%) create mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs rename source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/{iOS => Apple}/SKTouchHandler.cs (100%) delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs delete mode 100644 source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs diff --git a/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj b/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj index 1fea779096..9b5b1c5498 100644 --- a/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj +++ b/samples/Basic/Maui/SkiaSharpSample/SkiaSharpSample.csproj @@ -37,5 +37,6 @@ + diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs index 9fb132aba5..cc28dcf9e6 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/AppHostBuilderExtensions.cs @@ -13,6 +13,7 @@ public static MauiAppBuilder UseSkiaSharp(this MauiAppBuilder builder) => .ConfigureMauiHandlers(handlers => { handlers.AddHandler(); + handlers.AddHandler(); }) .ConfigureImageSources(sources => { diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs deleted file mode 100644 index e1c4b27bde..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.HandlerImpl.cs +++ /dev/null @@ -1,38 +0,0 @@ -#nullable enable - -using System; - -namespace SkiaSharp.Views.Maui.Controls -{ - public partial class SKCanvasView : ISKCanvasView - { - private SKSizeI lastCanvasSize; - - public SKCanvasView() - { - var controller = (ISKCanvasViewController)this; - - controller.GetCanvasSize += OnGetCanvasSize; - controller.SurfaceInvalidated += OnSurfaceInvalidated; - - void OnGetCanvasSize(object? sender, GetPropertyValueEventArgs e) - { - e.Value = lastCanvasSize; - } - - void OnSurfaceInvalidated(object? sender, EventArgs e) - { - Handler?.Invoke(nameof(ISKCanvasView.InvalidateSurface)); - } - } - - void ISKCanvasView.OnCanvasSizeChanged(SKSizeI size) => - lastCanvasSize = size; - - void ISKCanvasView.OnPaintSurface(SKPaintSurfaceEventArgs e) => - OnPaintSurface(e); - - void ISKCanvasView.OnTouch(SKTouchEventArgs e) => - OnTouch(e); - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs index e1b21e1082..9f4cb6172a 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKCanvasView.cs @@ -8,7 +8,7 @@ namespace SkiaSharp.Views.Maui.Controls { - public partial class SKCanvasView : View, ISKCanvasViewController + public partial class SKCanvasView : View, ISKCanvasView { public static readonly BindableProperty IgnorePixelScalingProperty = BindableProperty.Create(nameof(IgnorePixelScaling), typeof(bool), typeof(SKCanvasView), false); @@ -16,99 +16,52 @@ public partial class SKCanvasView : View, ISKCanvasViewController public static readonly BindableProperty EnableTouchEventsProperty = BindableProperty.Create(nameof(EnableTouchEvents), typeof(bool), typeof(SKCanvasView), false); - // the user can subscribe to repaint + private SKSizeI lastCanvasSize; + + public SKCanvasView() + { + } + public event EventHandler? PaintSurface; - // the user can subscribe to touch events public event EventHandler? Touch; - // the native listens to this event - private event EventHandler? SurfaceInvalidated; - private event EventHandler>? GetCanvasSize; - - // the user asks the for the size - public SKSize CanvasSize - { - get - { - // send a mesage to the native view - var args = new GetPropertyValueEventArgs(); - GetCanvasSize?.Invoke(this, args); - return args.Value; - } - } + public SKSize CanvasSize => lastCanvasSize; public bool IgnorePixelScaling { - get { return (bool)GetValue(IgnorePixelScalingProperty); } - set { SetValue(IgnorePixelScalingProperty, value); } + get => (bool)GetValue(IgnorePixelScalingProperty); + set => SetValue(IgnorePixelScalingProperty, value); } public bool EnableTouchEvents { - get { return (bool)GetValue(EnableTouchEventsProperty); } - set { SetValue(EnableTouchEventsProperty, value); } + get => (bool)GetValue(EnableTouchEventsProperty); + set => SetValue(EnableTouchEventsProperty, value); } - // the user asks to repaint public void InvalidateSurface() { - // send a mesage to the native view - SurfaceInvalidated?.Invoke(this, EventArgs.Empty); + Handler?.Invoke(nameof(ISKCanvasView.InvalidateSurface)); } - // the native view tells the user to repaint protected virtual void OnPaintSurface(SKPaintSurfaceEventArgs e) { PaintSurface?.Invoke(this, e); } - // the native view responds to a touch protected virtual void OnTouch(SKTouchEventArgs e) { Touch?.Invoke(this, e); } - // ISKViewController implementation - - event EventHandler ISKCanvasViewController.SurfaceInvalidated - { - add { SurfaceInvalidated += value; } - remove { SurfaceInvalidated -= value; } - } - - event EventHandler> ISKCanvasViewController.GetCanvasSize - { - add { GetCanvasSize += value; } - remove { GetCanvasSize -= value; } - } + void ISKCanvasView.OnCanvasSizeChanged(SKSizeI size) => + lastCanvasSize = size; - void ISKCanvasViewController.OnPaintSurface(SKPaintSurfaceEventArgs e) - { + void ISKCanvasView.OnPaintSurface(SKPaintSurfaceEventArgs e) => OnPaintSurface(e); - } - void ISKCanvasViewController.OnTouch(SKTouchEventArgs e) - { + void ISKCanvasView.OnTouch(SKTouchEventArgs e) => OnTouch(e); - } - - protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) - { - return new SizeRequest(new Size(40.0, 40.0)); - } - } - - public interface ISKCanvasViewController : IViewController - { - // the native listens to this event - event EventHandler SurfaceInvalidated; - event EventHandler> GetCanvasSize; - - // the native view tells the user to repaint - void OnPaintSurface(SKPaintSurfaceEventArgs e); - - // the native view responds to a touch - void OnTouch(SKTouchEventArgs e); } } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs index 519cbfc92d..373f1a6ed2 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKGLView.cs @@ -8,127 +8,71 @@ namespace SkiaSharp.Views.Maui.Controls { - public partial class SKGLView : View, ISKGLViewController + public partial class SKGLView : View, ISKGLView { + public static readonly BindableProperty IgnorePixelScalingProperty = + BindableProperty.Create(nameof(IgnorePixelScaling), typeof(bool), typeof(SKGLView), false); + public static readonly BindableProperty HasRenderLoopProperty = BindableProperty.Create(nameof(HasRenderLoop), typeof(bool), typeof(SKGLView), false); public static readonly BindableProperty EnableTouchEventsProperty = BindableProperty.Create(nameof(EnableTouchEvents), typeof(bool), typeof(SKGLView), false); + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + + public bool IgnorePixelScaling + { + get => (bool)GetValue(IgnorePixelScalingProperty); + set => SetValue(IgnorePixelScalingProperty, value); + } + public bool HasRenderLoop { - get { return (bool)GetValue(HasRenderLoopProperty); } - set { SetValue(HasRenderLoopProperty, value); } + get => (bool)GetValue(HasRenderLoopProperty); + set => SetValue(HasRenderLoopProperty, value); } public bool EnableTouchEvents { - get { return (bool)GetValue(EnableTouchEventsProperty); } - set { SetValue(EnableTouchEventsProperty, value); } + get => (bool)GetValue(EnableTouchEventsProperty); + set => SetValue(EnableTouchEventsProperty, value); } - // the user can subscribe to repaint public event EventHandler? PaintSurface; - // the user can subscribe to touch events public event EventHandler? Touch; - // the native listens to this event - private event EventHandler? SurfaceInvalidated; - private event EventHandler>? GetCanvasSize; - private event EventHandler>? GetGRContext; + public SKSize CanvasSize => lastCanvasSize; - // the user asks the for the size - public SKSize CanvasSize - { - get - { - // send a mesage to the native view - var args = new GetPropertyValueEventArgs(); - GetCanvasSize?.Invoke(this, args); - return args.Value; - } - } + public GRContext? GRContext => lastGRContext; - // the user asks the for the current GRContext - public GRContext GRContext - { - get - { - // send a mesage to the native view - var args = new GetPropertyValueEventArgs(); - GetGRContext?.Invoke(this, args); - return args.Value; - } - } - - // the user asks to repaint public void InvalidateSurface() { - // send a mesage to the native view - SurfaceInvalidated?.Invoke(this, EventArgs.Empty); + Handler?.Invoke(nameof(ISKGLView.InvalidateSurface)); } - // the native view tells the user to repaint protected virtual void OnPaintSurface(SKPaintGLSurfaceEventArgs e) { PaintSurface?.Invoke(this, e); } - // the native view responds to a touch protected virtual void OnTouch(SKTouchEventArgs e) { Touch?.Invoke(this, e); } - // ISKViewController implementation - - event EventHandler ISKGLViewController.SurfaceInvalidated - { - add { SurfaceInvalidated += value; } - remove { SurfaceInvalidated -= value; } - } - - event EventHandler> ISKGLViewController.GetCanvasSize - { - add { GetCanvasSize += value; } - remove { GetCanvasSize -= value; } - } + void ISKGLView.OnCanvasSizeChanged(SKSizeI size) => + lastCanvasSize = size; - event EventHandler> ISKGLViewController.GetGRContext - { - add { GetGRContext += value; } - remove { GetGRContext -= value; } - } + void ISKGLView.OnGRContextChanged(GRContext? context) => + lastGRContext = context; - void ISKGLViewController.OnPaintSurface(SKPaintGLSurfaceEventArgs e) - { + void ISKGLView.OnPaintSurface(SKPaintGLSurfaceEventArgs e) => OnPaintSurface(e); - } - void ISKGLViewController.OnTouch(SKTouchEventArgs e) - { + void ISKGLView.OnTouch(SKTouchEventArgs e) => OnTouch(e); - } - - protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint) - { - return new SizeRequest(new Size(40.0, 40.0)); - } - } - - public interface ISKGLViewController : IViewController - { - // the native listens to this event - event EventHandler SurfaceInvalidated; - event EventHandler> GetCanvasSize; - event EventHandler> GetGRContext; - - // the native view tells the user to repaint - void OnPaintSurface(SKPaintGLSurfaceEventArgs e); - - // the native view responds to a touch - void OnTouch(SKTouchEventArgs e); } } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs deleted file mode 100644 index 695fa33f77..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.HandlerImpl.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable enable - -namespace SkiaSharp.Views.Maui.Controls -{ - partial class SKImageImageSource : ISKImageImageSource - { - } - - partial class SKBitmapImageSource : ISKBitmapImageSource - { - } - - partial class SKPixmapImageSource : ISKPixmapImageSource - { - } - - partial class SKPictureImageSource : ISKPictureImageSource - { - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs index 86bcb3e2fb..aa0ad8b876 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Controls/SKImageSource.cs @@ -5,7 +5,7 @@ namespace SkiaSharp.Views.Maui.Controls { - public sealed partial class SKImageImageSource : ImageSource + public sealed partial class SKImageImageSource : ImageSource, ISKImageImageSource { public static readonly BindableProperty ImageProperty = BindableProperty.Create(nameof(Image), typeof(SKImage), typeof(SKImageImageSource), default(SKImage)); @@ -41,7 +41,7 @@ protected override void OnPropertyChanged(string propertyName = null) } } - public sealed partial class SKBitmapImageSource : ImageSource + public sealed partial class SKBitmapImageSource : ImageSource, ISKBitmapImageSource { public static readonly BindableProperty BitmapProperty = BindableProperty.Create(nameof(Bitmap), typeof(SKBitmap), typeof(SKBitmapImageSource), default(SKBitmap)); @@ -77,7 +77,7 @@ protected override void OnPropertyChanged(string propertyName = null) } } - public sealed partial class SKPixmapImageSource : ImageSource + public sealed partial class SKPixmapImageSource : ImageSource, ISKPixmapImageSource { public static readonly BindableProperty PixmapProperty = BindableProperty.Create(nameof(Pixmap), typeof(SKPixmap), typeof(SKPixmapImageSource), default(SKPixmap)); @@ -113,7 +113,7 @@ protected override void OnPropertyChanged(string propertyName = null) } } - public sealed partial class SKPictureImageSource : ImageSource + public sealed partial class SKPictureImageSource : ImageSource, ISKPictureImageSource { public static readonly BindableProperty PictureProperty = BindableProperty.Create(nameof(Picture), typeof(SKPicture), typeof(SKPictureImageSource), default(SKPicture)); diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs index 82bf3bd614..d9d67f8fa6 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Android.cs @@ -34,19 +34,16 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.Invalidate(); + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + 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.iOS.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs similarity index 92% rename from source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.iOS.cs rename to source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs index 33c3025314..a40ac0b1a2 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.iOS.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Apple.cs @@ -33,19 +33,16 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.SetNeedsDisplay(); + handler.PlatformView.SetNeedsDisplay(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + 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.Tizen.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.Tizen.cs index 08cd85f944..ad5bd55ce1 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,19 +33,16 @@ protected override void DisconnectHandler(SKCanvasView platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.Invalidate(); + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + 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 9b6ba30935..8518413d5d 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 @@ -1,4 +1,5 @@ using Microsoft.Maui.Handlers; +using Microsoft.UI.Xaml; using SkiaSharp.Views.Maui.Platform; using SkiaSharp.Views.Windows; @@ -32,12 +33,12 @@ protected override void DisconnectHandler(SKXamlCanvas platformView) public static void OnInvalidateSurface(SKCanvasViewHandler handler, ISKCanvasView canvasView, object? args) { - handler.PlatformView?.Invalidate(); + handler.PlatformView.Invalidate(); } public static void MapIgnorePixelScaling(SKCanvasViewHandler handler, ISKCanvasView canvasView) { - handler.PlatformView?.UpdateIgnorePixelScaling(canvasView); + handler.PlatformView.IgnorePixelScaling = canvasView.IgnorePixelScaling; } public static void MapEnableTouchEvents(SKCanvasViewHandler handler, ISKCanvasView canvasView) diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs index dd9deea98e..90ea1bcd4f 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKCanvasView/SKCanvasViewHandler.cs @@ -13,7 +13,7 @@ public partial class SKCanvasViewHandler }; public static CommandMapper SKCanvasViewCommandMapper = - new CommandMapper() + new CommandMapper(ViewHandler.ViewCommandMapper) { [nameof(ISKCanvasView.InvalidateSurface)] = OnInvalidateSurface, }; 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 new file mode 100644 index 0000000000..aff64caa15 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Android.cs @@ -0,0 +1,136 @@ +using Android.Content; +using Android.Opengl; +using Microsoft.Maui; +using Microsoft.Maui.Handlers; +using Microsoft.Maui.Platform; +using SkiaSharp.Views.Android; +using SkiaSharp.Views.Maui.Platform; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; + + protected override SKGLTextureView CreatePlatformView() + { + var view = new MauiSKGLTextureView(Context); + view.SetOpaque(false); + return view; + } + + protected override void ConnectHandler(SKGLTextureView platformView) + { + platformView.PaintSurface += OnPaintSurface; + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(SKGLTextureView platformView) + { + touchHandler?.Detach(platformView); + touchHandler = null; + + platformView.PaintSurface -= OnPaintSurface; + + base.DisconnectHandler(platformView); + } + + // Mapper actions / properties + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) + { + if (handler.PlatformView.RenderMode == Rendermode.WhenDirty) + handler.PlatformView.RequestRender(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is not MauiSKGLTextureView pv) + return; + + pv.IgnorePixelScaling = view.IgnorePixelScaling; + pv.RequestRender(); + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + handler.PlatformView.RenderMode = view.HasRenderLoop + ? Rendermode.Continuously + : Rendermode.WhenDirty; + } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) + { + handler.touchHandler ??= new SKTouchHandler( + args => view.OnTouch(args), + (x, y) => handler.OnGetScaledCoord(x, y)); + + handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents); + } + + // helper methods + + private void OnPaintSurface(object? sender, Android.SKPaintGLSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKGLTextureView platformView) + { + var newGRContext = platformView.GRContext; + if (lastGRContext != newGRContext) + { + lastGRContext = newGRContext; + VirtualView?.OnGRContextChanged(newGRContext); + } + } + + VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo)); + } + + private SKPoint OnGetScaledCoord(double x, double y) + { + if (VirtualView?.IgnorePixelScaling == true && Context != null) + { + x = Context.FromPixels(x); + y = Context.FromPixels(y); + } + + return new SKPoint((float)x, (float)y); + } + + private class MauiSKGLTextureView : SKGLTextureView + { + private float density; + + public MauiSKGLTextureView(Context context) + : base(context) + { + density = Resources?.DisplayMetrics?.Density ?? 1; + } + + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(Android.SKPaintGLSurfaceEventArgs e) + { + if (IgnorePixelScaling) + { + var userVisibleSize = new SKSizeI((int)(e.Info.Width / density), (int)(e.Info.Height / density)); + var canvas = e.Surface.Canvas; + canvas.Scale(density); + canvas.Save(); + + e = new Android.SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } + } +} 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 new file mode 100644 index 0000000000..81e91378e3 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.MacCatalyst.cs @@ -0,0 +1,19 @@ +using System; +using Microsoft.Maui.Handlers; +using UIKit; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + protected override UIView CreatePlatformView() => throw new PlatformNotSupportedException("OpenGL-based views (such as SKGLView) are not supported on Mac Catalyst. Instead, use Metal-based views."); + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs new file mode 100644 index 0000000000..c9ef2d859f --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Ref.cs @@ -0,0 +1,18 @@ +using System; +using Microsoft.Maui.Handlers; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + protected override object CreatePlatformView() => throw new NotImplementedException(); + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs new file mode 100644 index 0000000000..42a948c453 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Tizen.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.Maui.Handlers; +using SkiaSharp.Views.Maui.Platform; +using SkiaSharp.Views.Tizen.NUI; +using ScalingInfo = SkiaSharp.Views.Tizen.ScalingInfo; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + protected override SKGLSurfaceView CreatePlatformView() => throw new PlatformNotSupportedException("SKGLView is not yet implemented for Tizen."); + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + } +} 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 new file mode 100644 index 0000000000..58026f6a59 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.Windows.cs @@ -0,0 +1,129 @@ +using Microsoft.Maui.Handlers; +using SkiaSharp.Views.Maui.Platform; +using SkiaSharp.Views.Windows; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler : ViewHandler + { + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; + + protected override SKSwapChainPanel CreatePlatformView() => new MauiSKSwapChainPanel(); + + protected override void ConnectHandler(SKSwapChainPanel platformView) + { + platformView.PaintSurface += OnPaintSurface; + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(SKSwapChainPanel platformView) + { + touchHandler?.Detach(platformView); + touchHandler = null; + + platformView.PaintSurface -= OnPaintSurface; + + base.DisconnectHandler(platformView); + } + + // Mapper actions / properties + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) + { + if (!handler.PlatformView.EnableRenderLoop) + handler.PlatformView.Invalidate(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is not MauiSKSwapChainPanel pv) + return; + + pv.IgnorePixelScaling = view.IgnorePixelScaling; + pv.Invalidate(); + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + handler.PlatformView.EnableRenderLoop = view.HasRenderLoop; + } + + 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)); + + handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents); + } + + public static void MapBackground(SKGLViewHandler handler, ISKGLView view) + { + // WinUI 3 limitation: + // Setting 'Background' property is not supported on SwapChainPanel.'. + } + + // helper methods + + private void OnPaintSurface(object? sender, Windows.SKPaintGLSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKSwapChainPanel platformView) + { + var newGRContext = platformView.GRContext; + if (lastGRContext != newGRContext) + { + lastGRContext = newGRContext; + VirtualView?.OnGRContextChanged(newGRContext); + } + } + + VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo)); + } + + private SKPoint OnGetScaledCoord(double x, double y) + { + if (VirtualView?.IgnorePixelScaling == false && PlatformView != null) + { + var scale = PlatformView.ContentsScale; + + x *= scale; + y *= scale; + } + + return new SKPoint((float)x, (float)y); + } + + private class MauiSKSwapChainPanel : SKSwapChainPanel + { + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(Windows.SKPaintGLSurfaceEventArgs e) + { + if (IgnorePixelScaling) + { + var density = (float)ContentsScale; + var userVisibleSize = new SKSizeI((int)(e.Info.Width / density), (int)(e.Info.Height / density)); + var canvas = e.Surface.Canvas; + canvas.Scale(density); + canvas.Save(); + + e = new Windows.SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs new file mode 100644 index 0000000000..493691e456 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.cs @@ -0,0 +1,35 @@ +using Microsoft.Maui; +using Microsoft.Maui.Handlers; + +namespace SkiaSharp.Views.Maui.Handlers +{ + public partial class SKGLViewHandler + { + public static PropertyMapper SKGLViewMapper = + new PropertyMapper(ViewHandler.ViewMapper) + { + [nameof(ISKGLView.EnableTouchEvents)] = MapEnableTouchEvents, + [nameof(ISKGLView.IgnorePixelScaling)] = MapIgnorePixelScaling, + [nameof(ISKGLView.HasRenderLoop)] = MapHasRenderLoop, +#if WINDOWS + [nameof(ISKGLView.Background)] = MapBackground, +#endif + }; + + public static CommandMapper SKGLViewCommandMapper = + new CommandMapper(ViewHandler.ViewCommandMapper) + { + [nameof(ISKGLView.InvalidateSurface)] = OnInvalidateSurface, + }; + + public SKGLViewHandler() + : base(SKGLViewMapper, SKGLViewCommandMapper) + { + } + + public SKGLViewHandler(PropertyMapper? mapper, CommandMapper? commands) + : base(mapper ?? SKGLViewMapper, commands ?? SKGLViewCommandMapper) + { + } + } +} 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 new file mode 100644 index 0000000000..c19a2463a6 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKGLView/SKGLViewHandler.iOS.cs @@ -0,0 +1,219 @@ +using System; +using System.Runtime.Versioning; +using CoreAnimation; +using Foundation; +using Microsoft.Maui.Handlers; +using SkiaSharp.Views.iOS; +using SkiaSharp.Views.Maui.Platform; +using UIKit; + +namespace SkiaSharp.Views.Maui.Handlers +{ + [ObsoletedOSPlatform("ios12.0", "Use 'Metal' instead.")] + [ObsoletedOSPlatform("tvos12.0", "Use 'Metal' instead.")] + [SupportedOSPlatform("ios")] + [SupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("macos")] + public partial class SKGLViewHandler : ViewHandler + { + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; + private RenderLoopManager? renderLoopManager; + + protected override SKGLView CreatePlatformView() => + new MauiSKGLView + { + BackgroundColor = UIColor.Clear, + Opaque = false, + }; + + protected override void ConnectHandler(SKGLView platformView) + { + renderLoopManager = new RenderLoopManager(this); + + platformView.PaintSurface += OnPaintSurface; + + base.ConnectHandler(platformView); + } + + protected override void DisconnectHandler(SKGLView platformView) + { + renderLoopManager?.StopRenderLoop(); + + touchHandler?.Detach(platformView); + touchHandler = null; + + platformView.PaintSurface -= OnPaintSurface; + + base.DisconnectHandler(platformView); + } + + // Mapper actions / properties + + public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) + { + handler.renderLoopManager?.RequestDisplay(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is MauiSKGLView pv) + { + pv.IgnorePixelScaling = view.IgnorePixelScaling; + handler.renderLoopManager?.RequestDisplay(); + } + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + if (view.HasRenderLoop) + handler.renderLoopManager?.RequestRenderLoop(); + else + handler.renderLoopManager?.StopRenderLoop(); + } + + public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) + { + handler.touchHandler ??= new SKTouchHandler( + args => view.OnTouch(args), + (x, y) => handler.OnGetScaledCoord(x, y)); + + handler.touchHandler?.SetEnabled(handler.PlatformView, view.EnableTouchEvents); + } + + // helper methods + + private void OnPaintSurface(object? sender, iOS.SKPaintGLSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKGLView platformView) + { + var newGRContext = platformView.GRContext; + if (lastGRContext != newGRContext) + { + lastGRContext = newGRContext; + VirtualView?.OnGRContextChanged(newGRContext); + } + } + + VirtualView?.OnPaintSurface(new SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info, e.RawInfo)); + } + + private SKPoint OnGetScaledCoord(double x, double y) + { + if (VirtualView?.IgnorePixelScaling == false && PlatformView != null) + { + var scale = PlatformView.ContentScaleFactor; + + x *= scale; + y *= scale; + } + + return new SKPoint((float)x, (float)y); + } + + private class MauiSKGLView : SKGLView + { + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(iOS.SKPaintGLSurfaceEventArgs e) + { + if (IgnorePixelScaling) + { + var userVisibleSize = new SKSizeI((int)Bounds.Width, (int)Bounds.Height); + var canvas = e.Surface.Canvas; + canvas.Scale((float)ContentScaleFactor); + canvas.Save(); + + e = new iOS.SKPaintGLSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } + + private class RenderLoopManager + { + private CADisplayLink? displayLink; + private WeakReference weakHandler; + + public RenderLoopManager(SKGLViewHandler handler) + { + weakHandler = new WeakReference(handler); + } + + public SKGLViewHandler? Handler + { + get + { + if (weakHandler.TryGetTarget(out var handler)) + return handler; + return null; + } + } + + public SKGLView? PlatformView => Handler?.PlatformView; + + public ISKGLView? VirtualView => Handler?.VirtualView; + + public void RequestDisplay() + { + // skip if there is a render loop + if (displayLink is not null) + return; + + var nativeView = PlatformView; + nativeView?.BeginInvokeOnMainThread(() => + { + if (nativeView is not null && nativeView.Handle != IntPtr.Zero) + nativeView.Display(); + }); + } + + public void RequestRenderLoop() + { + // skip if there is already a render loop + if (displayLink is not null) + return; + + // bail out if we are requesting something that the view doesn't want to + if (VirtualView?.HasRenderLoop != true) + return; + + displayLink = CADisplayLink.Create(() => + { + var nativeView = PlatformView; + var virtualView = VirtualView; + + // stop the render loop if the loop was disabled, or the views are disposed + if (nativeView is null || virtualView is null || nativeView.Handle == IntPtr.Zero || !virtualView.HasRenderLoop) + { + StopRenderLoop(); + return; + } + + // redraw the view + nativeView.Display(); + }); + displayLink.AddToRunLoop(NSRunLoop.Current, NSRunLoopMode.Default); + } + + public void StopRenderLoop() + { + // skip if there is no render loop + if (displayLink is null) + return; + + displayLink.Invalidate(); + displayLink.Dispose(); + displayLink = null; + } + } + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.iOS.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.Apple.cs similarity index 100% rename from source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.iOS.cs rename to source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Handlers/SKImageSourceService/SKImageSourceService.Apple.cs diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs new file mode 100644 index 0000000000..55d517a5f0 --- /dev/null +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/ISKGLView.cs @@ -0,0 +1,27 @@ +using Microsoft.Maui; + +namespace SkiaSharp.Views.Maui +{ + public interface ISKGLView : IView + { + SKSize CanvasSize { get; } + + GRContext? GRContext { get; } + + bool HasRenderLoop { get; } + + bool IgnorePixelScaling { get; } + + bool EnableTouchEvents { get; } + + void InvalidateSurface(); + + void OnCanvasSizeChanged(SKSizeI size); + + void OnGRContextChanged(GRContext? context); + + void OnPaintSurface(SKPaintGLSurfaceEventArgs e); + + void OnTouch(SKTouchEventArgs e); + } +} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs deleted file mode 100644 index c292e76bed..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Android/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.Android; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKCanvasView nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKTouchHandler.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Apple/SKTouchHandler.cs similarity index 100% rename from source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKTouchHandler.cs rename to source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Apple/SKTouchHandler.cs diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs deleted file mode 100644 index fa6ba11eef..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Tizen/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.Tizen.NUI; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKCanvasView nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs deleted file mode 100644 index 5977efb5a8..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/Windows/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.Windows; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKXamlCanvas nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs deleted file mode 100644 index 8a495cc783..0000000000 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/Platform/iOS/SKCanvasViewExtensions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SkiaSharp.Views.iOS; - -namespace SkiaSharp.Views.Maui.Platform -{ - public static class SKCanvasViewExtensions - { - public static void UpdateIgnorePixelScaling(this SKCanvasView nativeView, ISKCanvasView canvasView) => - nativeView.IgnorePixelScaling = canvasView?.IgnorePixelScaling ?? false; - } -} diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs index de5039c76e..f1b7e3bc3d 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SKPaintGLSurfaceEventArgs.cs @@ -18,6 +18,23 @@ public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget render BackendRenderTarget = renderTarget; ColorType = colorType; Origin = origin; + Info = new SKImageInfo(renderTarget.Width, renderTarget.Height, ColorType); + RawInfo = Info; + } + + public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info) + : this(surface, renderTarget, origin, info, info) + { + } + + public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info, SKImageInfo rawInfo) + { + Surface = surface; + BackendRenderTarget = renderTarget; + ColorType = info.ColorType; + Origin = origin; + Info = info; + RawInfo = rawInfo; } public SKSurface Surface { get; private set; } @@ -27,5 +44,9 @@ public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget render public SKColorType ColorType { get; private set; } public GRSurfaceOrigin Origin { get; private set; } + + public SKImageInfo Info { get; private set; } + + public SKImageInfo RawInfo { get; private set; } } } diff --git a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj index c9c164a391..ee09f8be26 100644 --- a/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj +++ b/source/SkiaSharp.Views.Maui/SkiaSharp.Views.Maui.Core/SkiaSharp.Views.Maui.Core.csproj @@ -27,11 +27,23 @@ + + + + + + + + + + + + diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs index ee1a8eba55..f27b363442 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLLayer.cs @@ -2,6 +2,7 @@ using System; using System.ComponentModel; +using System.Runtime.Versioning; using CoreAnimation; using CoreGraphics; using OpenGLES; @@ -13,6 +14,12 @@ namespace SkiaSharp.Views.tvOS namespace SkiaSharp.Views.iOS #endif { + [ObsoletedOSPlatform("tvos12.0", "Use 'Metal' instead.")] + [ObsoletedOSPlatform("ios12.0", "Use 'Metal' instead.")] + [SupportedOSPlatform("ios")] + [SupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("macos")] + [UnsupportedOSPlatform("maccatalyst")] public class SKGLLayer : CAEAGLLayer { private const SKColorType colorType = SKColorType.Rgba8888; diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs index 58e10521ee..de4b9d2455 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/iOS/SKGLView.cs @@ -2,6 +2,8 @@ using System; using System.ComponentModel; +using System.Runtime.Versioning; +using CoreAnimation; using CoreGraphics; using Foundation; using GLKit; @@ -18,6 +20,11 @@ namespace SkiaSharp.Views.tvOS namespace SkiaSharp.Views.iOS #endif { + [ObsoletedOSPlatform("ios12.0", "Use 'Metal' instead.")] + [ObsoletedOSPlatform("tvos12.0", "Use 'Metal' instead.")] + [SupportedOSPlatform("ios")] + [SupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("macos")] [DesignTimeVisible(true)] #if HAS_UNO internal