A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

226 lines
10 KiB

using System;
using System.IO;
using System.Linq;
using Avalonia.Media;
using Avalonia.Media.Fonts;
using Avalonia.Platform;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Skia.UnitTests.Media
{
public class CustomFontCollectionTests
{
private const string AssetsNamespace = "Avalonia.Skia.UnitTests.Assets";
private const string AssetFonts = $"resm:{AssetsNamespace}?assembly=Avalonia.Skia.UnitTests";
[Fact]
public void Should_AddGlyphTypeface_By_Stream()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
var fontManager = FontManager.Current;
var fontCollection = new CustomFontCollection(new Uri("fonts:custom", UriKind.Absolute));
fontManager.AddFontCollection(fontCollection);
var assetLoader = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
var infos = new[]
{
new FontAssetInfo($"{AssetsNamespace}.AdobeBlank2VF.ttf", "Adobe Blank 2 VF R", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.Inter-Bold.ttf", "Inter", FontWeight.Bold),
new FontAssetInfo($"{AssetsNamespace}.Inter-Regular.ttf", "Inter", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.Manrope-Light.ttf", "Manrope Light", FontWeight.Light),
new FontAssetInfo($"{AssetsNamespace}.MiSans-Normal.ttf", "MiSans Normal", (FontWeight)305),
new FontAssetInfo($"{AssetsNamespace}.NISC18030.ttf", "GB18030 Bitmap", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.NotoMono-Regular.ttf", "Noto Mono", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.NotoSans-Italic.ttf", "Noto Sans", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.NotoSansArabic-Regular.ttf", "Noto Sans Arabic", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.NotoSansDeseret-Regular.ttf", "Noto Sans Deseret", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.NotoSansHebrew-Regular.ttf", "Noto Sans Hebrew", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.NotoSansMiao-Regular.ttf", "Noto Sans Miao", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.NotoSansTamil-Regular.ttf", "Noto Sans Tamil", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.SourceSerif4_36pt-Italic.ttf", "Source Serif 4 36pt", FontWeight.Normal),
new FontAssetInfo($"{AssetsNamespace}.TwitterColorEmoji-SVGinOT.ttf", "Twitter Color Emoji", FontWeight.Normal)
};
var assets = assetLoader.GetAssets(new Uri(AssetFonts, UriKind.Absolute), null)
.OrderBy(uri => uri.AbsoluteUri, StringComparer.OrdinalIgnoreCase)
.ToArray();
Assert.Equal(infos.Length, assets.Length);
var glyphTypefaces = new GlyphTypeface[infos.Length];
// Load fonts
for (var i = 0; i < infos.Length; ++i)
{
var info = infos[i];
var asset = assets[i];
Assert.Equal(info.Path, asset.AbsolutePath);
using var fontStream = assetLoader.Open(asset);
Assert.NotNull(fontStream);
Assert.True(fontCollection.TryAddGlyphTypeface(fontStream, out var glyphTypeface));
Assert.Equal(info.FamilyName, glyphTypeface.FamilyName);
Assert.Equal(info.Weight, glyphTypeface.Weight);
glyphTypefaces[i] = glyphTypeface;
}
// Check against the custom collection
for (var i = 0; i < infos.Length; ++i)
{
var info = infos[i];
var glyphTypeface = glyphTypefaces[i];
Assert.True(fontManager.TryGetGlyphTypeface(new Typeface($"fonts:custom#{info.FamilyName}", weight: info.Weight), out var secondGlyphTypeface));
Assert.Same(glyphTypeface, secondGlyphTypeface);
}
}
}
[Fact]
public void Should_Enumerate_FontFamilies()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
var fontManager = FontManager.Current;
var fontCollection = new CustomFontCollection(new Uri("fonts:custom", UriKind.Absolute));
fontManager.AddFontCollection(fontCollection);
var assetLoader = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
var assets = assetLoader.GetAssets(new Uri(AssetFonts, UriKind.Absolute), null).Where(x => x.AbsolutePath.EndsWith(".ttf")).ToArray();
foreach (var asset in assets)
{
fontCollection.TryAddGlyphTypeface(assetLoader.Open(asset), out _);
}
var families = fontCollection.ToArray();
Assert.True(families.Length >= assets.Length);
var other = new CustomFontCollection(new Uri("fonts:other", UriKind.Absolute));
foreach (var family in families)
{
var familyTypefaces = family.FamilyTypefaces;
foreach (var typeface in familyTypefaces)
{
other.TryAddGlyphTypeface(typeface.GlyphTypeface);
}
}
Assert.Equal(families.Length, other.Count);
for (int i = 0; i < families.Length; i++)
{
Assert.Equal(families[i].Name, other[i].Name);
}
}
}
[Fact]
public void Should_AddFontSource_From_File()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
var fontManager = FontManager.Current;
var fontCollection = new CustomFontCollection(new Uri("fonts:custom", UriKind.Absolute));
fontManager.AddFontCollection(fontCollection);
// Path to the test font
var fontPath = Path.Combine(AppContext.BaseDirectory, "Assets", "Inter-Regular.ttf");
Assert.True(File.Exists(fontPath));
var fontUri = new Uri(fontPath, UriKind.Absolute);
// Add the font file
Assert.True(fontCollection.TryAddFontSource(fontUri));
// Check if the font was loaded
Assert.True(fontCollection.TryGetGlyphTypeface("Inter", FontStyle.Normal, FontWeight.Regular, FontStretch.Normal, out var glyphTypeface));
Assert.Equal("Inter", glyphTypeface.FamilyName);
// Check if the FontManager can find the font
Assert.True(fontManager.TryGetGlyphTypeface(new Typeface("fonts:custom#Inter"), out var glyphTypeface2));
Assert.Equal(glyphTypeface, glyphTypeface2);
}
}
[Fact]
public void Should_AddFontSource_From_Folder()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
var fontManager = FontManager.Current;
var fontCollection = new CustomFontCollection(new Uri("fonts:custom", UriKind.Absolute));
fontManager.AddFontCollection(fontCollection);
// Path to the test fonts
var fontsFolder = Path.Combine(AppContext.BaseDirectory, "Assets");
Assert.True(Directory.Exists(fontsFolder));
var folderUri = new Uri(fontsFolder + Path.DirectorySeparatorChar, UriKind.Absolute);
// Add the fonts
Assert.True(fontCollection.TryAddFontSource(folderUri));
// Check if the font was loaded
Assert.True(fontCollection.TryGetGlyphTypeface("Inter", FontStyle.Normal, FontWeight.Regular, FontStretch.Normal, out var glyphTypeface));
Assert.Equal("Inter", glyphTypeface.FamilyName);
// Check if the FontManager can find the font
Assert.True(fontManager.TryGetGlyphTypeface(new Typeface("fonts:custom#Inter"), out var glyphTypeface2));
Assert.Equal(glyphTypeface, glyphTypeface2);
}
}
[Fact]
public void Should_AddFontSource_From_Resource()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
var fontManager = FontManager.Current;
var fontCollection = new CustomFontCollection(new Uri("fonts:custom", UriKind.Absolute));
fontManager.AddFontCollection(fontCollection);
var allFontsUri = new Uri(AssetFonts, UriKind.Absolute);
// Add the font resource
Assert.True(fontCollection.TryAddFontSource(allFontsUri));
// Get the loaded family names
var families = fontCollection.ToArray();
Assert.NotEmpty(families);
// Try to get a GlyphTypeface
Assert.True(fontCollection.TryGetGlyphTypeface("Noto Mono", FontStyle.Normal, FontWeight.Regular, FontStretch.Normal, out var glyphTypeface));
Assert.Equal("Noto Mono", glyphTypeface.FamilyName);
// Check if the FontManager can find the font
Assert.True(fontManager.TryGetGlyphTypeface(new Typeface("fonts:custom#Noto Mono"), out var glyphTypeface2));
Assert.Equal(glyphTypeface, glyphTypeface2);
}
}
private class CustomFontCollection(Uri key) : FontCollectionBase
{
public override Uri Key { get; } = key;
}
private record struct FontAssetInfo(string Path, string FamilyName, FontWeight Weight);
}
}