Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix FontCollection glyph typeface caching #17519

Merged
merged 5 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ public override bool TryGetGlyphTypeface(string familyName, FontStyle style, Fon
glyphTypeface = syntheticGlyphTypeface;
}

//Make sure we cache the found match
glyphTypefaces.TryAdd(key, glyphTypeface);

return true;
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ public override bool TryGetGlyphTypeface(string familyName, FontStyle style, Fon
//No exact match
if (createdKey != key)
{
//Add the created glyph typeface to the cache so we can match it.
glyphTypefaces.TryAdd(createdKey, glyphTypeface);

//Try to find nearest match if possible
if (TryGetNearestMatch(glyphTypefaces, key, out var nearestMatch))
{
Expand Down
35 changes: 35 additions & 0 deletions tests/Avalonia.Skia.UnitTests/Media/EmbeddedFontCollectionTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Media.Fonts;
using Avalonia.UnitTests;
Expand Down Expand Up @@ -89,5 +92,37 @@ public void Should_Get_Typeface_For_TypographicFamilyName()
Assert.Equal("Manrope", glyphTypeface2.TypographicFamilyName);
}
}

[Fact]
public void Should_Cache_Synthetic_GlyphTypeface()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
var source = new Uri(s_manrope, UriKind.Absolute);

var fontCollection = new TestEmbeddedFontCollection(source, source);

fontCollection.Initialize(new CustomFontManagerImpl());

Assert.True(fontCollection.TryGetGlyphTypeface("Manrope", FontStyle.Normal, FontWeight.ExtraBlack, FontStretch.Normal, out var glyphTypeface));

Assert.True(fontCollection.GlyphTypefaceCache.TryGetValue("Manrope", out var glyphTypefaces));

Assert.Equal(2, glyphTypefaces.Count);

fontCollection.TryGetGlyphTypeface("Manrope", FontStyle.Normal, FontWeight.ExtraBlack, FontStretch.Normal, out var otherGlyphTypeface);

Assert.Equal(glyphTypeface, otherGlyphTypeface);
}
}

private class TestEmbeddedFontCollection : EmbeddedFontCollection
{
public TestEmbeddedFontCollection(Uri key, Uri source) : base(key, source)
{
}

public IDictionary<string, ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>> GlyphTypefaceCache => _glyphTypefaceCache;
}
}
}
40 changes: 39 additions & 1 deletion tests/Avalonia.Skia.UnitTests/Media/FontCollectionTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using Avalonia.Media;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Media.Fonts;
using Avalonia.UnitTests;
using Xunit;

namespace Avalonia.Skia.UnitTests.Media
Expand All @@ -24,5 +27,40 @@ public void Should_Get_Implicit_Typeface(string input, string familyName, FontSt
Assert.Equal(weight, result.Weight);
Assert.Equal(FontStretch.Normal, result.Stretch);
}

[Win32Fact("Relies on some installed font family")]
public void Should_Cache_Nearest_Match()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
var fontManager = FontManager.Current;

var fontCollection = new TestSystemFontCollection(FontManager.Current);

Assert.True(fontCollection.TryGetGlyphTypeface("Arial", FontStyle.Normal, FontWeight.ExtraBlack, FontStretch.Normal, out var glyphTypeface));

Assert.True(glyphTypeface.FontSimulations == FontSimulations.Bold);

Assert.True(fontCollection.GlyphTypfaceCache.TryGetValue("Arial", out var glyphTypefaces));

Assert.Equal(2, glyphTypefaces.Count);

Assert.True(glyphTypefaces.ContainsKey(new FontCollectionKey(FontStyle.Normal, FontWeight.Black, FontStretch.Normal)));

fontCollection.TryGetGlyphTypeface("Arial", FontStyle.Normal, FontWeight.ExtraBlack, FontStretch.Normal, out var otherGlyphTypeface);

Assert.Equal(glyphTypeface, otherGlyphTypeface);
}
}

private class TestSystemFontCollection : SystemFontCollection
{
public TestSystemFontCollection(FontManager fontManager) : base(fontManager)
{

}

public IDictionary<string, ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>> GlyphTypfaceCache => _glyphTypefaceCache;
}
}
}