diff --git a/src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs b/src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs index d06bad8001..9002fd0fde 100644 --- a/src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs +++ b/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(); }); diff --git a/src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs b/src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs index ce20ace90c..9e233aef26 100644 --- a/src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs +++ b/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(); + 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(); + }); + + typefaces.TryAdd( + new FontCollectionKey(glyphTypeface.Style, glyphTypeface.Weight, glyphTypeface.Stretch), + glyphTypeface); } } } diff --git a/src/Avalonia.Base/Media/IGlyphTypeface2.cs b/src/Avalonia.Base/Media/IGlyphTypeface2.cs index 2c7ea58bcb..84b892dae3 100644 --- a/src/Avalonia.Base/Media/IGlyphTypeface2.cs +++ b/src/Avalonia.Base/Media/IGlyphTypeface2.cs @@ -14,6 +14,11 @@ namespace Avalonia.Media /// Returns true if the stream can be obtained, otherwise false. bool TryGetStream([NotNullWhen(true)] out Stream? stream); + /// + /// Gets the typographic family name. + /// + string TypographicFamilyName { get; } + /// /// Gets the localized family names. /// Keys are culture identifiers. diff --git a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs index cdf7807b01..06fe0e333c 100644 --- a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs +++ b/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(_nameTable.Languages.Count); @@ -112,6 +114,8 @@ namespace Avalonia.Skia FamilyNames = familyNames; } + public string TypographicFamilyName { get; } + public IReadOnlyDictionary FamilyNames { get; } public IReadOnlyList SupportedFeatures diff --git a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj index c40454dc62..d006c8c189 100644 --- a/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj +++ b/tests/Avalonia.Skia.UnitTests/Avalonia.Skia.UnitTests.csproj @@ -11,7 +11,9 @@ + + diff --git a/tests/Avalonia.Skia.UnitTests/Fonts/Manrope-Light.ttf b/tests/Avalonia.Skia.UnitTests/Fonts/Manrope-Light.ttf new file mode 100644 index 0000000000..4942924893 Binary files /dev/null and b/tests/Avalonia.Skia.UnitTests/Fonts/Manrope-Light.ttf differ diff --git a/tests/Avalonia.Skia.UnitTests/Media/EmbeddedFontCollectionTests.cs b/tests/Avalonia.Skia.UnitTests/Media/EmbeddedFontCollectionTests.cs index 006abe9278..910e87131a 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/EmbeddedFontCollectionTests.cs +++ b/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); + } + } } }