Browse Source

Introduce font family mapping (#17234)

Benedikt Stebner 1 year ago
parent
commit
d3aa0c21e3

+ 28 - 2
src/Avalonia.Base/Media/FontManager.cs

@@ -26,6 +26,7 @@ namespace Avalonia.Media
 
         private readonly ConcurrentDictionary<Uri, IFontCollection> _fontCollections = new ConcurrentDictionary<Uri, IFontCollection>();
         private readonly IReadOnlyList<FontFallback>? _fontFallbacks;
+        private readonly IReadOnlyDictionary<string, FontFamily>? _fontFamilyMappings;
 
         public FontManager(IFontManagerImpl platformImpl)
         {
@@ -35,6 +36,7 @@ namespace Avalonia.Media
 
             var options = AvaloniaLocator.Current.GetService<FontManagerOptions>();
             _fontFallbacks = options?.FontFallbacks;
+            _fontFamilyMappings = options?.FontFamilyMappings;
 
             var defaultFontFamilyName = GetDefaultFontFamilyName(options);
             DefaultFontFamily = new FontFamily(defaultFontFamilyName);
@@ -91,8 +93,8 @@ namespace Avalonia.Media
         {
             glyphTypeface = null;
 
-            var fontFamily = typeface.FontFamily;
-
+            var fontFamily = GetMappedFontFamily(typeface.FontFamily);
+            
             if (typeface.FontFamily.Name == FontFamily.DefaultFontFamilyName)
             {
                 return TryGetGlyphTypeface(new Typeface(DefaultFontFamily, typeface.Style, typeface.Weight, typeface.Stretch), out glyphTypeface);
@@ -108,6 +110,20 @@ namespace Avalonia.Media
 
                         var familyName = fontFamily.FamilyNames[i];
 
+                        if(_fontFamilyMappings != null && _fontFamilyMappings.TryGetValue(familyName, out var mappedFontFamily))
+                        {
+                            if(mappedFontFamily.Key != null)
+                            {
+                                key = mappedFontFamily.Key;
+                            }
+                            else
+                            {
+                                key = new FontFamilyKey(SystemFontsKey);
+                            }
+
+                            familyName = mappedFontFamily.FamilyNames.PrimaryFamilyName;
+                        }
+
                         if (TryGetGlyphTypefaceByKeyAndName(typeface, key, familyName, out glyphTypeface) &&
                             glyphTypeface.FamilyName.Contains(familyName))
                         {
@@ -144,6 +160,16 @@ namespace Avalonia.Media
 
             //Nothing was found so use the default
             return TryGetGlyphTypeface(new Typeface(FontFamily.DefaultFontFamilyName, typeface.Style, typeface.Weight, typeface.Stretch), out glyphTypeface);
+
+            FontFamily GetMappedFontFamily(FontFamily fontFamily)
+            {
+                if (_fontFamilyMappings == null ||!_fontFamilyMappings.TryGetValue(fontFamily.FamilyNames.PrimaryFamilyName, out var mappedFontFamily))
+                {
+                    return fontFamily;
+                }
+
+                return mappedFontFamily;
+            }
         }
 
         private bool TryGetGlyphTypefaceByKeyAndName(Typeface typeface, FontFamilyKey key, string familyName, [NotNullWhen(true)] out IGlyphTypeface? glyphTypeface)

+ 17 - 0
src/Avalonia.Base/Media/FontManagerOptions.cs

@@ -4,8 +4,25 @@ namespace Avalonia.Media
 {
     public class FontManagerOptions
     {
+        /// <summary>
+        /// Gets or sets the default font family's name
+        /// </summary>
         public string? DefaultFamilyName { get; set; }
 
+        /// <summary>
+        /// Gets or sets the font fallbacks.
+        /// </summary>
+        /// <remarks>
+        /// A fallback is fullfilled before anything else when the font manager tries to match a specific codepoint.
+        /// </remarks>
         public IReadOnlyList<FontFallback>? FontFallbacks { get; set; }
+
+        /// <summary>
+        /// Gets or sets the font family mappings.
+        /// </summary>
+        /// <remarks>
+        /// A font family mapping is used if a requested family name can't be resolved.
+        /// </remarks>
+        public IReadOnlyDictionary<string, FontFamily>? FontFamilyMappings { get; set; }
     }
 }

+ 29 - 0
tests/Avalonia.Skia.UnitTests/Media/FontManagerTests.cs

@@ -1,4 +1,6 @@
 using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.Linq;
 using Avalonia.Fonts.Inter;
 using Avalonia.Headless;
@@ -335,5 +337,32 @@ namespace Avalonia.Skia.UnitTests.Media
                 }
             }
         }
+
+        [Fact]
+        public void Should_Map_FontFamily()
+        {
+            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
+            {
+                using (AvaloniaLocator.EnterScope())
+                {
+                    AvaloniaLocator.CurrentMutable.BindToSelf(new FontManagerOptions 
+                    { 
+                        DefaultFamilyName = s_fontUri, 
+                        FontFamilyMappings = new Dictionary<string, FontFamily> 
+                        { 
+                            { "Segoe UI", new FontFamily("fonts:Inter#Inter") } 
+                        }
+                    });
+
+                    FontManager.Current.AddFontCollection(new InterFontCollection());
+
+                    var result = FontManager.Current.TryGetGlyphTypeface(new Typeface("Abc, Segoe UI"), out var glyphTypeface);
+
+                    Assert.True(result);
+
+                    Assert.Equal("Inter", glyphTypeface.FamilyName);
+                }
+            }
+        }
     }
 }