Skip to content

Commit 4f2dd67

Browse files
authored
Add TypographicFamilyName to GlyphTypeface and use it for FontCollection (AvaloniaUI#16844)
* Introduce TypographicFamilyName * Add TypographicFamilyName to the FontCollection cache if available
1 parent de86c5a commit 4f2dd67

File tree

7 files changed

+70
-21
lines changed

7 files changed

+70
-21
lines changed

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,15 @@ private void AddGlyphTypeface(IGlyphTypeface glyphTypeface)
131131
{
132132
if (glyphTypeface is IGlyphTypeface2 glyphTypeface2)
133133
{
134-
foreach (var kvp in glyphTypeface2.FamilyNames)
134+
//Add the TypographicFamilyName to the cache
135+
if (!string.IsNullOrEmpty(glyphTypeface2.TypographicFamilyName))
135136
{
136-
var familyName = kvp.Value;
137+
AddGlyphTypefaceByFamilyName(glyphTypeface2.TypographicFamilyName, glyphTypeface);
138+
}
137139

138-
AddGlyphTypefaceByFamilyName(familyName, glyphTypeface);
140+
foreach (var kvp in glyphTypeface2.FamilyNames)
141+
{
142+
AddGlyphTypefaceByFamilyName(kvp.Value, glyphTypeface);
139143
}
140144
}
141145
else
@@ -150,7 +154,7 @@ void AddGlyphTypefaceByFamilyName(string familyName, IGlyphTypeface glyphTypefac
150154
var typefaces = _glyphTypefaceCache.GetOrAdd(familyName,
151155
x =>
152156
{
153-
_fontFamilies.Add(new FontFamily(_key, glyphTypeface.FamilyName));
157+
_fontFamilies.Add(new FontFamily(_key, familyName));
154158

155159
return new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
156160
});

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

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -160,26 +160,35 @@ private void LoadGlyphTypefaces(IFontManagerImpl fontManager, Uri source)
160160
{
161161
var stream = assetLoader.Open(fontAsset);
162162

163-
if (fontManager.TryCreateGlyphTypeface(stream, FontSimulations.None, out var glyphTypeface))
163+
if (!fontManager.TryCreateGlyphTypeface(stream, FontSimulations.None, out var glyphTypeface))
164164
{
165-
if (!_glyphTypefaceCache.TryGetValue(glyphTypeface.FamilyName, out var glyphTypefaces))
166-
{
167-
glyphTypefaces = new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
165+
continue;
166+
}
168167

169-
if (_glyphTypefaceCache.TryAdd(glyphTypeface.FamilyName, glyphTypefaces))
170-
{
171-
//Move the user defined system font to the start of the collection
172-
_familyNames.Insert(0, glyphTypeface.FamilyName);
173-
}
174-
}
168+
//Add TypographicFamilyName to the cache
169+
if (glyphTypeface is IGlyphTypeface2 glyphTypeface2 && !string.IsNullOrEmpty(glyphTypeface2.TypographicFamilyName))
170+
{
171+
AddGlyphTypefaceByFamilyName(glyphTypeface2.TypographicFamilyName, glyphTypeface);
172+
}
173+
174+
AddGlyphTypefaceByFamilyName(glyphTypeface.FamilyName, glyphTypeface);
175+
}
175176

176-
var key = new FontCollectionKey(
177-
glyphTypeface.Style,
178-
glyphTypeface.Weight,
179-
glyphTypeface.Stretch);
177+
return;
180178

181-
glyphTypefaces.TryAdd(key, glyphTypeface);
182-
}
179+
void AddGlyphTypefaceByFamilyName(string familyName, IGlyphTypeface glyphTypeface)
180+
{
181+
var typefaces = _glyphTypefaceCache.GetOrAdd(familyName,
182+
x =>
183+
{
184+
_familyNames.Insert(0, familyName);
185+
186+
return new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
187+
});
188+
189+
typefaces.TryAdd(
190+
new FontCollectionKey(glyphTypeface.Style, glyphTypeface.Weight, glyphTypeface.Stretch),
191+
glyphTypeface);
183192
}
184193
}
185194
}

