From d3304139bd091a33b57e4db75abdf60ce87af98e Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 9 Jul 2020 07:13:09 +0200 Subject: [PATCH 1/6] Use SkiaSharp V2 --- build/HarfBuzzSharp.props | 4 ++-- build/SkiaSharp.props | 4 ++-- src/Skia/Avalonia.Skia/FormattedTextImpl.cs | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props index 873048ef21..88c4d36282 100644 --- a/build/HarfBuzzSharp.props +++ b/build/HarfBuzzSharp.props @@ -1,6 +1,6 @@  - - + + diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props index 4def44cbd0..a8d9332c57 100644 --- a/build/SkiaSharp.props +++ b/build/SkiaSharp.props @@ -1,6 +1,6 @@  - - + + diff --git a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs index ade659f5eb..d1f8d6a779 100644 --- a/src/Skia/Avalonia.Skia/FormattedTextImpl.cs +++ b/src/Skia/Avalonia.Skia/FormattedTextImpl.cs @@ -35,6 +35,7 @@ namespace Avalonia.Skia IsAntialias = true, LcdRenderText = true, SubpixelText = true, + IsLinearText = true, Typeface = glyphTypeface.Typeface, TextSize = (float)fontSize, TextAlign = textAlignment.ToSKTextAlign() From 0555f218d320deb35f4b1baec24a701cf37c5d61 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 9 Jul 2020 19:26:04 +0200 Subject: [PATCH 2/6] Remove obsolete SkiaSharp members --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 6 +++--- .../Gpu/OpenGl/GlRenderTarget.cs | 4 ++-- .../Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs | 11 +++++----- .../Avalonia.Skia/PlatformRenderInterface.cs | 20 +++++++++---------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index a510763f64..d818e683c3 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -629,8 +629,8 @@ namespace Avalonia.Skia var tileTransform = tileBrush.TileMode != TileMode.None - ? SKMatrix.MakeTranslation(-(float)calc.DestinationRect.X, -(float)calc.DestinationRect.Y) - : SKMatrix.MakeIdentity(); + ? SKMatrix.CreateTranslation(-(float)calc.DestinationRect.X, -(float)calc.DestinationRect.Y) + : SKMatrix.CreateIdentity(); SKShaderTileMode tileX = tileBrush.TileMode == TileMode.None @@ -655,7 +655,7 @@ namespace Avalonia.Skia SKMatrix.Concat( ref paintTransform, tileTransform, - SKMatrix.MakeScale((float)(96.0 / _dpi.X), (float)(96.0 / _dpi.Y))); + SKMatrix.CreateScale((float)(96.0 / _dpi.X), (float)(96.0 / _dpi.Y))); using (var shader = image.ToShader(tileX, tileY, paintTransform)) { diff --git a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs index 9b73174006..e0b7019672 100644 --- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlRenderTarget.cs @@ -82,10 +82,10 @@ namespace Avalonia.Skia var renderTarget = new GRBackendRenderTarget(size.Width, size.Height, disp.SampleCount, disp.StencilSize, - new GRGlFramebufferInfo((uint)fb, GRPixelConfig.Rgba8888.ToGlSizedFormat())); + new GRGlFramebufferInfo((uint)fb, SKColorType.Rgba8888.ToGlSizedFormat())); var surface = SKSurface.Create(_grContext, renderTarget, glSession.IsYFlipped ? GRSurfaceOrigin.TopLeft : GRSurfaceOrigin.BottomLeft, - GRPixelConfig.Rgba8888.ToColorType()); + SKColorType.Rgba8888); success = true; return new GlGpuSession(_grContext, renderTarget, surface, glSession); diff --git a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs index de188f42bd..9278de2137 100644 --- a/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs +++ b/src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs @@ -15,19 +15,18 @@ namespace Avalonia.Skia using (context.MakeCurrent()) { using (var iface = context.Version.Type == GlProfileType.OpenGL ? - GRGlInterface.AssembleGlInterface((_, proc) => context.GlInterface.GetProcAddress(proc)) : - GRGlInterface.AssembleGlesInterface((_, proc) => context.GlInterface.GetProcAddress(proc))) + GRGlInterface.CreateOpenGl(proc => context.GlInterface.GetProcAddress(proc)) : + GRGlInterface.CreateGles(proc => context.GlInterface.GetProcAddress(proc))) { - _grContext = GRContext.Create(GRBackend.OpenGL, iface); + _grContext = GRContext.CreateGl(iface); if (maxResourceBytes.HasValue) { - _grContext.GetResourceCacheLimits(out var maxResources, out _); - _grContext.SetResourceCacheLimits(maxResources, maxResourceBytes.Value); + _grContext.SetResourceCacheLimit(maxResourceBytes.Value); } } } } - + public ISkiaGpuRenderTarget TryCreateRenderTarget(IEnumerable surfaces) { foreach (var surface in surfaces) diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index 0bc5dd56ac..66b7fdea13 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -157,12 +157,12 @@ namespace Avalonia.Skia return new WriteableBitmapImpl(size, dpi, format); } - private static readonly SKPaint s_paint = new SKPaint + private static readonly SKFont s_font = new SKFont { - TextEncoding = SKTextEncoding.GlyphId, - IsAntialias = true, - IsStroke = false, - SubpixelText = true + Subpixel = true, + Edging = SKFontEdging.Antialias, + Hinting = SKFontHinting.Full, + LinearMetrics = true }; private static readonly SKTextBlobBuilder s_textBlobBuilder = new SKTextBlobBuilder(); @@ -176,8 +176,8 @@ namespace Avalonia.Skia var typeface = glyphTypeface.Typeface; - s_paint.TextSize = (float)glyphRun.FontRenderingEmSize; - s_paint.Typeface = typeface; + s_font.Size = (float)glyphRun.FontRenderingEmSize; + s_font.Typeface = typeface; SKTextBlob textBlob; @@ -190,7 +190,7 @@ namespace Avalonia.Skia { if (glyphTypeface.IsFixedPitch) { - s_textBlobBuilder.AddRun(s_paint, 0, 0, glyphRun.GlyphIndices.Buffer.Span); + s_textBlobBuilder.AddRun(glyphRun.GlyphIndices.Buffer.Span, s_font); textBlob = s_textBlobBuilder.Build(); @@ -198,7 +198,7 @@ namespace Avalonia.Skia } else { - var buffer = s_textBlobBuilder.AllocateHorizontalRun(s_paint, count, 0); + var buffer = s_textBlobBuilder.AllocateHorizontalRun(s_font, count, 0); var positions = buffer.GetPositionSpan(); @@ -223,7 +223,7 @@ namespace Avalonia.Skia } else { - var buffer = s_textBlobBuilder.AllocatePositionedRun(s_paint, count); + var buffer = s_textBlobBuilder.AllocatePositionedRun(s_font, count); var glyphPositions = buffer.GetPositionSpan(); From af8acfce0dbab0864affb5bc8ee4e45bc8c9f4a9 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 9 Jul 2020 21:49:34 +0200 Subject: [PATCH 3/6] Prevent crashes caused by null locked framebuffer. --- src/Windows/Avalonia.Win32/FramebufferManager.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Windows/Avalonia.Win32/FramebufferManager.cs b/src/Windows/Avalonia.Win32/FramebufferManager.cs index 87c5a1bb02..f4c3a80799 100644 --- a/src/Windows/Avalonia.Win32/FramebufferManager.cs +++ b/src/Windows/Avalonia.Win32/FramebufferManager.cs @@ -17,16 +17,18 @@ namespace Avalonia.Win32 public ILockedFramebuffer Lock() { - UnmanagedMethods.RECT rc; - UnmanagedMethods.GetClientRect(_hwnd, out rc); - var width = rc.right - rc.left; - var height = rc.bottom - rc.top; - if ((_fb == null || _fb.Size.Width != width || _fb.Size.Height != height) && width > 0 && height > 0) + UnmanagedMethods.GetClientRect(_hwnd, out var rc); + + var width = Math.Max(1, rc.right - rc.left); + var height = Math.Max(1, rc.bottom - rc.top); + + if ((_fb == null || _fb.Size.Width != width || _fb.Size.Height != height)) { _fb?.Deallocate(); _fb = null; _fb = new WindowFramebuffer(_hwnd, new PixelSize(width, height)); } + return _fb; } } From 1d94f80f7f4392479e1311992db610d89d79100d Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 9 Jul 2020 23:00:46 +0200 Subject: [PATCH 4/6] Dispose window framebuffers. --- src/Shared/PlatformSupport/StandardRuntimePlatform.cs | 10 +++++++--- src/Windows/Avalonia.Win32/FramebufferManager.cs | 8 +++++++- src/Windows/Avalonia.Win32/WindowImpl.cs | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs b/src/Shared/PlatformSupport/StandardRuntimePlatform.cs index 03832d3063..d574732e3d 100644 --- a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs +++ b/src/Shared/PlatformSupport/StandardRuntimePlatform.cs @@ -86,11 +86,15 @@ namespace Avalonia.Shared.PlatformSupport #if DEBUG if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId) { - lock(_lock) + lock (_lock) + { if (!IsDisposed) + { Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: " - + Environment.StackTrace - + "\n\nBlob created by " + _backtrace); + + Environment.StackTrace + + "\n\nBlob created by " + _backtrace); + } + } } #endif DoDispose(); diff --git a/src/Windows/Avalonia.Win32/FramebufferManager.cs b/src/Windows/Avalonia.Win32/FramebufferManager.cs index f4c3a80799..6969a49dad 100644 --- a/src/Windows/Avalonia.Win32/FramebufferManager.cs +++ b/src/Windows/Avalonia.Win32/FramebufferManager.cs @@ -5,7 +5,7 @@ using Avalonia.Win32.Interop; namespace Avalonia.Win32 { - class FramebufferManager : IFramebufferPlatformSurface + class FramebufferManager : IFramebufferPlatformSurface, IDisposable { private readonly IntPtr _hwnd; private WindowFramebuffer _fb; @@ -31,5 +31,11 @@ namespace Avalonia.Win32 return _fb; } + + public void Dispose() + { + _fb?.Deallocate(); + _fb = null; + } } } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 6e9cb81b11..0ee1342d27 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -389,6 +389,8 @@ namespace Avalonia.Win32 UnregisterClass(_className, GetModuleHandle(null)); _className = null; } + + _framebuffer.Dispose(); } public void Invalidate(Rect rect) From 5d8f54ac42419ea23161a1a53a8948360acdaf6a Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 9 Jul 2020 23:12:05 +0200 Subject: [PATCH 5/6] Fix hardcoded thumb min length. --- src/Avalonia.Controls/Primitives/Track.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Avalonia.Controls/Primitives/Track.cs b/src/Avalonia.Controls/Primitives/Track.cs index c91adaa26e..29e7f28b44 100644 --- a/src/Avalonia.Controls/Primitives/Track.cs +++ b/src/Avalonia.Controls/Primitives/Track.cs @@ -353,6 +353,15 @@ namespace Avalonia.Controls.Primitives var trackLength = isVertical ? arrangeSize.Height : arrangeSize.Width; double thumbMinLength = 10; + StyledProperty minLengthProperty = isVertical ? MinHeightProperty : MinWidthProperty; + + var thumb = Thumb; + + if (thumb != null && thumb.IsSet(minLengthProperty)) + { + thumbMinLength = thumb.GetValue(minLengthProperty); + } + thumbLength = trackLength * viewportSize / extent; CoerceLength(ref thumbLength, trackLength); thumbLength = Math.Max(thumbMinLength, thumbLength); From 1ae75006911c94718653246c20a6f72760bc5945 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 10 Jul 2020 14:17:01 +0300 Subject: [PATCH 6/6] Fix X11 screens implementation for some old/weird setups --- src/Avalonia.X11/X11Screens.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index e247a4241a..af6d2674b6 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -48,9 +48,13 @@ namespace Avalonia.X11 var pwa = (IntPtr*)prop; var wa = new PixelRect(pwa[0].ToInt32(), pwa[1].ToInt32(), pwa[2].ToInt32(), pwa[3].ToInt32()); - - foreach (var s in screens) + + foreach (var s in screens) + { s.WorkingArea = s.Bounds.Intersect(wa); + if (s.WorkingArea.Width <= 0 || s.WorkingArea.Height <= 0) + s.WorkingArea = s.Bounds; + } XFree(prop); return screens; @@ -134,8 +138,14 @@ namespace Avalonia.X11 settings.GlobalScaleFactor) }); } - - Screens = new[] {new X11Screen(new PixelRect(0, 0, 1920, 1280), true, "Default", null, settings.GlobalScaleFactor)}; + else + { + Screens = new[] + { + new X11Screen(new PixelRect(0, 0, 1920, 1280), true, "Default", null, + settings.GlobalScaleFactor) + }; + } } public X11Screen[] Screens { get; }