Browse Source

Fix issue 4427 - System.InvalidOperationException: Default font family name can't be null or empty (#12817)

* Fix issue 4427 - System.InvalidOperationException: Default font family name can't be null or empty

* Updated FontManager

* Removed Linq usage from FontManager

---------

Co-authored-by: Mihnea Rădulescu <>
Co-authored-by: Benedikt Stebner <Gillibald@users.noreply.github.com>
#Conflicts:
#	src/Avalonia.Base/Media/FontManager.cs
release/11.0.7
Mihnea Rădulescu 2 years ago
committed by Max Katz
parent
commit
1fcf3251ed
  1. 38
      src/Avalonia.Base/Media/FontManager.cs
  2. 59
      src/Headless/Avalonia.Headless/HeadlessPlatformStubs.cs
  3. 19
      tests/Avalonia.Base.UnitTests/Media/FontManagerTests.cs

38
src/Avalonia.Base/Media/FontManager.cs

@ -28,20 +28,13 @@ namespace Avalonia.Media
{
PlatformImpl = platformImpl;
var options = AvaloniaLocator.Current.GetService<FontManagerOptions>();
AddFontCollection(new SystemFontCollection(this));
var options = AvaloniaLocator.Current.GetService<FontManagerOptions>();
_fontFallbacks = options?.FontFallbacks;
var defaultFontFamilyName = options?.DefaultFamilyName ?? PlatformImpl.GetDefaultFontFamilyName();
if (string.IsNullOrEmpty(defaultFontFamilyName))
{
throw new InvalidOperationException("Default font family name can't be null or empty.");
}
var defaultFontFamilyName = GetDefaultFontFamilyName(options);
DefaultFontFamily = new FontFamily(defaultFontFamilyName);
AddFontCollection(new SystemFontCollection(this));
}
/// <summary>
@ -111,8 +104,8 @@ namespace Avalonia.Media
var key = compositeKey.Keys[i];
var familyName = fontFamily.FamilyNames[i];
if (TryGetGlyphTypefaceByKeyAndName(typeface, key, familyName, out glyphTypeface) &&
if (TryGetGlyphTypefaceByKeyAndName(typeface, key, familyName, out glyphTypeface) &&
glyphTypeface.FamilyName.Contains(familyName))
{
return true;
@ -270,7 +263,7 @@ namespace Avalonia.Media
private bool TryGetFontCollection(Uri source, [NotNullWhen(true)] out IFontCollection? fontCollection)
{
if(source.Scheme == SystemFontScheme)
if (source.Scheme == SystemFontScheme)
{
source = SystemFontsKey;
}
@ -289,5 +282,24 @@ namespace Avalonia.Media
return fontCollection != null;
}
private string GetDefaultFontFamilyName(FontManagerOptions? options)
{
var defaultFontFamilyName = options?.DefaultFamilyName
?? PlatformImpl.GetDefaultFontFamilyName();
if (string.IsNullOrEmpty(defaultFontFamilyName) && SystemFonts.Count > 0)
{
defaultFontFamilyName = SystemFonts[0].Name;
}
if (string.IsNullOrEmpty(defaultFontFamilyName))
{
throw new InvalidOperationException(
"Default font family name can't be null or empty.");
}
return defaultFontFamilyName;
}
}
}

59
src/Headless/Avalonia.Headless/HeadlessPlatformStubs.cs

@ -250,6 +250,65 @@ namespace Avalonia.Headless
}
}
internal class HeadlessFontManagerWithMultipleSystemFontsStub : IFontManagerImpl
{
private readonly string[] _installedFontFamilyNames;
private readonly string _defaultFamilyName;
public HeadlessFontManagerWithMultipleSystemFontsStub(
string[] installedFontFamilyNames,
string defaultFamilyName = "Default")
{
_installedFontFamilyNames = installedFontFamilyNames;
_defaultFamilyName = defaultFamilyName;
}
public int TryCreateGlyphTypefaceCount { get; private set; }
public string GetDefaultFontFamilyName()
{
return _defaultFamilyName;
}
string[] IFontManagerImpl.GetInstalledFontFamilyNames(bool checkForUpdates)
{
return _installedFontFamilyNames;
}
public bool TryMatchCharacter(int codepoint, FontStyle fontStyle, FontWeight fontWeight,
FontStretch fontStretch,
CultureInfo? culture, out Typeface fontKey)
{
fontKey = new Typeface(_defaultFamilyName);
return false;
}
public virtual bool TryCreateGlyphTypeface(string familyName, FontStyle style, FontWeight weight,
FontStretch stretch, [NotNullWhen(true)] out IGlyphTypeface? glyphTypeface)
{
glyphTypeface = null;
TryCreateGlyphTypefaceCount++;
if (familyName == "Unknown")
{
return false;
}
glyphTypeface = new HeadlessGlyphTypefaceImpl();
return true;
}
public virtual bool TryCreateGlyphTypeface(Stream stream, out IGlyphTypeface glyphTypeface)
{
glyphTypeface = new HeadlessGlyphTypefaceImpl();
return true;
}
}
internal class HeadlessIconLoaderStub : IPlatformIconLoader
{
private class IconStub : IWindowIconImpl

19
tests/Avalonia.Base.UnitTests/Media/FontManagerTests.cs

@ -26,9 +26,12 @@ namespace Avalonia.Base.UnitTests.Media
}
[Fact]
public void Should_Throw_When_Default_FamilyName_Is_Null()
public void Should_Throw_When_Default_FamilyName_Is_Null_And_Installed_Font_Family_Names_Is_Empty()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new HeadlessFontManagerStub(null!))))
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface
.With(fontManagerImpl: new HeadlessFontManagerWithMultipleSystemFontsStub(
installedFontFamilyNames: new string[] { },
defaultFamilyName: null))))
{
Assert.Throws<InvalidOperationException>(() => FontManager.Current);
}
@ -73,5 +76,17 @@ namespace Avalonia.Base.UnitTests.Media
Assert.Equal("MyFont", typeface.FontFamily.Name);
}
}
[Fact]
public void Should_Return_First_Installed_Font_Family_Name_When_Default_Family_Name_Is_Null()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface
.With(fontManagerImpl: new HeadlessFontManagerWithMultipleSystemFontsStub(
installedFontFamilyNames: new[] { "DejaVu", "Verdana" },
defaultFamilyName: null))))
{
Assert.Equal("DejaVu", FontManager.Current.DefaultFontFamily.Name);
}
}
}
}

Loading…
Cancel
Save