From 27cdbc572d9b450cb89266a4ad4294a4c3c6a925 Mon Sep 17 00:00:00 2001 From: psyGamer Date: Sat, 26 Oct 2024 21:53:00 +0200 Subject: [PATCH] refactor(Studio): Drop Eto.SkiaDraw dependency --- .../CelesteStudio.GTK.csproj | 4 +- .../CelesteStudio.Mac.csproj | 2 +- .../CelesteStudio.WPF.csproj | 2 +- Studio/CelesteStudio/CelesteStudio.csproj | 3 +- Studio/CelesteStudio/Controls/SkiaDrawable.cs | 43 +++++++++++++++++++ Studio/CelesteStudio/Editing/Editor.cs | 19 ++++---- .../Editing/SyntaxHighlighter.cs | 3 +- Studio/CelesteStudio/FontManager.cs | 20 ++++++--- 8 files changed, 77 insertions(+), 19 deletions(-) create mode 100644 Studio/CelesteStudio/Controls/SkiaDrawable.cs diff --git a/Studio/CelesteStudio.GTK/CelesteStudio.GTK.csproj b/Studio/CelesteStudio.GTK/CelesteStudio.GTK.csproj index 2e56291f..186f0531 100644 --- a/Studio/CelesteStudio.GTK/CelesteStudio.GTK.csproj +++ b/Studio/CelesteStudio.GTK/CelesteStudio.GTK.csproj @@ -20,7 +20,9 @@ - + + + diff --git a/Studio/CelesteStudio.Mac/CelesteStudio.Mac.csproj b/Studio/CelesteStudio.Mac/CelesteStudio.Mac.csproj index ffc95ed9..54e973a1 100644 --- a/Studio/CelesteStudio.Mac/CelesteStudio.Mac.csproj +++ b/Studio/CelesteStudio.Mac/CelesteStudio.Mac.csproj @@ -22,7 +22,7 @@ - + diff --git a/Studio/CelesteStudio.WPF/CelesteStudio.WPF.csproj b/Studio/CelesteStudio.WPF/CelesteStudio.WPF.csproj index 8d411839..b11b921a 100644 --- a/Studio/CelesteStudio.WPF/CelesteStudio.WPF.csproj +++ b/Studio/CelesteStudio.WPF/CelesteStudio.WPF.csproj @@ -21,7 +21,7 @@ - + diff --git a/Studio/CelesteStudio/CelesteStudio.csproj b/Studio/CelesteStudio/CelesteStudio.csproj index 6525d000..2a217fa4 100644 --- a/Studio/CelesteStudio/CelesteStudio.csproj +++ b/Studio/CelesteStudio/CelesteStudio.csproj @@ -23,10 +23,11 @@ - + + diff --git a/Studio/CelesteStudio/Controls/SkiaDrawable.cs b/Studio/CelesteStudio/Controls/SkiaDrawable.cs new file mode 100644 index 00000000..2881db85 --- /dev/null +++ b/Studio/CelesteStudio/Controls/SkiaDrawable.cs @@ -0,0 +1,43 @@ +using Eto; +using Eto.Drawing; +using Eto.Forms; +using SkiaSharp; +using System; + +namespace CelesteStudio.Controls; + +public abstract class SkiaDrawable : Drawable { + private readonly SKColorType colorType = Platform.Instance.IsWinForms || Platform.Instance.IsWpf ? SKColorType.Bgra8888 : SKColorType.Rgba8888; + + private Bitmap? image = null; + private SKImageInfo imageInfo = SKImageInfo.Empty; + + protected abstract void Draw(PaintEventArgs e, SKSurface surface, SKImageInfo info); + + protected override void OnPaint(PaintEventArgs e) + { + try { + if (Width <= 0 || Height <= 0) { + return; + } + + if (Size != image?.Size) + { + image?.Dispose(); + image = new Bitmap(Size, PixelFormat.Format32bppRgba); + imageInfo = new SKImageInfo(Width, Height, colorType, SKAlphaType.Unpremul); + } + + using var bmp = image.Lock(); + using var surface = SKSurface.Create(imageInfo, bmp.Data, bmp.ScanWidth); + + Draw(e, surface, imageInfo); + + e.Graphics.DrawImage(image, PointF.Empty); + } + catch (Exception ex) + { + e.Graphics.DrawText(Fonts.Monospace(12.0f), Colors.Red, PointF.Empty, ex.ToString()); + } + } +} diff --git a/Studio/CelesteStudio/Editing/Editor.cs b/Studio/CelesteStudio/Editing/Editor.cs index 96a47bdb..d0d6a3e1 100644 --- a/Studio/CelesteStudio/Editing/Editor.cs +++ b/Studio/CelesteStudio/Editing/Editor.cs @@ -7,13 +7,13 @@ using System.Threading; using System.Threading.Tasks; using CelesteStudio.Communication; +using CelesteStudio.Controls; using CelesteStudio.Data; using CelesteStudio.Dialog; using CelesteStudio.Editing.ContextActions; using CelesteStudio.Util; using Eto.Drawing; using Eto.Forms; -using Eto.SkiaDraw; using SkiaSharp; using StudioCommunication; using StudioCommunication.Util; @@ -3620,10 +3620,13 @@ private void UpdateMouseCursor(PointF location, Keys modifiers) { #region Drawing - protected override void OnPaint(SKPaintEventArgs e) { - var canvas = e.Surface.Canvas; + protected override void Draw(PaintEventArgs e, SKSurface surface, SKImageInfo imageInfo) { + var canvas = surface.Canvas; canvas.Clear(); + // Adjust unit to points instead of pixels + //canvas.Scale(e.Graphics.PixelsPerPoint); + // To be reused below. Kinda annoying how C# handles out parameter conflicts WrapEntry wrap; @@ -3740,7 +3743,7 @@ protected override void OnPaint(SKPaintEventArgs e) { suffixPaint.IsAntialias = true; canvas.DrawText(CommunicationWrapper.CurrentLineSuffix, x: scrollablePosition.X + scrollableSize.Width - suffixWidth - padding, - y: actualToVisualRows[CommunicationWrapper.CurrentLine] * font.LineHeight() - Font.Metrics.Ascent, + y: actualToVisualRows[CommunicationWrapper.CurrentLine] * font.LineHeight()+ Font.Offset(), suffixPaint); } @@ -3829,7 +3832,7 @@ protected override void OnPaint(SKPaintEventArgs e) { float h = Font.LineHeight(); canvas.DrawRoundRect(x, y, w, h, 4.0f, 4.0f, calcBgPaint); - canvas.DrawText(calculateLine, x + padding, y - Font.Metrics.Ascent, Font, calcFgPaint); + canvas.DrawText(calculateLine, x + padding, y+ Font.Offset(), Font, calcFgPaint); } // Draw line numbers @@ -3907,10 +3910,10 @@ protected override void OnPaint(SKPaintEventArgs e) { : Settings.Instance.Theme.LineNumber.ToSkia(); if (Settings.Instance.LineNumberAlignment == LineNumberAlignment.Left) { - canvas.DrawText(numberString, scrollablePosition.X + LineNumberPadding, yPos - Font.Metrics.Ascent, Font, textPaint); + canvas.DrawText(numberString, scrollablePosition.X + LineNumberPadding, yPos+ Font.Offset(), Font, textPaint); } else if (Settings.Instance.LineNumberAlignment == LineNumberAlignment.Right) { float ident = Font.CharWidth() * (Document.Lines.Count.Digits() - (row + 1).Digits()); - canvas.DrawText(numberString, scrollablePosition.X + LineNumberPadding + ident, yPos - Font.Metrics.Ascent, Font, textPaint); + canvas.DrawText(numberString, scrollablePosition.X + LineNumberPadding + ident, yPos+ Font.Offset(), Font, textPaint); } bool collapsed = false; @@ -3974,7 +3977,7 @@ protected override void OnPaint(SKPaintEventArgs e) { popupFgPaint.IsAntialias = true; foreach (var line in lines) { // TODO: Use PopupFont - canvas.DrawText(line, x, y - Font.Metrics.Ascent, Font, popupFgPaint); + canvas.DrawText(line, x, y+ Font.Offset(), Font, popupFgPaint); y += Font.LineHeight(); } } diff --git a/Studio/CelesteStudio/Editing/SyntaxHighlighter.cs b/Studio/CelesteStudio/Editing/SyntaxHighlighter.cs index 72721a5b..5de2fdcf 100644 --- a/Studio/CelesteStudio/Editing/SyntaxHighlighter.cs +++ b/Studio/CelesteStudio/Editing/SyntaxHighlighter.cs @@ -118,7 +118,8 @@ public void DrawLine(SKCanvas canvas, float x, float y, string line, DrawLineOpt textPaint.Color = style.ForegroundColor.ToSkia(); // textPaint.Style = SKPaintStyle.Fill; textPaint.IsAntialias = true; - canvas.DrawText(str, x + xOff, y - font.Metrics.Ascent, font, textPaint); + textPaint.TextAlign = SKTextAlign.Left; + canvas.DrawText(str, x + xOff, y + font.Offset(), font, textPaint); // } xOff += width; diff --git a/Studio/CelesteStudio/FontManager.cs b/Studio/CelesteStudio/FontManager.cs index d9df6006..19c763e5 100644 --- a/Studio/CelesteStudio/FontManager.cs +++ b/Studio/CelesteStudio/FontManager.cs @@ -26,7 +26,7 @@ public static class FontManager { public static Font StatusFont => statusFont ??= CreateStatus(); public static Font PopupFont => popupFont ??= CreatePopup(); - public static SKFont SKEditorFontRegular => skEditorFontRegular ??= CreateSKFont(Settings.Instance.FontFamily, Settings.Instance.EditorFontSize * Settings.Instance.FontZoom); + public static SKFont SKEditorFontRegular => skEditorFontRegular ??= CreateSKFont(Settings.Instance.FontFamily, Settings.Instance.EditorFontSize * Settings.Instance.FontZoom * (4.0f/3.0f)); private static FontFamily? builtinFontFamily; public static Font CreateFont(string fontFamily, float size, FontStyle style = FontStyle.None) { @@ -55,9 +55,13 @@ public static SKFont CreateSKFont(string fontFamily, float size) { if (fontFamily == FontFamilyBuiltin) { var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("JetBrainsMono/JetBrainsMono-Regular"); - return new SKFont(SKTypeface.FromStream(stream), size); + var typeface = SKTypeface.FromStream(stream); + + return new SKFont(typeface, size) { LinearMetrics = true }; } else { - return new SKFont(SKTypeface.FromFamilyName(fontFamily), size); + var typeface = SKTypeface.FromFamilyName(fontFamily, SKFontStyleWeight.Light, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright); + + return new SKFont(typeface, size) { LinearMetrics = true }; } } @@ -93,14 +97,18 @@ public static float CharWidth(this SKFont font) { return width; } - widthCache[font] = font.Metrics.AverageCharacterWidth; - return font.Metrics.AverageCharacterWidth; + widthCache[font] = width = font.Metrics.AverageCharacterWidth * font.ScaleX; + return width; } public static float MeasureWidth(this SKFont font, string text) { return font.CharWidth() * text.Length; } + // Apply +/- 1.0f for better visuals public static float LineHeight(this SKFont font) { - return font.Spacing; + return font.Spacing + 0.6f; + } + public static float Offset(this SKFont font) { + return -font.Metrics.Ascent + 0.7f; } public static void OnFontChanged() {