From 86ff828568752b7a05bd1e4c5903235addf4e0ae Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 6 Nov 2019 06:39:44 +0100 Subject: [PATCH] Resolve merge conflicts --- samples/ControlCatalog/MainView.xaml | 1 - .../ControlCatalog/Pages/GlyphRunPage.xaml | 6 - .../ControlCatalog/Pages/GlyphRunPage.xaml.cs | 87 -------- .../Media/FormattedTextStyleSpan.cs | 4 +- src/Avalonia.Visuals/Platform/IFontManager.cs | 57 ------ src/Skia/Avalonia.Skia/FontManager.cs | 91 --------- src/Skia/Avalonia.Skia/TextRunIterator.cs | 5 +- .../Avalonia.Direct2D1/Direct2D1Platform.cs | 7 + .../Avalonia.Direct2D1/Media/FontManager.cs | 81 -------- .../Media/GlyphTypefaceImpl.cs | 188 ++++++++++++++++++ .../Media/TextRunIterator.cs | 5 +- .../FullLayoutTests.cs | 13 +- .../TextLayoutTests.cs | 90 ++++++--- ...kFontManager.cs => MockFontManagerImpl.cs} | 2 +- .../MockPlatformRenderInterface.cs | 2 +- tests/Avalonia.UnitTests/TestServices.cs | 13 +- .../Avalonia.UnitTests/UnitTestApplication.cs | 1 - 17 files changed, 270 insertions(+), 383 deletions(-) delete mode 100644 samples/ControlCatalog/Pages/GlyphRunPage.xaml delete mode 100644 samples/ControlCatalog/Pages/GlyphRunPage.xaml.cs delete mode 100644 src/Avalonia.Visuals/Platform/IFontManager.cs delete mode 100644 src/Skia/Avalonia.Skia/FontManager.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Media/FontManager.cs rename tests/Avalonia.UnitTests/{MockFontManager.cs => MockFontManagerImpl.cs} (94%) diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 41e8565a8ef5..874560a29442 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -50,7 +50,6 @@ - diff --git a/samples/ControlCatalog/Pages/GlyphRunPage.xaml b/samples/ControlCatalog/Pages/GlyphRunPage.xaml deleted file mode 100644 index c8813a919955..000000000000 --- a/samples/ControlCatalog/Pages/GlyphRunPage.xaml +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/samples/ControlCatalog/Pages/GlyphRunPage.xaml.cs b/samples/ControlCatalog/Pages/GlyphRunPage.xaml.cs deleted file mode 100644 index 7eeaf42f3c2c..000000000000 --- a/samples/ControlCatalog/Pages/GlyphRunPage.xaml.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Text; - -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; -using Avalonia.Media; - -namespace ControlCatalog.Pages -{ - public class GlyphRunPage : UserControl - { - public GlyphRunPage() - { - this.InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - public override void Render(DrawingContext drawingContext) - { - var glyphTypeface = Typeface.Default.GlyphTypeface; - - var bytes = Encoding.UTF32.GetBytes("1234567890"); - - var codePoints = new uint[bytes.Length / 4]; - - Buffer.BlockCopy(bytes, 0, codePoints, 0, bytes.Length); - - var glyphs = glyphTypeface.GetGlyphs(codePoints); - - var baselineOrigin = new Point(15, 15); - - for (var i = 12; i < 32; i++) - { - var spacing = i * 0.3; - - var scale = (double)i / glyphTypeface.DesignEmHeight; - - baselineOrigin += new Point(0, -glyphTypeface.Ascent * scale); - - var offsets = new Vector[10]; - - var offsetY = 0.0d; - - for (var j = 0; j < 5; j++) - { - offsets[j] = new Vector(0, offsetY++ * i * 0.06); - } - - var maxY = offsetY; - - for (var j = 5; j < 10; j++) - { - offsets[j] = new Vector(0, offsetY-- * i * 0.06); - } - - var advances = new double[10]; - - var width = 0.0; - - for (var j = 0; j < glyphs.Length; j++) - { - var advance = glyphTypeface.GetGlyphAdvance(glyphs[j]) * scale; - advances[j] = advance; - width += advance; - } - - var bounds = new Rect(baselineOrigin.X, baselineOrigin.Y + glyphTypeface.Ascent * scale + spacing / 2, width, - glyphTypeface.LineHeight * scale); - - var glyphRun = new GlyphRun(glyphTypeface, i, glyphs, advances, offsets, bounds: bounds); - - drawingContext.DrawGlyphRun(Brushes.Black, glyphRun, baselineOrigin); - - drawingContext.DrawRectangle(new Pen(Brushes.Orange), bounds); - - drawingContext.DrawLine(new Pen(Brushes.Blue), baselineOrigin, new Point(baselineOrigin.X + width, baselineOrigin.Y)); - - baselineOrigin += new Point(0, maxY + spacing); - } - } - } -} diff --git a/src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs b/src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs index f02ea14a64cf..35e26131b5cc 100644 --- a/src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs +++ b/src/Avalonia.Visuals/Media/FormattedTextStyleSpan.cs @@ -7,8 +7,6 @@ namespace Avalonia.Media /// public class FormattedTextStyleSpan { - private static readonly IFontManager s_fontManager = AvaloniaLocator.Current.GetService(); - /// /// Initializes a new instance of the class. /// @@ -82,7 +80,7 @@ private static Typeface GetTypeface(FontFamily fontFamily, FontWeight? fontWeigh fontStyle = FontStyle.Normal; } - return s_fontManager.GetTypeface(fontFamily, fontWeight.Value, fontStyle.Value); + return FontManager.Default.GetCachedTypeface(fontFamily, fontWeight.Value, fontStyle.Value); } } } diff --git a/src/Avalonia.Visuals/Platform/IFontManager.cs b/src/Avalonia.Visuals/Platform/IFontManager.cs deleted file mode 100644 index 91894ae2a494..000000000000 --- a/src/Avalonia.Visuals/Platform/IFontManager.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Generic; -using System.Globalization; -using Avalonia.Media; - -namespace Avalonia.Platform -{ - public interface IFontManager - { - /// - /// Gets the system's default font family's name. - /// - string DefaultFontFamilyName { get; } - - /// - /// Get all installed fonts in the system. - /// If true the font collection is updated. - /// - IEnumerable GetInstalledFontFamilyNames(bool checkForUpdates = false); - - /// - /// Creates a glyph typeface for specified typeface. - /// - /// The typeface. - /// - /// The glyph typeface implementation. - /// - IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface); - - /// - /// Get a typeface from specified parameters. - /// - /// The font family. - /// The font weight. - /// The font style. - /// - /// The typeface. - /// - Typeface GetTypeface(FontFamily fontFamily, FontWeight fontWeight, FontStyle fontStyle); - - /// - /// Tries to match a specified character to a typeface that supports specified font properties. - /// - /// The codepoint to match against. - /// The font weight. - /// The font style. - /// The font family. This is optional and used for fallback lookup. - /// The culture. - /// - /// The typeface. - /// - Typeface MatchCharacter(int codepoint, FontWeight fontWeight = default, FontStyle fontStyle = default, - FontFamily fontFamily = null, CultureInfo culture = null); - } -} diff --git a/src/Skia/Avalonia.Skia/FontManager.cs b/src/Skia/Avalonia.Skia/FontManager.cs deleted file mode 100644 index 31c7e6769bea..000000000000 --- a/src/Skia/Avalonia.Skia/FontManager.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using Avalonia.Media; -using Avalonia.Platform; -using SkiaSharp; - -namespace Avalonia.Skia -{ - internal class FontManager : IFontManager - { - private SKFontManager _skFontManager = SKFontManager.Default; - - private readonly ConcurrentDictionary _glyphTypefaceCache = - new ConcurrentDictionary(); - - public FontManager() - { - DefaultFontFamilyName = SKTypeface.Default.FamilyName; - } - - public string DefaultFontFamilyName { get; } - - public IEnumerable GetInstalledFontFamilyNames(bool checkForUpdates = false) - { - if (checkForUpdates) - { - _skFontManager = SKFontManager.CreateDefault(); - } - - return _skFontManager.FontFamilies; - } - - public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface) - { - return _glyphTypefaceCache.GetOrAdd(typeface, new GlyphTypefaceImpl(typeface)); - } - - public Typeface GetTypeface(FontFamily fontFamily, FontWeight fontWeight, FontStyle fontStyle) - { - return TypefaceCache.Get(fontFamily.Name, fontWeight, fontStyle).Typeface; - } - - public Typeface MatchCharacter(int codepoint, FontWeight fontWeight = default, FontStyle fontStyle = default, - FontFamily fontFamily = null, CultureInfo culture = null) - { - var fontFamilyName = FontFamily.Default.Name; - - if (culture == null) - { - culture = CultureInfo.CurrentUICulture; - } - - if (fontFamily != null) - { - foreach (var familyName in fontFamily.FamilyNames) - { - var skTypeface = _skFontManager.MatchCharacter(familyName, (SKFontStyleWeight)fontWeight, - SKFontStyleWidth.Normal, - (SKFontStyleSlant)fontStyle, - new[] { culture.TwoLetterISOLanguageName, culture.ThreeLetterISOLanguageName }, codepoint); - - if (skTypeface == null) - { - continue; - } - - fontFamilyName = familyName; - - break; - } - } - else - { - var skTypeface = _skFontManager.MatchCharacter(null, (SKFontStyleWeight)fontWeight, SKFontStyleWidth.Normal, - (SKFontStyleSlant)fontStyle, - new[] { culture.TwoLetterISOLanguageName, culture.ThreeLetterISOLanguageName }, codepoint); - - if (skTypeface != null) - { - fontFamilyName = skTypeface.FamilyName; - } - } - - return GetTypeface(fontFamilyName, fontWeight, fontStyle); - } - } -} diff --git a/src/Skia/Avalonia.Skia/TextRunIterator.cs b/src/Skia/Avalonia.Skia/TextRunIterator.cs index 766fad646662..e2b62986c6de 100644 --- a/src/Skia/Avalonia.Skia/TextRunIterator.cs +++ b/src/Skia/Avalonia.Skia/TextRunIterator.cs @@ -5,15 +5,12 @@ using Avalonia.Media; using Avalonia.Media.Text; using Avalonia.Media.Text.Unicode; -using Avalonia.Platform; using HarfBuzzSharp; namespace Avalonia.Skia { internal static class TextRunIterator { - private static readonly IFontManager s_fontManager = AvaloniaLocator.Current.GetService(); - /// /// Creates a list of text runs with unique properties. /// @@ -35,7 +32,7 @@ public static List Create(ReadOnlySlice text, Typeface //ToDo: Fix FontFamily fallback currentTypeface = - s_fontManager.MatchCharacter(codepoint, defaultTypeface.Weight, defaultTypeface.Style); + FontManager.Default.MatchCharacter(codepoint, defaultTypeface.Weight, defaultTypeface.Style); if (currentTypeface == null || !TryGetRunProperties(text, currentTypeface, defaultTypeface, out count)) { diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index 7de8762ba1e3..75f06d671b51 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -9,6 +9,7 @@ using Avalonia.Controls.Platform.Surfaces; using Avalonia.Direct2D1.Media; using Avalonia.Direct2D1.Media.Imaging; +using Avalonia.Media; using Avalonia.Platform; using SharpDX.DirectWrite; using GlyphRun = Avalonia.Media.GlyphRun; @@ -31,6 +32,7 @@ public class Direct2D1Platform : IPlatformRenderInterface { private readonly ConcurrentDictionary _glyphTypefaceCache = new ConcurrentDictionary(); + private static readonly Direct2D1Platform s_instance = new Direct2D1Platform(); public static SharpDX.Direct3D11.Device Direct3D11Device { get; private set; } @@ -177,6 +179,11 @@ public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, PixelSize size, V return new WicBitmapImpl(format, data, size, dpi, stride); } + public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface) + { + return _glyphTypefaceCache.GetOrAdd(typeface, new GlyphTypefaceImpl(typeface)); + } + public IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width) { var glyphTypeface = (GlyphTypefaceImpl)glyphRun.GlyphTypeface.PlatformImpl; diff --git a/src/Windows/Avalonia.Direct2D1/Media/FontManager.cs b/src/Windows/Avalonia.Direct2D1/Media/FontManager.cs deleted file mode 100644 index f6522cb6e95c..000000000000 --- a/src/Windows/Avalonia.Direct2D1/Media/FontManager.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) The Avalonia Project. All rights reserved. -// Licensed under the MIT license. See licence.md file in the project root for full license information. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using Avalonia.Media; -using Avalonia.Platform; -using SharpDX.DirectWrite; -using FontFamily = Avalonia.Media.FontFamily; -using FontStyle = Avalonia.Media.FontStyle; -using FontWeight = Avalonia.Media.FontWeight; - -namespace Avalonia.Direct2D1.Media -{ - internal class FontManager : IFontManager - { - private readonly ConcurrentDictionary _glyphTypefaceCache = - new ConcurrentDictionary(); - - public FontManager() - { - //ToDo: Implement a real lookup of the system's default font. - DefaultFontFamilyName = "segoe ui"; - } - - public string DefaultFontFamilyName { get; } - - public IEnumerable GetInstalledFontFamilyNames(bool checkForUpdates = false) - { - var familyCount = Direct2D1FontCollectionCache.InstalledFontCollection.FontFamilyCount; - - var fontFamilies = new string[familyCount]; - - for (var i = 0; i < familyCount; i++) - { - fontFamilies[i] = Direct2D1FontCollectionCache.InstalledFontCollection.GetFontFamily(i).FamilyNames.GetString(0); - } - - return fontFamilies; - } - - public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface) - { - return _glyphTypefaceCache.GetOrAdd(typeface, new GlyphTypefaceImpl(typeface)); - } - - public Typeface GetTypeface(FontFamily fontFamily, FontWeight fontWeight, FontStyle fontStyle) - { - throw new NotImplementedException(); - } - - public Typeface MatchCharacter(int codepoint, FontWeight fontWeight = default, FontStyle fontStyle = default, - FontFamily fontFamily = null, CultureInfo culture = null) - { - var fontFamilyName = FontFamily.Default.Name; - - var familyCount = Direct2D1FontCollectionCache.InstalledFontCollection.FontFamilyCount; - - for (var i = 0; i < familyCount; i++) - { - var font = Direct2D1FontCollectionCache.InstalledFontCollection.GetFontFamily(i) - .GetMatchingFonts((SharpDX.DirectWrite.FontWeight)fontWeight, FontStretch.Normal, - (SharpDX.DirectWrite.FontStyle)fontStyle).GetFont(0); - - if (!font.HasCharacter((int)codepoint)) - { - continue; - } - - fontFamilyName = font.FontFamily.FamilyNames.GetString(0); - - break; - } - - //ToDo: This should be cached. - return new Typeface(new FontFamily(fontFamilyName), fontWeight, fontStyle); - } - } -} diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs index e69de29bb2d1..32def01c392e 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs @@ -0,0 +1,188 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media; +using Avalonia.Platform; +using HarfBuzzSharp; +using SharpDX.DirectWrite; + +namespace Avalonia.Direct2D1.Media +{ + public class GlyphTypefaceImpl : IGlyphTypefaceImpl + { + private bool _isDisposed; + + public GlyphTypefaceImpl(Typeface typeface) + { + DWFont = Direct2D1FontCollectionCache.GetFont(typeface); + + FontFace = new FontFace(DWFont); + + Face = new Face(GetTable); + + Font = new HarfBuzzSharp.Font(Face); + + Font.SetFunctionsOpenType(); + + Font.GetScale(out var xScale, out _); + + DesignEmHeight = (short)xScale; + + if (!Font.TryGetHorizontalFontExtents(out var fontExtents)) + { + Font.TryGetVerticalFontExtents(out fontExtents); + } + + Ascent = -fontExtents.Ascender; + + Descent = -fontExtents.Descender; + + LineGap = fontExtents.LineGap; + + if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.UnderlineOffset, out var underlinePosition)) + { + UnderlinePosition = underlinePosition; + } + + if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.UnderlineSize, out var underlineThickness)) + { + UnderlineThickness = underlineThickness; + } + + if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.StrikeoutOffset, out var strikethroughPosition)) + { + StrikethroughPosition = strikethroughPosition; + } + + if (Font.OpenTypeMetrics.TryGetPosition(OpenTypeMetricsTag.StrikeoutSize, out var strikethroughThickness)) + { + StrikethroughThickness = strikethroughThickness; + } + } + + private Blob GetTable(Face face, Tag tag) + { + var dwTag = (int)SwapBytes(tag); + + if (FontFace.TryGetFontTable(dwTag, out var tableData, out _)) + { + return new Blob(tableData.Pointer, tableData.Size, MemoryMode.ReadOnly, () => { }); + } + + return null; + } + + private static uint SwapBytes(uint x) + { + x = (x >> 16) | (x << 16); + + return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); + } + + public SharpDX.DirectWrite.Font DWFont { get; } + + public FontFace FontFace { get; } + + public Face Face { get; } + + public HarfBuzzSharp.Font Font { get; } + + /// + public short DesignEmHeight { get; } + + /// + public int Ascent { get; } + + /// + public int Descent { get; } + + /// + public int LineGap { get; } + + //ToDo: Read font table for these values + /// + public int UnderlinePosition { get; } + + /// + public int UnderlineThickness { get; } + + /// + public int StrikethroughPosition { get; } + + /// + public int StrikethroughThickness { get; } + + /// + public ushort GetGlyph(uint codepoint) + { + if (Font.TryGetGlyph(codepoint, out var glyph)) + { + return (ushort)glyph; + } + + return 0; + } + + /// + public ushort[] GetGlyphs(ReadOnlySpan codepoints) + { + var glyphs = new ushort[codepoints.Length]; + + for (var i = 0; i < codepoints.Length; i++) + { + if (Font.TryGetGlyph(codepoints[i], out var glyph)) + { + glyphs[i] = (ushort)glyph; + } + } + + return glyphs; + } + + /// + public int GetGlyphAdvance(ushort glyph) + { + return Font.GetHorizontalGlyphAdvance(glyph); + } + + /// + public int[] GetGlyphAdvances(ReadOnlySpan glyphs) + { + var glyphIndices = new uint[glyphs.Length]; + + for (var i = 0; i < glyphs.Length; i++) + { + glyphIndices[i] = glyphs[i]; + } + + return Font.GetHorizontalGlyphAdvances(glyphIndices); + } + + private void Dispose(bool disposing) + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + + if (!disposing) + { + return; + } + + Font?.Dispose(); + Face?.Dispose(); + FontFace?.Dispose(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} + diff --git a/src/Windows/Avalonia.Direct2D1/Media/TextRunIterator.cs b/src/Windows/Avalonia.Direct2D1/Media/TextRunIterator.cs index e0eb1ae916ea..317cf91107c1 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/TextRunIterator.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/TextRunIterator.cs @@ -5,15 +5,12 @@ using Avalonia.Media; using Avalonia.Media.Text; using Avalonia.Media.Text.Unicode; -using Avalonia.Platform; using HarfBuzzSharp; namespace Avalonia.Direct2D1.Media { internal static class TextRunIterator { - private static readonly IFontManager s_fontManager = AvaloniaLocator.Current.GetService(); - /// /// Creates a list of text runs with unique properties. /// @@ -36,7 +33,7 @@ public static List Create(ReadOnlySlice text, Typeface //ToDo: Fix FontFamily fallback currentTypeface = - s_fontManager.MatchCharacter(codepoint, defaultTypeface.Weight, defaultTypeface.Style); + FontManager.Default.MatchCharacter(codepoint, defaultTypeface.Weight, defaultTypeface.Style); if (currentTypeface == null || !TryGetRunProperties(text, currentTypeface, defaultTypeface, out count)) { diff --git a/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs b/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs index 626f98eac8ec..5ec6efb9c17b 100644 --- a/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs +++ b/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs @@ -141,16 +141,7 @@ private void RegisterServices() var outObj = (object)10; globalStylesResources.Setup(x => x.TryGetResource("FontSizeNormal", out outObj)).Returns(true); - var renderInterface = new Mock(); - - var streamGeometry = new Mock(); - streamGeometry.Setup(x => - x.Open()) - .Returns(new Mock().Object); - - renderInterface.Setup(x => - x.CreateStreamGeometry()) - .Returns(streamGeometry.Object); + var renderInterface = new MockPlatformRenderInterface(); var windowImpl = new Mock(); @@ -167,7 +158,7 @@ private void RegisterServices() .Bind().ToConstant(new Mock().Object) .Bind().ToConstant(globalStyles.Object) .Bind().ToConstant(new AppBuilder().RuntimePlatform) - .Bind().ToConstant(renderInterface.Object) + .Bind().ToConstant(renderInterface) .Bind().ToConstant(new MockTextFormatter()) .Bind().ToConstant(new Styler()) .Bind().ToConstant(new Avalonia.Controls.UnitTests.WindowingPlatformMock(() => windowImpl.Object)); diff --git a/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs b/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs index d854fb939d2b..b6c857c831fe 100644 --- a/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs +++ b/tests/Avalonia.Skia.UnitTests/TextLayoutTests.cs @@ -17,11 +17,15 @@ public class TextLayoutTests public void Should_Apply_TextStyleSpan_To_Text_In_Between() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var foreground = new SolidColorBrush(Colors.Red).ToImmutable(); - var spans = new List { new FormattedTextStyleSpan(1, 2, foreground: foreground) }; + var spans = new List + { + new FormattedTextStyleSpan(1, 2, foreground: foreground) + }; var layout = new TextLayout( s_multiLineText, @@ -53,11 +57,15 @@ public void Should_Apply_TextStyleSpan_To_Text_In_Between() public void Should_Apply_TextStyleSpan_To_Text_At_Start() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var foreground = new SolidColorBrush(Colors.Red).ToImmutable(); - var spans = new List { new FormattedTextStyleSpan(0, 2, foreground: foreground) }; + var spans = new List + { + new FormattedTextStyleSpan(0, 2, foreground: foreground) + }; var layout = new TextLayout( s_singleLineText, @@ -77,7 +85,8 @@ public void Should_Apply_TextStyleSpan_To_Text_At_Start() Assert.Equal(2, textRun.GlyphRun.Characters.Length); - var actual = s_singleLineText.Substring(textRun.GlyphRun.Characters.Start, textRun.GlyphRun.Characters.Length); + var actual = s_singleLineText.Substring(textRun.GlyphRun.Characters.Start, + textRun.GlyphRun.Characters.Length); Assert.Equal("01", actual); @@ -89,11 +98,15 @@ public void Should_Apply_TextStyleSpan_To_Text_At_Start() public void Should_Apply_TextStyleSpan_To_Text_At_End() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var foreground = new SolidColorBrush(Colors.Red).ToImmutable(); - var spans = new List { new FormattedTextStyleSpan(8, 2, foreground: foreground) }; + var spans = new List + { + new FormattedTextStyleSpan(8, 2, foreground: foreground) + }; var layout = new TextLayout( s_singleLineText, @@ -125,11 +138,15 @@ public void Should_Apply_TextStyleSpan_To_Text_At_End() public void Should_Apply_TextStyleSpan_To_Single_Character() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var foreground = new SolidColorBrush(Colors.Red).ToImmutable(); - var spans = new List { new FormattedTextStyleSpan(0, 1, foreground: foreground) }; + var spans = new List + { + new FormattedTextStyleSpan(0, 1, foreground: foreground) + }; var layout = new TextLayout( "0", @@ -156,14 +173,17 @@ public void Should_Apply_TextStyleSpan_To_Single_Character() [Fact] public void Should_Apply_TextSpan_To_Unicode_String_In_Between() { - using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With( + renderInterface: new PlatformRenderInterface(null), textFormatter: new TextFormatter()))) { const string text = "😄😄😄😄"; var foreground = new SolidColorBrush(Colors.Red).ToImmutable(); - var spans = new List { new FormattedTextStyleSpan(2, 2, foreground: foreground) }; + var spans = new List + { + new FormattedTextStyleSpan(2, 2, foreground: foreground) + }; var layout = new TextLayout( text, @@ -195,7 +215,8 @@ public void Should_Apply_TextSpan_To_Unicode_String_In_Between() public void TextLength_Should_Be_Equal_To_TextLine_Length_Sum() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var layout = new TextLayout( s_multiLineText, @@ -214,7 +235,8 @@ public void TextLength_Should_Be_Equal_To_TextLine_Length_Sum() public void TextLength_Should_Be_Equal_To_TextRun_TextLength_Sum() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var layout = new TextLayout( s_multiLineText, @@ -227,7 +249,8 @@ public void TextLength_Should_Be_Equal_To_TextRun_TextLength_Sum() Assert.Equal( s_multiLineText.Length, - layout.TextLines.Select(textLine => textLine.TextRuns.Sum(textRun => textRun.GlyphRun.Characters.Length)) + layout.TextLines.Select(textLine => + textLine.TextRuns.Sum(textRun => textRun.GlyphRun.Characters.Length)) .Sum()); } } @@ -236,7 +259,8 @@ public void TextLength_Should_Be_Equal_To_TextRun_TextLength_Sum() public void TextLength_Should_Be_Equal_To_TextRun_TextLength_Sum_After_Wrap_With_Style_Applied() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { const string text = "Multiline TextBox with TextWrapping.\r\rLorem ipsum dolor sit amet, consectetur adipiscing elit. " + @@ -262,7 +286,8 @@ public void TextLength_Should_Be_Equal_To_TextRun_TextLength_Sum_After_Wrap_With Assert.Equal( text.Length, - layout.TextLines.Select(textLine => textLine.TextRuns.Sum(textRun => textRun.GlyphRun.Characters.Length)) + layout.TextLines.Select(textLine => + textLine.TextRuns.Sum(textRun => textRun.GlyphRun.Characters.Length)) .Sum()); } } @@ -271,7 +296,8 @@ public void TextLength_Should_Be_Equal_To_TextRun_TextLength_Sum_After_Wrap_With public void Should_Apply_TextStyleSpan_To_MultiLine() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var foreground = new SolidColorBrush(Colors.Red).ToImmutable(); @@ -296,11 +322,12 @@ public void Should_Apply_TextStyleSpan_To_MultiLine() } } - [Fact(/*Skip = "Currently fails on Linux because of not present Emojis font"*/)] + [Fact( /*Skip = "Currently fails on Linux because of not present Emojis font"*/)] public void Should_Hit_Test_SurrogatePair() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { const string text = "😄😄"; @@ -331,7 +358,8 @@ public void Should_Hit_Test_SurrogatePair() public void Should_Break_With_BreakChar_Pair(string text) { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var layout = new TextLayout( text, @@ -358,7 +386,8 @@ public void Should_Break_With_BreakChar_Pair(string text) public void Should_Have_One_Run_With_Common_Script() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var layout = new TextLayout( "abcde\r\n", @@ -376,13 +405,16 @@ public void Should_Have_One_Run_With_Common_Script() [Theory] [InlineData("0123", 1)] [InlineData("\r\n", 1)] - [InlineData("👍b", 2/*, Skip = "Currently fails on Linux because of not present fonts"*/)] - [InlineData("a👍b", 3/*, Skip = "Currently fails on Linux because of not present fonts"*/)] - [InlineData("a👍子b", 4/*, Skip = "Currently fails on Linux because of not present fonts"*/)] + [InlineData("👍b", 2 /*, Skip = "Currently fails on Linux because of not present fonts"*/)] + [InlineData("a👍b", 3 /*, Skip = "Currently fails on Linux because of not present fonts"*/)] + [InlineData("a👍子b", 4 /*, Skip = "Currently fails on Linux because of not present fonts"*/)] public void Should_Produce_Unique_Runs(string text, int numberOfRuns) { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With( + renderInterface: new PlatformRenderInterface(null), + fontManagerImpl: new FontManagerImpl(), + textFormatter: new TextFormatter()))) { var buffer = new ReadOnlySlice(text.AsMemory()); @@ -398,7 +430,8 @@ public void Should_Produce_Unique_Runs(string text, int numberOfRuns) public void Should_Split_Run_On_Direction() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var text = "1234الدولي"; @@ -416,7 +449,8 @@ public void Should_Split_Run_On_Direction() public void Should_Layout_Corrupted_Text() { using (UnitTestApplication.Start( - TestServices.MockPlatformRenderInterface.With(fontManager: new FontManager(), textFormatter: new TextFormatter()))) + TestServices.MockPlatformRenderInterface.With(renderInterface: new PlatformRenderInterface(null), + textFormatter: new TextFormatter()))) { var text = new string(new[] { '\uD802', '\uD802', '\uD802', '\uD802', '\uD802', '\uD802', '\uD802' }); diff --git a/tests/Avalonia.UnitTests/MockFontManager.cs b/tests/Avalonia.UnitTests/MockFontManagerImpl.cs similarity index 94% rename from tests/Avalonia.UnitTests/MockFontManager.cs rename to tests/Avalonia.UnitTests/MockFontManagerImpl.cs index c3b00c163170..c0740737b0bd 100644 --- a/tests/Avalonia.UnitTests/MockFontManager.cs +++ b/tests/Avalonia.UnitTests/MockFontManagerImpl.cs @@ -6,7 +6,7 @@ namespace Avalonia.UnitTests { - public class MockFontManager : IFontManager + public class MockFontManagerImpl : IFontManagerImpl { public string DefaultFontFamilyName => "Arial"; public IEnumerable GetInstalledFontFamilyNames(bool checkForUpdates = false) diff --git a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs index 7db98b342b9b..fbb025aea8ba 100644 --- a/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs +++ b/tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs @@ -81,7 +81,7 @@ public IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width) public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface) { - return Mock.Of(); + return new MockGlyphTypeface(); } } } diff --git a/tests/Avalonia.UnitTests/TestServices.cs b/tests/Avalonia.UnitTests/TestServices.cs index 5a6c1fa596c6..ae5e2c902870 100644 --- a/tests/Avalonia.UnitTests/TestServices.cs +++ b/tests/Avalonia.UnitTests/TestServices.cs @@ -29,13 +29,12 @@ public class TestServices styler: new Styler(), theme: () => CreateDefaultTheme(), threadingInterface: Mock.Of(x => x.CurrentThreadIsLoopThread == true), - fontManager: new MockFontManager(), + fontManagerImpl: new MockFontManagerImpl(), textFormatter: new MockTextFormatter(), windowingPlatform: new MockWindowingPlatform()); public static readonly TestServices MockPlatformRenderInterface = new TestServices( renderInterface: new MockPlatformRenderInterface(), - fontManager: new MockFontManager(), textFormatter: new MockTextFormatter()); public static readonly TestServices MockPlatformWrapper = new TestServices( @@ -75,7 +74,7 @@ public TestServices( IStyler styler = null, Func theme = null, IPlatformThreadingInterface threadingInterface = null, - IFontManager fontManager = null, + IFontManagerImpl fontManagerImpl = null, ITextFormatter textFormatter = null, IWindowImpl windowImpl = null, IWindowingPlatform windowingPlatform = null) @@ -89,7 +88,7 @@ public TestServices( MouseDevice = mouseDevice; Platform = platform; RenderInterface = renderInterface; - FontManager = fontManager; + FontManagerImpl = fontManagerImpl; TextFormatter = textFormatter; Scheduler = scheduler; StandardCursorFactory = standardCursorFactory; @@ -109,7 +108,7 @@ public TestServices( public Func MouseDevice { get; } public IRuntimePlatform Platform { get; } public IPlatformRenderInterface RenderInterface { get; } - public IFontManager FontManager { get; } + public IFontManagerImpl FontManagerImpl { get; } public ITextFormatter TextFormatter { get; } public IScheduler Scheduler { get; } public IStandardCursorFactory StandardCursorFactory { get; } @@ -135,7 +134,7 @@ public TestServices With( IStyler styler = null, Func theme = null, IPlatformThreadingInterface threadingInterface = null, - IFontManager fontManager = null, + IFontManagerImpl fontManagerImpl = null, ITextFormatter textFormatter = null, IWindowImpl windowImpl = null, IWindowingPlatform windowingPlatform = null) @@ -150,7 +149,7 @@ public TestServices With( mouseDevice: mouseDevice ?? MouseDevice, platform: platform ?? Platform, renderInterface: renderInterface ?? RenderInterface, - fontManager: fontManager ?? FontManager, + fontManagerImpl: fontManagerImpl ?? FontManagerImpl, textFormatter: textFormatter ?? TextFormatter, scheduler: scheduler ?? Scheduler, standardCursorFactory: standardCursorFactory ?? StandardCursorFactory, diff --git a/tests/Avalonia.UnitTests/UnitTestApplication.cs b/tests/Avalonia.UnitTests/UnitTestApplication.cs index b07fbb8259fa..470c7dfd263f 100644 --- a/tests/Avalonia.UnitTests/UnitTestApplication.cs +++ b/tests/Avalonia.UnitTests/UnitTestApplication.cs @@ -61,7 +61,6 @@ public override void RegisterServices() .Bind().ToConstant(Services.MouseDevice?.Invoke()) .Bind().ToConstant(Services.Platform) .Bind().ToConstant(Services.RenderInterface) - .Bind().ToConstant(Services.FontManager) .Bind().ToConstant(Services.TextFormatter) .Bind().ToConstant(Services.ThreadingInterface) .Bind().ToConstant(Services.Scheduler)