src/Avalonia.Base/Media/IGlyphTypeface2.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ internal interface IGlyphTypeface2 : IGlyphTypeface
1414
/// <returns>Returns <c>true</c> if the stream can be obtained, otherwise <c>false</c>.</returns>
1515
bool TryGetStream([NotNullWhen(true)] out Stream? stream);
1616

17+
/// <summary>
18+
/// Gets the typographic family name.
19+
/// </summary>
20+
string TypographicFamilyName { get; }
21+
1722
/// <summary>
1823
/// Gets the localized family names.
1924
/// <para>Keys are culture identifiers.</para>

src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ public GlyphTypefaceImpl(SKTypeface typeface, FontSimulations fontSimulations)
100100

101101
_nameTable = NameTable.Load(this);
102102

103+
TypographicFamilyName = _nameTable.GetNameById((ushort)CultureInfo.InvariantCulture.LCID, KnownNameIds.TypographicFamilyName);
104+
103105
FamilyName = _nameTable.FontFamilyName((ushort)CultureInfo.InvariantCulture.LCID);
104106

105107
var familyNames = new Dictionary<ushort, string>(_nameTable.Languages.Count);
@@ -112,6 +114,8 @@ public GlyphTypefaceImpl(SKTypeface typeface, FontSimulations fontSimulations)
112114
FamilyNames = familyNames;
113115
}
114116

117+
public string TypographicFamilyName { get; }
118+
115119
public IReadOnlyDictionary<ushort, string> FamilyNames { get; }
116120

117121
public IReadOnlyList<OpenTypeTag> SupportedFeatures

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
<ItemGroup>
1212
<EmbeddedResource Include="..\Avalonia.RenderTests\*\*.ttf" />
1313
<None Remove="Fonts\DejaVuSans.ttf" />
14+
<None Remove="Fonts\Manrope-Light.ttf" />
1415
<EmbeddedResource Include="Fonts\DejaVuSans.ttf" />
16+
<EmbeddedResource Include="Fonts\Manrope-Light.ttf" />
1517
</ItemGroup>
1618
<ItemGroup>
1719
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj" />
Binary file not shown.

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ public class EmbeddedFontCollectionTests
1010
{
1111
private const string s_notoMono =
1212
"resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests#Noto Mono";
13-
13+
14+
private const string s_manrope = "resm:Avalonia.Skia.UnitTests.Fonts?assembly=Avalonia.Skia.UnitTests#Manrope";
15+
1416
[InlineData(FontWeight.SemiLight, FontStyle.Normal)]
1517
[InlineData(FontWeight.Bold, FontStyle.Italic)]
1618
[InlineData(FontWeight.Heavy, FontStyle.Oblique)]
@@ -64,5 +66,28 @@ public void Should_Get_Typeface_For_Partial_FamilyName()
6466
Assert.Equal("Twitter Color Emoji", glyphTypeface.FamilyName);
6567
}
6668
}
69+
70+
[Fact]
71+
public void Should_Get_Typeface_For_TypographicFamilyName()
72+
{
73+
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
74+
{
75+
var source = new Uri(s_manrope, UriKind.Absolute);
76+
77+
var fontCollection = new EmbeddedFontCollection(source, source);
78+
79+
fontCollection.Initialize(new CustomFontManagerImpl());
80+
81+
Assert.True(fontCollection.TryGetGlyphTypeface("Manrope", FontStyle.Normal, FontWeight.Light, FontStretch.Normal, out var glyphTypeface));
82+
83+
Assert.Equal("Manrope Light", glyphTypeface.FamilyName);
84+
85+
Assert.True(glyphTypeface is IGlyphTypeface2);
86+
87+
var glyphTypeface2 = (IGlyphTypeface2)glyphTypeface;
88+
89+
Assert.Equal("Manrope", glyphTypeface2.TypographicFamilyName);
90+
}
91+
}
6792
}
6893
}

0 commit comments

Comments
 (0)