diff --git a/Studio/CelesteStudio.WPF/SkiaDrawableHandler.cs b/Studio/CelesteStudio.WPF/SkiaDrawableHandler.cs index 12445c93..e1247f7e 100644 --- a/Studio/CelesteStudio.WPF/SkiaDrawableHandler.cs +++ b/Studio/CelesteStudio.WPF/SkiaDrawableHandler.cs @@ -11,11 +11,11 @@ namespace CelesteStudio.WPF; public class SkiaDrawableHandler : WpfPanel, SkiaDrawable.IHandler { - public void Create() { + public void Create() { Control = new SkiaBorder(Widget); } - private class SkiaBorder(SkiaDrawable drawable) : Border { + private class SkiaBorder(SkiaDrawable drawable) : Border, IDisposable { private SKSurface? surface; private WriteableBitmap? bitmap; @@ -32,24 +32,37 @@ protected override void OnRender(DrawingContext drawingContext) { return; } - if (width != bitmap?.PixelWidth || height != bitmap?.PixelHeight) { - bitmap = new WriteableBitmap(width, height, dpiX, dpiY, PixelFormats.Pbgra32, null); + if (bitmap == null || surface == null || width != bitmap.PixelWidth || height != bitmap.PixelHeight) { + const double bitmapDpi = 96.0; + bitmap = new WriteableBitmap(width, height, bitmapDpi * dpiX, bitmapDpi * dpiY, PixelFormats.Pbgra32, null); surface?.Dispose(); - surface = SKSurface.Create(new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul), bitmap.BackBuffer, bitmap.BackBufferStride); + surface = SKSurface.Create(new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul), bitmap.BackBuffer, bitmap.BackBufferStride, new SKSurfaceProperties(SKPixelGeometry.Unknown)); + surface.Canvas.Scale((float)dpiX, (float)dpiY); + surface.Canvas.Save(); } bitmap.Lock(); - using (new SKAutoCanvasRestore(surface!.Canvas, true)) { + using (new SKAutoCanvasRestore(surface.Canvas, true)) { drawable.Draw(surface); } surface.Canvas.Flush(); bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height)); - drawingContext.DrawImage(bitmap, new Rect(drawable.DrawX, drawable.DrawY, width, height)); + drawingContext.DrawImage(bitmap, new Rect(drawable.DrawX, drawable.DrawY, width / dpiX, height / dpiY)); bitmap.Unlock(); } + + ~SkiaBorder() { + Dispose(); + } + public void Dispose() { + surface?.Dispose(); + surface = null; + + GC.SuppressFinalize(this); + } } public bool CanFocus { diff --git a/Studio/CelesteStudio/Dialog/ChangelogDialog.cs b/Studio/CelesteStudio/Dialog/ChangelogDialog.cs index 92f8681f..cd1ed622 100644 --- a/Studio/CelesteStudio/Dialog/ChangelogDialog.cs +++ b/Studio/CelesteStudio/Dialog/ChangelogDialog.cs @@ -29,16 +29,19 @@ public override void Draw(SKSurface surface) { titlePaint.ColorF = textColor; titlePaint.IsAntialias = true; titlePaint.TextAlign = SKTextAlign.Center; + titlePaint.SubpixelText = true; using var headingFont = new SKFont(SKTypeface.Default, 24.0f); using var headingPaint = new SKPaint(headingFont); headingPaint.ColorF = textColor; headingPaint.IsAntialias = true; + headingPaint.SubpixelText = true; using var entryFont = new SKFont(SKTypeface.Default, 13.0f); using var entryPaint = new SKPaint(entryFont); entryPaint.ColorF = textColor; entryPaint.IsAntialias = true; + entryPaint.SubpixelText = true; float yOffset = 0.0f; // Title diff --git a/Studio/CelesteStudio/Editing/Theme.cs b/Studio/CelesteStudio/Editing/Theme.cs index 7a7d3a3c..d501151f 100644 --- a/Studio/CelesteStudio/Editing/Theme.cs +++ b/Studio/CelesteStudio/Editing/Theme.cs @@ -11,7 +11,7 @@ public record struct Style(Color ForegroundColor, Color? BackgroundColor = null, public StylePaint CreatePaint() => new(CreateForegroundPaint(), CreateBackgroundPaint(), FontStyle); public SKPaint CreateForegroundPaint(SKPaintStyle style = SKPaintStyle.Fill) => - new() { ColorF = ForegroundColor.ToSkia(), Style = style, IsAntialias = true }; + new() { ColorF = ForegroundColor.ToSkia(), Style = style, IsAntialias = true, SubpixelText = true }; public SKPaint? CreateBackgroundPaint(SKPaintStyle style = SKPaintStyle.Fill) => BackgroundColor == null ? null : new() { ColorF = BackgroundColor.Value.ToSkia(), Style = style, IsAntialias = true }; } @@ -99,19 +99,19 @@ public class Theme { public SKPaint CommentBoxPaint => _commentBox ??= Comment.CreateForegroundPaint(SKPaintStyle.Stroke); [TomlNonSerialized] - public SKPaint StatusFgPaint => _statusFgPaint ??= new SKPaint { ColorF = StatusFg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint StatusFgPaint => _statusFgPaint ??= new SKPaint { ColorF = StatusFg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true, SubpixelText = true }; [TomlNonSerialized] - public SKPaint SubpixelIndicatorDotPaint => _subpixelIndicatorDotPaint ??= new SKPaint { ColorF = SubpixelIndicatorDot.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint SubpixelIndicatorDotPaint => _subpixelIndicatorDotPaint ??= new SKPaint { ColorF = SubpixelIndicatorDot.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true, SubpixelText = true }; [TomlNonSerialized] - public SKPaint PopupMenuFgPaint => _popupMenuFgPaint ??= new SKPaint { ColorF = PopupMenuFg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint PopupMenuFgPaint => _popupMenuFgPaint ??= new SKPaint { ColorF = PopupMenuFg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true, SubpixelText = true }; [TomlNonSerialized] - public SKPaint PopupMenuFgDisabledPaint => _popupMenuFgDisabledPaint ??= new SKPaint { ColorF = PopupMenuFgDisabled.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint PopupMenuFgDisabledPaint => _popupMenuFgDisabledPaint ??= new SKPaint { ColorF = PopupMenuFgDisabled.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true, SubpixelText = true }; [TomlNonSerialized] - public SKPaint PopupMenuFgExtraPaint => _popupMenuFgExtraPaint ??= new SKPaint { ColorF = PopupMenuFgExtra.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint PopupMenuFgExtraPaint => _popupMenuFgExtraPaint ??= new SKPaint { ColorF = PopupMenuFgExtra.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true, SubpixelText = true }; [TomlNonSerialized] - public SKPaint PopupMenuBgPaint => _popupMenuBgPaint ??= new SKPaint { ColorF = PopupMenuBg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint PopupMenuBgPaint => _popupMenuBgPaint ??= new SKPaint { ColorF = PopupMenuBg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true, SubpixelText = true }; [TomlNonSerialized] - public SKPaint PopupMenuSelectedPaint => _popupMenuSelectedPaint ??= new SKPaint { ColorF = PopupMenuSelected.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint PopupMenuSelectedPaint => _popupMenuSelectedPaint ??= new SKPaint { ColorF = PopupMenuSelected.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true, SubpixelText = true }; public void InvalidateCache() { _actionPaint?.Dispose();