Browse Source

Add TypographicFamilyName to GlyphTypeface and use it for FontCollection (#16844)

* Introduce TypographicFamilyName

* Add TypographicFamilyName to the FontCollection cache if available
pull/16887/head
Benedikt Stebner 1 year ago
committed by GitHub
parent
commit
4f2dd6741a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs
  2. 41
      src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs
  3. 5
      src/Avalonia.Base/Media/IGlyphTypeface2.cs
  4. 4
      src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
  5. 2
      tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj
  6. BIN
      tests/Avalonia.Skia.UnitTests/Fonts/Manrope-Light.ttf
  7. 27
      tests/Avalonia.Skia.UnitTests/Media/EmbeddedFontCollectionTests.cs

12
src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs

@ -131,11 +131,15 @@ namespace Avalonia.Media.Fonts
{
if (glyphTypeface is IGlyphTypeface2 glyphTypeface2)
{
foreach (var kvp in glyphTypeface2.FamilyNames)
//Add the TypographicFamilyName to the cache
if (!string.IsNullOrEmpty(glyphTypeface2.TypographicFamilyName))
{
var familyName = kvp.Value;
AddGlyphTypefaceByFamilyName(glyphTypeface2.TypographicFamilyName, glyphTypeface);
}
AddGlyphTypefaceByFamilyName(familyName, glyphTypeface);
foreach (var kvp in glyphTypeface2.FamilyNames)
{
AddGlyphTypefaceByFamilyName(kvp.Value, glyphTypeface);
}
}
else
@ -150,7 +154,7 @@ namespace Avalonia.Media.Fonts
var typefaces = _glyphTypefaceCache.GetOrAdd(familyName,
x =>
{
_fontFamilies.Add(new FontFamily(_key, glyphTypeface.FamilyName));
_fontFamilies.Add(new FontFamily(_key, familyName));
return new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
});

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

@ -160,26 +160,35 @@ namespace Avalonia.Media.Fonts
{
var stream = assetLoader.Open(fontAsset);
if (fontManager.TryCreateGlyphTypeface(stream, FontSimulations.None, out var glyphTypeface))
if (!fontManager.TryCreateGlyphTypeface(stream, FontSimulations.None, out var glyphTypeface))
{
if (!_glyphTypefaceCache.TryGetValue(glyphTypeface.FamilyName, out var glyphTypefaces))
{
glyphTypefaces = new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
continue;
}
if (_glyphTypefaceCache.TryAdd(glyphTypeface.FamilyName, glyphTypefaces))
{
//Move the user defined system font to the start of the collection
_familyNames.Insert(0, glyphTypeface.FamilyName);
}
}
//Add TypographicFamilyName to the cache
if (glyphTypeface is IGlyphTypeface2 glyphTypeface2 && !string.IsNullOrEmpty(glyphTypeface2.TypographicFamilyName))
{
AddGlyphTypefaceByFamilyName(glyphTypeface2.TypographicFamilyName, glyphTypeface);
}
AddGlyphTypefaceByFamilyName(glyphTypeface.FamilyName, glyphTypeface);
}
var key = new FontCollectionKey(
glyphTypeface.Style,
glyphTypeface.Weight,
glyphTypeface.Stretch);
return;
glyphTypefaces.TryAdd(key, glyphTypeface);
}
void AddGlyphTypefaceByFamilyName(string familyName, IGlyphTypeface glyphTypeface)
{
var typefaces = _glyphTypefaceCache.GetOrAdd(familyName,
x =>
{
_familyNames.Insert(0, familyName);
return new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
});
typefaces.TryAdd(
new FontCollectionKey(glyphTypeface.Style, glyphTypeface.Weight, glyphTypeface.Stretch),
glyphTypeface);
}
}
}

5
src/Avalonia.Base/Media/IGlyphTypeface2.cs

@ -14,6 +14,11 @@ namespace Avalonia.Media
/// <returns>Returns <c>true</c> if the stream can be obtained, otherwise <c>false</c>.</returns>
bool TryGetStream([NotNullWhen(true)] out Stream? stream);
/// <summary>
/// Gets the typographic family name.
/// </summary>
string TypographicFamilyName { get; }
/// <summary>
/// Gets the localized family names.
/// <para>Keys are culture identifiers.</para>

4
src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs

@ -100,6 +100,8 @@ namespace Avalonia.Skia
_nameTable = NameTable.Load(this);
TypographicFamilyName = _nameTable.GetNameById((ushort)CultureInfo.InvariantCulture.LCID, KnownNameIds.TypographicFamilyName);
FamilyName = _nameTable.FontFamilyName((ushort)CultureInfo.InvariantCulture.LCID);
var familyNames = new Dictionary<ushort, string>(_nameTable.Languages.Count);
@ -112,6 +114,8 @@ namespace Avalonia.Skia
FamilyNames = familyNames;
}
public string TypographicFamilyName { get; }
public IReadOnlyDictionary<ushort, string> FamilyNames { get; }
public IReadOnlyList<OpenTypeTag> SupportedFeatures

2
tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj

@ -11,7 +11,9 @@
<ItemGroup>
<EmbeddedResource Include="..\Avalonia.RenderTests\*\*.ttf" />
<None Remove="Fonts\DejaVuSans.ttf" />
<None Remove="Fonts\Manrope-Light.ttf" />
<EmbeddedResource Include="Fonts\DejaVuSans.ttf" />
<EmbeddedResource Include="Fonts\Manrope-Light.ttf" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />

BIN
tests/Avalonia.Skia.UnitTests/Fonts/Manrope-Light.ttf

Binary file not shown.

27
tests/Avalonia.Skia.UnitTests/Media/EmbeddedFontCollectionTests.cs

@ -10,7 +10,9 @@ namespace Avalonia.Skia.UnitTests.Media
{
private const string s_notoMono =
"resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests#Noto Mono";
private const string s_manrope = "resm:Avalonia.Skia.UnitTests.Fonts?assembly=Avalonia.Skia.UnitTests#Manrope";
[InlineData(FontWeight.SemiLight, FontStyle.Normal)]
[InlineData(FontWeight.Bold, FontStyle.Italic)]
[InlineData(FontWeight.Heavy, FontStyle.Oblique)]
@ -64,5 +66,28 @@ namespace Avalonia.Skia.UnitTests.Media
Assert.Equal("Twitter Color Emoji", glyphTypeface.FamilyName);
}
}
[Fact]
public void Should_Get_Typeface_For_TypographicFamilyName()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
var source = new Uri(s_manrope, UriKind.Absolute);
var fontCollection = new EmbeddedFontCollection(source, source);
fontCollection.Initialize(new CustomFontManagerImpl());
Assert.True(fontCollection.TryGetGlyphTypeface("Manrope", FontStyle.Normal, FontWeight.Light, FontStretch.Normal, out var glyphTypeface));
Assert.Equal("Manrope Light", glyphTypeface.FamilyName);
Assert.True(glyphTypeface is IGlyphTypeface2);
var glyphTypeface2 = (IGlyphTypeface2)glyphTypeface;
Assert.Equal("Manrope", glyphTypeface2.TypographicFamilyName);
}
}
}
}

Loading…
Cancel
Save