From b83991fdb6a10c021c6badc5d06cc19357e28c79 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 16 Oct 2016 17:36:37 +0100 Subject: [PATCH 01/11] Implemented Skia DPI scaling. Has a workaround for bug in DrawingContext. --- .../Avalonia.Skia.Desktop/RenderTarget.cs | 34 ++++++++++++++++++- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 20 +++++++---- .../Avalonia.Skia/WindowDrawingContextImpl.cs | 4 +-- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs index 5b61042655..a53f57a968 100644 --- a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs +++ b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs @@ -79,6 +79,31 @@ namespace Avalonia.Skia #endif } +#if WIN32 + private Size GetWindowDpi() + { + if (UnmanagedMethods.ShCoreAvailable) + { + uint dpix, dpiy; + + var monitor = UnmanagedMethods.MonitorFromWindow( + _hwnd.Handle, + UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST); + + if (UnmanagedMethods.GetDpiForMonitor( + monitor, + UnmanagedMethods.MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, + out dpix, + out dpiy) == 0) + { + return new Size(dpix, dpiy); + } + } + + return new Size(96, 96); + } +#endif + public override DrawingContext CreateDrawingContext() { FixSize(); @@ -89,9 +114,16 @@ namespace Avalonia.Skia canvas.Clear(SKColors.Red); canvas.ResetMatrix(); + double scale = 1.0; + +#if WIN32 + var dpi = GetWindowDpi(); + scale = dpi.Width / 96.0; +#endif + return new DrawingContext( - new WindowDrawingContextImpl(this)); + new WindowDrawingContextImpl(this, scale)); } public void Present() diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 7744e15104..0d8e2a6436 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -11,13 +11,19 @@ namespace Avalonia.Skia internal class DrawingContextImpl : IDrawingContextImpl { private Stack maskStack = new Stack(); - + private Matrix _dpiScaleMatrix; + private Matrix _currentTransform = Matrix.Identity; + public SKCanvas Canvas { get; private set; } - public DrawingContextImpl(SKCanvas canvas) + public DrawingContextImpl(SKCanvas canvas, double scale = 1.0) { Canvas = canvas; Canvas.Clear(); + + _dpiScaleMatrix = Matrix.CreateScale(scale, scale); + + _currentTransform = Matrix.Identity * _dpiScaleMatrix; } public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) @@ -342,9 +348,7 @@ namespace Avalonia.Skia } Canvas.Restore(); Canvas.Restore(); - } - - private Matrix _currentTransform = Matrix.Identity; + } public Matrix Transform { @@ -355,7 +359,11 @@ namespace Avalonia.Skia return; _currentTransform = value; - Canvas.SetMatrix(value.ToSKMatrix()); + + // TODO this line is a workaround for bug in DrawingContext.cs + _currentTransform *= _dpiScaleMatrix; + + Canvas.SetMatrix(_currentTransform.ToSKMatrix()); } } } diff --git a/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs b/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs index a4e29fc022..2ab5433063 100644 --- a/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs @@ -6,8 +6,8 @@ namespace Avalonia.Skia { WindowRenderTarget _target; - public WindowDrawingContextImpl(WindowRenderTarget target) - : base(target.Surface.Canvas) + public WindowDrawingContextImpl(WindowRenderTarget target, double scale = 1.0) + : base(target.Surface.Canvas, scale) { _target = target; } From b7f7775906ac36b27a15c292ef1c597953611757 Mon Sep 17 00:00:00 2001 From: danwalmsley Date: Mon, 17 Oct 2016 10:49:11 +0100 Subject: [PATCH 02/11] DPI Scaling handled via RenderTarget and not DrawingContextImpl. --- src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs | 9 +++++++-- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 12 ++---------- src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs | 4 ++-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs index a53f57a968..67ca727bc5 100644 --- a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs +++ b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs @@ -121,9 +121,14 @@ namespace Avalonia.Skia scale = dpi.Width / 96.0; #endif - return + var result = new DrawingContext( - new WindowDrawingContextImpl(this, scale)); + new WindowDrawingContextImpl(this)); + + result.PushPreTransform(Matrix.CreateScale(scale, scale)); + result.PushTransformContainer(); + + return result; } public void Present() diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 0d8e2a6436..00b39313c3 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -11,19 +11,14 @@ namespace Avalonia.Skia internal class DrawingContextImpl : IDrawingContextImpl { private Stack maskStack = new Stack(); - private Matrix _dpiScaleMatrix; private Matrix _currentTransform = Matrix.Identity; public SKCanvas Canvas { get; private set; } - public DrawingContextImpl(SKCanvas canvas, double scale = 1.0) + public DrawingContextImpl(SKCanvas canvas) { Canvas = canvas; Canvas.Clear(); - - _dpiScaleMatrix = Matrix.CreateScale(scale, scale); - - _currentTransform = Matrix.Identity * _dpiScaleMatrix; } public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) @@ -360,10 +355,7 @@ namespace Avalonia.Skia _currentTransform = value; - // TODO this line is a workaround for bug in DrawingContext.cs - _currentTransform *= _dpiScaleMatrix; - - Canvas.SetMatrix(_currentTransform.ToSKMatrix()); + Canvas.SetMatrix(value.ToSKMatrix()); } } } diff --git a/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs b/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs index 2ab5433063..a4e29fc022 100644 --- a/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/WindowDrawingContextImpl.cs @@ -6,8 +6,8 @@ namespace Avalonia.Skia { WindowRenderTarget _target; - public WindowDrawingContextImpl(WindowRenderTarget target, double scale = 1.0) - : base(target.Surface.Canvas, scale) + public WindowDrawingContextImpl(WindowRenderTarget target) + : base(target.Surface.Canvas) { _target = target; } From abb45f14420634464f5a1352d7276ac3029d6eec Mon Sep 17 00:00:00 2001 From: danwalmsley Date: Mon, 17 Oct 2016 10:59:25 +0100 Subject: [PATCH 03/11] Remov #if WIN32 by using IRuntimePlatformService to detect OS. --- src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs index 67ca727bc5..1e0f63c0f1 100644 --- a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs +++ b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs @@ -116,11 +116,19 @@ namespace Avalonia.Skia double scale = 1.0; -#if WIN32 - var dpi = GetWindowDpi(); - scale = dpi.Width / 96.0; -#endif + var runtimeService = AvaloniaLocator.Current.GetService(); + if (runtimeService != null) + { + switch (runtimeService.GetRuntimeInfo().OperatingSystem) + { + case OperatingSystemType.WinNT: + var dpi = GetWindowDpi(); + scale = dpi.Width / 96.0; + break; + } + } + var result = new DrawingContext( new WindowDrawingContextImpl(this)); From 71ee09c650d5f447cf3753ec6a23188ca1eac1b7 Mon Sep 17 00:00:00 2001 From: danwalmsley Date: Mon, 17 Oct 2016 11:01:42 +0100 Subject: [PATCH 04/11] Reset DrawingContextImpl. --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 00b39313c3..7744e15104 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -11,8 +11,7 @@ namespace Avalonia.Skia internal class DrawingContextImpl : IDrawingContextImpl { private Stack maskStack = new Stack(); - private Matrix _currentTransform = Matrix.Identity; - + public SKCanvas Canvas { get; private set; } public DrawingContextImpl(SKCanvas canvas) @@ -343,7 +342,9 @@ namespace Avalonia.Skia } Canvas.Restore(); Canvas.Restore(); - } + } + + private Matrix _currentTransform = Matrix.Identity; public Matrix Transform { @@ -354,7 +355,6 @@ namespace Avalonia.Skia return; _currentTransform = value; - Canvas.SetMatrix(value.ToSKMatrix()); } } From 52656a4749cd487365b43e972b580cbdc496a83f Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 18 Oct 2016 20:10:52 +0300 Subject: [PATCH 05/11] Additional transform for drawing context --- src/Avalonia.SceneGraph/Media/DrawingContext.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.SceneGraph/Media/DrawingContext.cs b/src/Avalonia.SceneGraph/Media/DrawingContext.cs index 9fd8761ca5..c19856e62f 100644 --- a/src/Avalonia.SceneGraph/Media/DrawingContext.cs +++ b/src/Avalonia.SceneGraph/Media/DrawingContext.cs @@ -12,6 +12,9 @@ namespace Avalonia.Media { private readonly IDrawingContextImpl _impl; private int _currentLevel; + //Internal tranformation that is applied but not exposed anywhere + //To be used for DPI scaling, etc + private Matrix? _hiddenPostTransform = Matrix.Identity; @@ -36,7 +39,7 @@ namespace Avalonia.Media } } - public DrawingContext(IDrawingContextImpl impl) + public DrawingContext(IDrawingContextImpl impl, Matrix? hiddenPostTransform = null) { _impl = impl; } @@ -55,10 +58,16 @@ namespace Avalonia.Media private set { _currentTransform = value; - _impl.Transform = _currentTransform*_currentContainerTransform; + var transform = _currentTransform*_currentContainerTransform; + if (_hiddenPostTransform.HasValue) + transform = transform*_hiddenPostTransform.Value; + _impl.Transform = transform; } } + //HACK: This is a temporary hack that is used in the render loop + //to update TransformedBounds property + [Obsolete("HACK for render loop, don't use")] internal Matrix CurrentContainerTransform => _currentContainerTransform; /// From e78c2b056034e28657b15c8512222ce1d82d423b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Oct 2016 18:30:31 +0100 Subject: [PATCH 06/11] Copy hidden matrix from contructor to field. --- src/Avalonia.SceneGraph/Media/DrawingContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.SceneGraph/Media/DrawingContext.cs b/src/Avalonia.SceneGraph/Media/DrawingContext.cs index c19856e62f..3ef537292f 100644 --- a/src/Avalonia.SceneGraph/Media/DrawingContext.cs +++ b/src/Avalonia.SceneGraph/Media/DrawingContext.cs @@ -42,6 +42,7 @@ namespace Avalonia.Media public DrawingContext(IDrawingContextImpl impl, Matrix? hiddenPostTransform = null) { _impl = impl; + _hiddenPostTransform = hiddenPostTransform; } From e5aea92c4ba89361cf1e0088d3f4ba6a0edd3ce6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Oct 2016 18:31:09 +0100 Subject: [PATCH 07/11] Using hidden matrix to scale the screen to correct dpi. --- src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs index 1e0f63c0f1..961dc2b92b 100644 --- a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs +++ b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs @@ -128,14 +128,11 @@ namespace Avalonia.Skia break; } } - + var result = new DrawingContext( - new WindowDrawingContextImpl(this)); - - result.PushPreTransform(Matrix.CreateScale(scale, scale)); - result.PushTransformContainer(); - + new WindowDrawingContextImpl(this), Matrix.CreateScale(scale, scale)); + return result; } From ab9c656ce2f8563a63b5b72eefaf48eac8cf88af Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Oct 2016 18:59:12 +0100 Subject: [PATCH 08/11] made obselete a warning --- src/Avalonia.SceneGraph/Media/DrawingContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.SceneGraph/Media/DrawingContext.cs b/src/Avalonia.SceneGraph/Media/DrawingContext.cs index 3ef537292f..1113d01b07 100644 --- a/src/Avalonia.SceneGraph/Media/DrawingContext.cs +++ b/src/Avalonia.SceneGraph/Media/DrawingContext.cs @@ -68,7 +68,7 @@ namespace Avalonia.Media //HACK: This is a temporary hack that is used in the render loop //to update TransformedBounds property - [Obsolete("HACK for render loop, don't use")] + [Obsolete("HACK for render loop, don't use", false)] internal Matrix CurrentContainerTransform => _currentContainerTransform; /// From 4d69be45312cc83c16a7f95b28565459f6dd40e7 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Oct 2016 19:04:56 +0100 Subject: [PATCH 09/11] disable warning for obsolete --- src/Avalonia.SceneGraph/Media/DrawingContext.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.SceneGraph/Media/DrawingContext.cs b/src/Avalonia.SceneGraph/Media/DrawingContext.cs index 1113d01b07..43ee65de16 100644 --- a/src/Avalonia.SceneGraph/Media/DrawingContext.cs +++ b/src/Avalonia.SceneGraph/Media/DrawingContext.cs @@ -68,8 +68,10 @@ namespace Avalonia.Media //HACK: This is a temporary hack that is used in the render loop //to update TransformedBounds property - [Obsolete("HACK for render loop, don't use", false)] + #pragma warning disable 0618 + [Obsolete("HACK for render loop, don't use")] internal Matrix CurrentContainerTransform => _currentContainerTransform; + #pragma warning restore 0618 /// /// Draws a bitmap image. From 0188d7cd08f433e3e8a8e1c5b93e2db51a52092a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Oct 2016 19:17:35 +0100 Subject: [PATCH 10/11] fixed warning suppression for obsolete error. --- src/Avalonia.SceneGraph/Media/DrawingContext.cs | 4 +--- src/Avalonia.SceneGraph/Rendering/RendererMixin.cs | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.SceneGraph/Media/DrawingContext.cs b/src/Avalonia.SceneGraph/Media/DrawingContext.cs index 43ee65de16..ddaa681bab 100644 --- a/src/Avalonia.SceneGraph/Media/DrawingContext.cs +++ b/src/Avalonia.SceneGraph/Media/DrawingContext.cs @@ -68,10 +68,8 @@ namespace Avalonia.Media //HACK: This is a temporary hack that is used in the render loop //to update TransformedBounds property - #pragma warning disable 0618 [Obsolete("HACK for render loop, don't use")] - internal Matrix CurrentContainerTransform => _currentContainerTransform; - #pragma warning restore 0618 + internal Matrix CurrentContainerTransform => _currentContainerTransform; /// /// Draws a bitmap image. diff --git a/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs b/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs index 416cdb9855..f5dc3c4566 100644 --- a/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs +++ b/src/Avalonia.SceneGraph/Rendering/RendererMixin.cs @@ -124,8 +124,12 @@ namespace Avalonia.Rendering using (context.PushTransformContainer()) { visual.Render(context); + +#pragma warning disable 0618 var transformed = new TransformedBounds(bounds, new Rect(), context.CurrentContainerTransform); +#pragma warning restore 0618 + if (visual is Visual) { BoundsTracker.SetTransformedBounds((Visual)visual, transformed); From 83b0714f3be8a39bbfba5a823af4903ca15d2ca7 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 18 Oct 2016 21:27:44 +0100 Subject: [PATCH 11/11] Removed pointless #ifdef --- src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs index 961dc2b92b..ef5fb88142 100644 --- a/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs +++ b/src/Skia/Avalonia.Skia.Desktop/RenderTarget.cs @@ -79,8 +79,7 @@ namespace Avalonia.Skia #endif } -#if WIN32 - private Size GetWindowDpi() + private Size GetWindowDpiWin32() { if (UnmanagedMethods.ShCoreAvailable) { @@ -102,7 +101,6 @@ namespace Avalonia.Skia return new Size(96, 96); } -#endif public override DrawingContext CreateDrawingContext() { @@ -123,7 +121,7 @@ namespace Avalonia.Skia switch (runtimeService.GetRuntimeInfo().OperatingSystem) { case OperatingSystemType.WinNT: - var dpi = GetWindowDpi(); + var dpi = GetWindowDpiWin32(); scale = dpi.Width / 96.0; break; }