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 81e91378e3..8b1a067929 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 @@ -1,19 +1,127 @@ using System; using Microsoft.Maui.Handlers; +using SkiaSharp.Views.iOS; +using SkiaSharp.Views.Maui.Platform; using UIKit; namespace SkiaSharp.Views.Maui.Handlers { - public partial class SKGLViewHandler : ViewHandler + 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."); + private SKSizeI lastCanvasSize; + private GRContext? lastGRContext; + private SKTouchHandler? touchHandler; - public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) { } + protected override SKMetalView CreatePlatformView() => + new MauiSKMetalView + { + BackgroundColor = UIColor.Clear, + Opaque = false, + }; - public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) { } + protected override void ConnectHandler(SKMetalView platformView) + { + platformView.PaintSurface += OnPaintSurface; - public static void MapEnableTouchEvents(SKGLViewHandler handler, ISKGLView view) { } + base.ConnectHandler(platformView); + } - public static void OnInvalidateSurface(SKGLViewHandler handler, ISKGLView view, object? args) { } + protected override void DisconnectHandler(SKMetalView 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.Paused && handler.PlatformView.EnableSetNeedsDisplay) + handler.PlatformView.SetNeedsDisplay(); + } + + public static void MapIgnorePixelScaling(SKGLViewHandler handler, ISKGLView view) + { + if (handler.PlatformView is MauiSKMetalView pv) + { + pv.IgnorePixelScaling = view.IgnorePixelScaling; + handler.PlatformView.SetNeedsDisplay(); + } + } + + public static void MapHasRenderLoop(SKGLViewHandler handler, ISKGLView view) + { + handler.PlatformView.Paused = !view.HasRenderLoop; + handler.PlatformView.EnableSetNeedsDisplay = !view.HasRenderLoop; + } + + 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.SKPaintMetalSurfaceEventArgs e) + { + var newCanvasSize = e.Info.Size; + if (lastCanvasSize != newCanvasSize) + { + lastCanvasSize = newCanvasSize; + VirtualView?.OnCanvasSizeChanged(newCanvasSize); + } + if (sender is SKMetalView 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 MauiSKMetalView : SKMetalView + { + public bool IgnorePixelScaling { get; set; } + + protected override void OnPaintSurface(iOS.SKPaintMetalSurfaceEventArgs 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.SKPaintMetalSurfaceEventArgs(e.Surface, e.BackendRenderTarget, e.Origin, e.Info.WithSize(userVisibleSize), e.Info); + } + + base.OnPaintSurface(e); + } + } } } diff --git a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj index d325665ab0..2fd3ed249a 100644 --- a/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj +++ b/source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI/SkiaSharp.Views.Uno.WinUI.csproj @@ -65,7 +65,7 @@ - + diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs index 2630aca7dd..4df486b4e5 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/GlesInterop/Gles.cs @@ -1,4 +1,4 @@ -#if !__WASM__ && (!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__))) +#if !__WASM__ && (!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__))) && !MACCATALYST // Note that `(!UNO_REFERENCE_API || (NET6_0_OR_GREATER && (__IOS__ || __MACOS__)))` is required // because of https://github.com/unoplatform/uno/issues/8814, where !UNO_REFERENCE_API should be enough. diff --git a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs index 08122bdccf..cc86bfb368 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views.Shared/SKPaintGLSurfaceEventArgs.cs @@ -1,4 +1,5 @@ -using System; +#if !MACCATALYST || HAS_UNO_WINUI +using System; using System.ComponentModel; #if HAS_UNO_WINUI @@ -68,3 +69,4 @@ public SKPaintGLSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget render public SKImageInfo RawInfo { get; private set; } } } +#endif diff --git a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs index b81803f403..fa840facd4 100644 --- a/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs +++ b/source/SkiaSharp.Views/SkiaSharp.Views/Platform/Apple/SKPaintMetalSurfaceEventArgs.cs @@ -20,6 +20,23 @@ public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget ren BackendRenderTarget = renderTarget; ColorType = colorType; Origin = origin; + Info = new SKImageInfo(renderTarget.Width, renderTarget.Height, ColorType); + RawInfo = Info; + } + + public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget renderTarget, GRSurfaceOrigin origin, SKImageInfo info) + : this(surface, renderTarget, origin, info, info) + { + } + + public SKPaintMetalSurfaceEventArgs(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; } @@ -29,6 +46,10 @@ public SKPaintMetalSurfaceEventArgs(SKSurface surface, GRBackendRenderTarget ren public SKColorType ColorType { get; private set; } public GRSurfaceOrigin Origin { get; private set; } + + public SKImageInfo Info { get; private set; } + + public SKImageInfo RawInfo { get; private set; } } } #endif