Browse Source

Introduce AppBuilder extension to customize system fonts

pull/13191/head
Benedikt Stebner 3 years ago
parent
commit
36ec244b2c
  1. 64
      src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs
  2. 20
      src/Avalonia.Controls/SystemFontAppBuilderExtension.cs
  3. 24
      tests/Avalonia.Skia.UnitTests/Media/FontManagerTests.cs

64
src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs

@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Avalonia.Platform;
namespace Avalonia.Media.Fonts
@ -9,12 +10,12 @@ namespace Avalonia.Media.Fonts
internal class SystemFontCollection : FontCollectionBase
{
private readonly FontManager _fontManager;
private readonly string[] _familyNames;
private readonly List<string> _familyNames;
public SystemFontCollection(FontManager fontManager)
{
_fontManager = fontManager;
_familyNames = fontManager.PlatformImpl.GetInstalledFontFamilyNames();
_familyNames = fontManager.PlatformImpl.GetInstalledFontFamilyNames().ToList();
}
public override Uri Key => FontManager.SystemFontsKey;
@ -29,7 +30,15 @@ namespace Avalonia.Media.Fonts
}
}
public override int Count => _familyNames.Length;
public override int Count => _familyNames.Count;
public override IEnumerator<FontFamily> GetEnumerator()
{
foreach (var familyName in _familyNames)
{
yield return new FontFamily(familyName);
}
}
public override bool TryGetGlyphTypeface(string familyName, FontStyle style, FontWeight weight,
FontStretch stretch, [NotNullWhen(true)] out IGlyphTypeface? glyphTypeface)
@ -58,11 +67,54 @@ namespace Avalonia.Media.Fonts
//We initialize the system font collection during construction.
}
public override IEnumerator<FontFamily> GetEnumerator()
public void AddCustomFontFamilies(IReadOnlyList<FontFamily> customFontFamilies)
{
foreach (var familyName in _familyNames)
if (customFontFamilies is null)
{
yield return new FontFamily(familyName);
return;
}
for (int i = 0; i < customFontFamilies.Count; i++)
{
var fontFamily = customFontFamilies[i];
if (fontFamily.Key is FontFamilyKey key)
{
LoadGlyphTypefaces(_fontManager.PlatformImpl, key.Source);
}
}
}
private void LoadGlyphTypefaces(IFontManagerImpl fontManager, Uri source)
{
var assetLoader = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
var fontAssets = FontFamilyLoader.LoadFontAssets(source);
foreach (var fontAsset in fontAssets)
{
var stream = assetLoader.Open(fontAsset);
if (fontManager.TryCreateGlyphTypeface(stream, out var glyphTypeface))
{
if (!_glyphTypefaceCache.TryGetValue(glyphTypeface.FamilyName, out var glyphTypefaces))
{
glyphTypefaces = new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
if (_glyphTypefaceCache.TryAdd(glyphTypeface.FamilyName, glyphTypefaces))
{
//Move the user defined system font to the start of the collection
_familyNames.Insert(0, glyphTypeface.FamilyName);
}
}
var key = new FontCollectionKey(
glyphTypeface.Style,
glyphTypeface.Weight,
glyphTypeface.Stretch);
glyphTypefaces.TryAdd(key, glyphTypeface);
}
}
}
}

20
src/Avalonia.Controls/SystemFontAppBuilderExtension.cs

@ -0,0 +1,20 @@
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Media.Fonts;
namespace Avalonia
{
public static class SystemFontAppBuilderExtension
{
public static AppBuilder WithCustomSystemFonts(this AppBuilder appBuilder, IReadOnlyList<FontFamily> customFontFamilies)
{
return appBuilder.ConfigureFonts(fontManager =>
{
if(fontManager.SystemFonts is SystemFontCollection systemFontCollection)
{
systemFontCollection.AddCustomFontFamilies(customFontFamilies);
}
});
}
}
}

24
tests/Avalonia.Skia.UnitTests/Media/FontManagerTests.cs

@ -1,6 +1,8 @@
using System;
using System.Linq;
using Avalonia.Headless;
using Avalonia.Media;
using Avalonia.Media.Fonts;
using Avalonia.UnitTests;
using SkiaSharp;
using Xunit;
@ -217,5 +219,27 @@ namespace Avalonia.Skia.UnitTests.Media
}
}
}
[Fact]
public void Should_Use_Custom_SystemFont()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
using (AvaloniaLocator.EnterScope())
{
var systemFontCollection = FontManager.Current.SystemFonts as SystemFontCollection;
Assert.NotNull(systemFontCollection);
var customFontFamilies = new[] { new FontFamily(s_fontUri) };
systemFontCollection.AddCustomFontFamilies(customFontFamilies);
Assert.True(FontManager.Current.TryGetGlyphTypeface(new Typeface("Noto Mono"), out var glyphTypeface));
Assert.Equal("Noto Mono", glyphTypeface.FamilyName);
}
}
}
}
}

Loading…
Cancel
Save