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>
pull/12915/head
Mihnea Rădulescu 3 years ago
committed by GitHub
parent
commit
7b67fda0eb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 40
      src/Avalonia.Base/Media/FontManager.cs
  2. 59
      src/Headless/Avalonia.Headless/HeadlessPlatformStubs.cs
  3. 19
      tests/Avalonia.Base.UnitTests/Media/FontManagerTests.cs

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

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

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

@ -26,9 +26,12 @@ namespace Avalonia.Base.UnitTests.Media
} }
[Fact] [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); Assert.Throws<InvalidOperationException>(() => FontManager.Current);
} }
@ -73,5 +76,17 @@ namespace Avalonia.Base.UnitTests.Media
Assert.Equal("MyFont", typeface.FontFamily.Name); 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