Browse Source

Make typeface matching and synthetic typeface creation customizable (#18890)

* Make typeface matching and synthetic typeface creation customizable

* Rename test collection

* Revert breaking change

* Directly use the DefaultFontFamily name when the alias is being used
release/11.3.5
Benedikt Stebner 9 months ago
parent
commit
b7c2881655
  1. 66
      src/Avalonia.Base/Media/FontManager.cs
  2. 14
      src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs
  3. 84
      src/Avalonia.Base/Media/Fonts/FontCollectionBase.cs
  4. 11
      src/Avalonia.Base/Media/Fonts/IFontCollection.cs
  5. 6
      src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs
  6. 6
      src/Headless/Avalonia.Headless/HeadlessPlatformStubs.cs
  7. 34
      tests/Avalonia.Skia.UnitTests/Media/EmbeddedFontCollectionTests.cs
  8. 111
      tests/Avalonia.Skia.UnitTests/Media/FontCollectionTests.cs

66
src/Avalonia.Base/Media/FontManager.cs

@ -109,9 +109,9 @@ namespace Avalonia.Media
var familyName = fontFamily.FamilyNames[i]; var familyName = fontFamily.FamilyNames[i];
if(_fontFamilyMappings != null && _fontFamilyMappings.TryGetValue(familyName, out var mappedFontFamily)) if (_fontFamilyMappings != null && _fontFamilyMappings.TryGetValue(familyName, out var mappedFontFamily))
{ {
if(mappedFontFamily.Key != null) if (mappedFontFamily.Key != null)
{ {
key = mappedFontFamily.Key; key = mappedFontFamily.Key;
} }
@ -123,6 +123,11 @@ namespace Avalonia.Media
familyName = mappedFontFamily.FamilyNames.PrimaryFamilyName; familyName = mappedFontFamily.FamilyNames.PrimaryFamilyName;
} }
if (familyName == FontFamily.DefaultFontFamilyName)
{
return TryGetGlyphTypeface(new Typeface(DefaultFontFamily, typeface.Style, typeface.Weight, typeface.Stretch), out glyphTypeface);
}
if (TryGetGlyphTypefaceByKeyAndName(typeface, key, familyName, out glyphTypeface) && if (TryGetGlyphTypefaceByKeyAndName(typeface, key, familyName, out glyphTypeface) &&
glyphTypeface.FamilyName.Contains(familyName)) glyphTypeface.FamilyName.Contains(familyName))
{ {
@ -274,6 +279,11 @@ namespace Avalonia.Media
var familyName = fontFamily.FamilyNames[i]; var familyName = fontFamily.FamilyNames[i];
var source = key.Source.EnsureAbsolute(key.BaseUri); var source = key.Source.EnsureAbsolute(key.BaseUri);
if(familyName == FontFamily.DefaultFontFamilyName)
{
familyName = DefaultFontFamily.Name;
}
if (TryGetFontCollection(source, out var fontCollection) && if (TryGetFontCollection(source, out var fontCollection) &&
fontCollection.TryMatchCharacter(codepoint, fontStyle, fontWeight, fontStretch, familyName, culture, out typeface)) fontCollection.TryMatchCharacter(codepoint, fontStyle, fontWeight, fontStretch, familyName, culture, out typeface))
{ {
@ -286,58 +296,6 @@ namespace Avalonia.Media
return PlatformImpl.TryMatchCharacter(codepoint, fontStyle, fontWeight, fontStretch, culture, out typeface); return PlatformImpl.TryMatchCharacter(codepoint, fontStyle, fontWeight, fontStretch, culture, out typeface);
} }
/// <summary>
/// Tries to create a synthetic glyph typefacefor specified source glyph typeface and font properties.
/// </summary>
/// <param name="fontManager">The font manager implementation.</param>
/// <param name="glyphTypeface">The source glyph typeface.</param>
/// <param name="style">The requested font style.</param>
/// <param name="weight">The requested font weight.</param>
/// <param name="syntheticGlyphTypeface">The created synthetic glyph typeface.</param>
/// <returns>
/// <c>True</c>, if the <see cref="FontManager"/> could create a synthetic glyph typeface, <c>False</c> otherwise.
/// </returns>
internal static bool TryCreateSyntheticGlyphTypeface(IFontManagerImpl fontManager, IGlyphTypeface glyphTypeface, FontStyle style, FontWeight weight,
[NotNullWhen(true)] out IGlyphTypeface? syntheticGlyphTypeface)
{
if (fontManager == null)
{
syntheticGlyphTypeface = null;
return false;
}
if (glyphTypeface is IGlyphTypeface2 glyphTypeface2)
{
var fontSimulations = FontSimulations.None;
if (style != FontStyle.Normal && glyphTypeface2.Style != style)
{
fontSimulations |= FontSimulations.Oblique;
}
if ((int)weight >= 600 && glyphTypeface2.Weight < weight)
{
fontSimulations |= FontSimulations.Bold;
}
if (fontSimulations != FontSimulations.None && glyphTypeface2.TryGetStream(out var stream))
{
using (stream)
{
fontManager.TryCreateGlyphTypeface(stream, fontSimulations,
out syntheticGlyphTypeface);
return syntheticGlyphTypeface != null;
}
}
}
syntheticGlyphTypeface = null;
return false;
}
internal IReadOnlyList<Typeface> GetFamilyTypefaces(FontFamily fontFamily) internal IReadOnlyList<Typeface> GetFamilyTypefaces(FontFamily fontFamily)
{ {
var key = fontFamily.Key; var key = fontFamily.Key;

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

@ -71,14 +71,16 @@ namespace Avalonia.Media.Fonts
if (TryGetNearestMatch(glyphTypefaces, key, out glyphTypeface)) if (TryGetNearestMatch(glyphTypefaces, key, out glyphTypeface))
{ {
if(_fontManager != null && FontManager.TryCreateSyntheticGlyphTypeface(_fontManager, glyphTypeface, style, weight, out var syntheticGlyphTypeface)) var matchedKey = new FontCollectionKey(glyphTypeface.Style, glyphTypeface.Weight, glyphTypeface.Stretch);
if(matchedKey != key)
{ {
glyphTypeface = syntheticGlyphTypeface; if (TryCreateSyntheticGlyphTypeface(glyphTypeface, style, weight, stretch, out var syntheticGlyphTypeface))
{
glyphTypeface = syntheticGlyphTypeface;
}
} }
//Make sure we cache the found match
glyphTypefaces.TryAdd(key, glyphTypeface);
return true; return true;
} }
} }
@ -143,7 +145,7 @@ namespace Avalonia.Media.Fonts
} }
} }
bool IFontCollection2.TryGetFamilyTypefaces(string familyName, [NotNullWhen(true)] out IReadOnlyList<Typeface>? familyTypefaces) public bool TryGetFamilyTypefaces(string familyName, [NotNullWhen(true)] out IReadOnlyList<Typeface>? familyTypefaces)
{ {
familyTypefaces = null; familyTypefaces = null;

84
src/Avalonia.Base/Media/Fonts/FontCollectionBase.cs

@ -23,7 +23,7 @@ namespace Avalonia.Media.Fonts
public abstract bool TryGetGlyphTypeface(string familyName, FontStyle style, FontWeight weight, FontStretch stretch, public abstract bool TryGetGlyphTypeface(string familyName, FontStyle style, FontWeight weight, FontStretch stretch,
[NotNullWhen(true)] out IGlyphTypeface? glyphTypeface); [NotNullWhen(true)] out IGlyphTypeface? glyphTypeface);
public bool TryMatchCharacter(int codepoint, FontStyle style, FontWeight weight, FontStretch stretch, public virtual bool TryMatchCharacter(int codepoint, FontStyle style, FontWeight weight, FontStretch stretch,
string? familyName, CultureInfo? culture, out Typeface match) string? familyName, CultureInfo? culture, out Typeface match)
{ {
match = default; match = default;
@ -59,6 +59,88 @@ namespace Avalonia.Media.Fonts
return false; return false;
} }
public virtual bool TryCreateSyntheticGlyphTypeface(
IGlyphTypeface glyphTypeface,
FontStyle style,
FontWeight weight,
FontStretch stretch,
[NotNullWhen(true)] out IGlyphTypeface? syntheticGlyphTypeface)
{
syntheticGlyphTypeface = null;
//Source family should be present in the cache.
if (!_glyphTypefaceCache.TryGetValue(glyphTypeface.FamilyName, out var glyphTypefaces))
{
return false;
}
var fontManager = FontManager.Current.PlatformImpl;
var key = new FontCollectionKey(style, weight, stretch);
var currentKey =
new FontCollectionKey(glyphTypeface.Style, glyphTypeface.Weight, glyphTypeface.Stretch);
if (currentKey == key)
{
return false;
}
if (glyphTypeface is not IGlyphTypeface2 glyphTypeface2)
{
return false;
}
var fontSimulations = FontSimulations.None;
if (style != FontStyle.Normal && glyphTypeface2.Style != style)
{
fontSimulations |= FontSimulations.Oblique;
}
if ((int)weight >= 600 && glyphTypeface2.Weight < weight)
{
fontSimulations |= FontSimulations.Bold;
}
if (fontSimulations != FontSimulations.None && glyphTypeface2.TryGetStream(out var stream))
{
using (stream)
{
if (fontManager.TryCreateGlyphTypeface(stream, fontSimulations, out syntheticGlyphTypeface))
{
//Add the TypographicFamilyName to the cache
if (!string.IsNullOrEmpty(glyphTypeface2.TypographicFamilyName))
{
AddGlyphTypefaceByFamilyName(glyphTypeface2.TypographicFamilyName, syntheticGlyphTypeface);
}
foreach (var kvp in glyphTypeface2.FamilyNames)
{
AddGlyphTypefaceByFamilyName(kvp.Value, syntheticGlyphTypeface);
}
return true;
}
return false;
}
}
return false;
void AddGlyphTypefaceByFamilyName(string familyName, IGlyphTypeface glyphTypeface)
{
var typefaces = _glyphTypefaceCache.GetOrAdd(familyName,
x =>
{
return new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
});
typefaces.TryAdd(key, glyphTypeface);
}
}
public abstract void Initialize(IFontManagerImpl fontManager); public abstract void Initialize(IFontManagerImpl fontManager);
public abstract IEnumerator<FontFamily> GetEnumerator(); public abstract IEnumerator<FontFamily> GetEnumerator();

11
src/Avalonia.Base/Media/Fonts/IFontCollection.cs

@ -59,5 +59,16 @@ namespace Avalonia.Media.Fonts
/// <c>True</c>, if the <see cref="IFontCollection2"/> could get the list of typefaces, <c>False</c> otherwise. /// <c>True</c>, if the <see cref="IFontCollection2"/> could get the list of typefaces, <c>False</c> otherwise.
/// </returns> /// </returns>
bool TryGetFamilyTypefaces(string familyName, [NotNullWhen(true)] out IReadOnlyList<Typeface>? familyTypefaces); bool TryGetFamilyTypefaces(string familyName, [NotNullWhen(true)] out IReadOnlyList<Typeface>? familyTypefaces);
/// <summary>
/// Try to get a synthetic glyph typeface for given parameters.
/// </summary>
/// <param name="glyphTypeface">The glyph typeface we try to synthesize.</param>
/// <param name="style">The font style.</param>
/// <param name="weight">The font weight.</param>
/// <param name="stretch">The font stretch.</param>
/// <param name="syntheticGlyphTypeface"></param>
/// <returns>Returns <c>true</c> if a synthetic glyph typface can be created; otherwise, <c>false</c></returns>
bool TryCreateSyntheticGlyphTypeface(IGlyphTypeface glyphTypeface, FontStyle style, FontWeight weight, FontStretch stretch, [NotNullWhen(true)] out IGlyphTypeface? syntheticGlyphTypeface);
} }
} }

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

@ -91,9 +91,11 @@ namespace Avalonia.Media.Fonts
} }
//Try to create a synthetic glyph typeface //Try to create a synthetic glyph typeface
if (FontManager.TryCreateSyntheticGlyphTypeface(_fontManager.PlatformImpl, glyphTypeface, style, weight, out var syntheticGlyphTypeface)) if (TryCreateSyntheticGlyphTypeface(glyphTypeface, style, weight, stretch, out var syntheticGlyphTypeface))
{ {
glyphTypeface = syntheticGlyphTypeface; glyphTypeface = syntheticGlyphTypeface;
return true;
} }
} }
@ -159,7 +161,7 @@ namespace Avalonia.Media.Fonts
} }
} }
bool IFontCollection2.TryGetFamilyTypefaces(string familyName, [NotNullWhen(true)] out IReadOnlyList<Typeface>? familyTypefaces) public bool TryGetFamilyTypefaces(string familyName, [NotNullWhen(true)] out IReadOnlyList<Typeface>? familyTypefaces)
{ {
familyTypefaces = null; familyTypefaces = null;

6
src/Headless/Avalonia.Headless/HeadlessPlatformStubs.cs

@ -245,7 +245,11 @@ namespace Avalonia.Headless
public virtual bool TryCreateGlyphTypeface(Stream stream, FontSimulations fontSimulations, out IGlyphTypeface glyphTypeface) public virtual bool TryCreateGlyphTypeface(Stream stream, FontSimulations fontSimulations, out IGlyphTypeface glyphTypeface)
{ {
glyphTypeface = new HeadlessGlyphTypefaceImpl(FontFamily.DefaultFontFamilyName, FontStyle.Normal, FontWeight.Normal, FontStretch.Normal); glyphTypeface = new HeadlessGlyphTypefaceImpl(
FontFamily.DefaultFontFamilyName,
fontSimulations.HasFlag(FontSimulations.Oblique) ? FontStyle.Italic : FontStyle.Normal,
fontSimulations.HasFlag(FontSimulations.Bold) ? FontWeight.Bold : FontWeight.Normal,
FontStretch.Normal);
TryCreateGlyphTypefaceCount++; TryCreateGlyphTypefaceCount++;

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

@ -4,6 +4,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Fonts; using Avalonia.Media.Fonts;
using Avalonia.UnitTests; using Avalonia.UnitTests;
@ -18,6 +19,7 @@ namespace Avalonia.Skia.UnitTests.Media
private const string s_manrope = "resm:Avalonia.Skia.UnitTests.Fonts?assembly=Avalonia.Skia.UnitTests#Manrope"; private const string s_manrope = "resm:Avalonia.Skia.UnitTests.Fonts?assembly=Avalonia.Skia.UnitTests#Manrope";
[InlineData(FontWeight.SemiLight, FontStyle.Normal)] [InlineData(FontWeight.SemiLight, FontStyle.Normal)]
[InlineData(FontWeight.Bold, FontStyle.Italic)] [InlineData(FontWeight.Bold, FontStyle.Italic)]
[InlineData(FontWeight.Heavy, FontStyle.Oblique)] [InlineData(FontWeight.Heavy, FontStyle.Oblique)]
@ -28,7 +30,7 @@ namespace Avalonia.Skia.UnitTests.Media
{ {
var source = new Uri(s_notoMono, UriKind.Absolute); var source = new Uri(s_notoMono, UriKind.Absolute);
var fontCollection = new EmbeddedFontCollection(source, source); var fontCollection = new TestEmbeddedFontCollection(source, source);
fontCollection.Initialize(new CustomFontManagerImpl()); fontCollection.Initialize(new CustomFontManagerImpl());
@ -47,7 +49,7 @@ namespace Avalonia.Skia.UnitTests.Media
{ {
var source = new Uri(s_notoMono, UriKind.Absolute); var source = new Uri(s_notoMono, UriKind.Absolute);
var fontCollection = new EmbeddedFontCollection(source, source); var fontCollection = new TestEmbeddedFontCollection(source, source);
fontCollection.Initialize(new CustomFontManagerImpl()); fontCollection.Initialize(new CustomFontManagerImpl());
@ -62,7 +64,7 @@ namespace Avalonia.Skia.UnitTests.Media
{ {
var source = new Uri("resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests#T", UriKind.Absolute); var source = new Uri("resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests#T", UriKind.Absolute);
var fontCollection = new EmbeddedFontCollection(source, source); var fontCollection = new TestEmbeddedFontCollection(source, source);
fontCollection.Initialize(new CustomFontManagerImpl()); fontCollection.Initialize(new CustomFontManagerImpl());
@ -79,7 +81,7 @@ namespace Avalonia.Skia.UnitTests.Media
{ {
var source = new Uri(s_manrope, UriKind.Absolute); var source = new Uri(s_manrope, UriKind.Absolute);
var fontCollection = new EmbeddedFontCollection(source, source); var fontCollection = new TestEmbeddedFontCollection(source, source);
fontCollection.Initialize(new CustomFontManagerImpl()); fontCollection.Initialize(new CustomFontManagerImpl());
@ -102,7 +104,7 @@ namespace Avalonia.Skia.UnitTests.Media
{ {
var source = new Uri(s_manrope, UriKind.Absolute); var source = new Uri(s_manrope, UriKind.Absolute);
var fontCollection = new TestEmbeddedFontCollection(source, source); var fontCollection = new TestEmbeddedFontCollection(source, source, true);
fontCollection.Initialize(new CustomFontManagerImpl()); fontCollection.Initialize(new CustomFontManagerImpl());
@ -120,11 +122,31 @@ namespace Avalonia.Skia.UnitTests.Media
private class TestEmbeddedFontCollection : EmbeddedFontCollection private class TestEmbeddedFontCollection : EmbeddedFontCollection
{ {
public TestEmbeddedFontCollection(Uri key, Uri source) : base(key, source) private bool _createSyntheticTypefaces;
public TestEmbeddedFontCollection(Uri key, Uri source, bool createSyntheticTypefaces = false) : base(key, source)
{ {
_createSyntheticTypefaces = createSyntheticTypefaces;
} }
public IDictionary<string, ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>> GlyphTypefaceCache => _glyphTypefaceCache; public IDictionary<string, ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>> GlyphTypefaceCache => _glyphTypefaceCache;
public override bool TryCreateSyntheticGlyphTypeface(
IGlyphTypeface glyphTypeface,
FontStyle style,
FontWeight weight,
FontStretch stretch,
[NotNullWhen(true)] out IGlyphTypeface? syntheticGlyphTypeface)
{
if (!_createSyntheticTypefaces)
{
syntheticGlyphTypeface = null;
return false;
}
return base.TryCreateSyntheticGlyphTypeface(glyphTypeface, style, weight, stretch, out syntheticGlyphTypeface);
}
} }
} }
} }

111
tests/Avalonia.Skia.UnitTests/Media/FontCollectionTests.cs

@ -1,7 +1,10 @@
#nullable enable #nullable enable
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Fonts; using Avalonia.Media.Fonts;
using Avalonia.UnitTests; using Avalonia.UnitTests;
@ -11,6 +14,9 @@ namespace Avalonia.Skia.UnitTests.Media
{ {
public class FontCollectionTests public class FontCollectionTests
{ {
private const string NotoMono =
"resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests";
[InlineData("Hello World 6", "Hello World 6", FontStyle.Normal, FontWeight.Normal)] [InlineData("Hello World 6", "Hello World 6", FontStyle.Normal, FontWeight.Normal)]
[InlineData("Hello World Italic", "Hello World", FontStyle.Italic, FontWeight.Normal)] [InlineData("Hello World Italic", "Hello World", FontStyle.Italic, FontWeight.Normal)]
[InlineData("Hello World Italic Bold", "Hello World", FontStyle.Italic, FontWeight.Bold)] [InlineData("Hello World Italic Bold", "Hello World", FontStyle.Italic, FontWeight.Bold)]
@ -41,8 +47,6 @@ namespace Avalonia.Skia.UnitTests.Media
Assert.True(fontCollection.TryGetGlyphTypeface("Arial", FontStyle.Normal, FontWeight.ExtraBlack, FontStretch.Normal, out var glyphTypeface)); Assert.True(fontCollection.TryGetGlyphTypeface("Arial", FontStyle.Normal, FontWeight.ExtraBlack, FontStretch.Normal, out var glyphTypeface));
Assert.True(glyphTypeface.FontSimulations == FontSimulations.Bold);
Assert.True(fontCollection.GlyphTypefaceCache.TryGetValue("Arial", out var glyphTypefaces)); Assert.True(fontCollection.GlyphTypefaceCache.TryGetValue("Arial", out var glyphTypefaces));
Assert.Equal(2, glyphTypefaces.Count); Assert.Equal(2, glyphTypefaces.Count);
@ -64,5 +68,108 @@ namespace Avalonia.Skia.UnitTests.Media
public IDictionary<string, ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>> GlyphTypefaceCache => _glyphTypefaceCache; public IDictionary<string, ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>> GlyphTypefaceCache => _glyphTypefaceCache;
} }
[Fact]
public void Should_Use_Fallback()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
var source = new Uri(NotoMono, UriKind.Absolute);
var fallback = new FontFallback { FontFamily = new FontFamily("Arial"), UnicodeRange = new UnicodeRange('A', 'A') };
var fontCollection = new CustomizableFontCollection(source, source, new[] { fallback });
fontCollection.Initialize(new CustomFontManagerImpl());
Assert.True(fontCollection.TryMatchCharacter('A', FontStyle.Normal, FontWeight.Normal, FontStretch.Normal, null, null, out var match));
Assert.Equal("Arial", match.FontFamily.Name);
}
}
[Fact]
public void Should_Ignore_FontFamily()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
var source = new Uri(NotoMono + "#Noto Mono", UriKind.Absolute);
var ignorable = new FontFamily(new Uri(NotoMono, UriKind.Absolute), "Noto Mono");
var typeface = new Typeface(ignorable);
var fontCollection = new CustomizableFontCollection(source, source, null, new[] { ignorable });
fontCollection.Initialize(new CustomFontManagerImpl());
Assert.False(fontCollection.TryCreateSyntheticGlyphTypeface(
typeface.GlyphTypeface,
FontStyle.Italic,
FontWeight.DemiBold,
FontStretch.Normal,
out var syntheticGlyphTypeface));
}
}
private class CustomizableFontCollection : EmbeddedFontCollection
{
private readonly IReadOnlyList<FontFallback>? _fallbacks;
private readonly IReadOnlyList<FontFamily>? _ignorables;
public CustomizableFontCollection(Uri key, Uri source, IReadOnlyList<FontFallback>? fallbacks = null, IReadOnlyList<FontFamily>? ignorables = null) : base(key, source)
{
_fallbacks = fallbacks;
_ignorables = ignorables;
}
public override bool TryMatchCharacter(
int codepoint,
FontStyle style,
FontWeight weight,
FontStretch stretch,
string? familyName,
CultureInfo? culture,
out Typeface match)
{
if(_fallbacks is not null)
{
foreach (var fallback in _fallbacks)
{
if (fallback.UnicodeRange.IsInRange(codepoint))
{
match = new Typeface(fallback.FontFamily, style, weight, stretch);
return true;
}
}
}
return base.TryMatchCharacter(codepoint, style, weight, stretch, familyName, culture, out match);
}
public override bool TryCreateSyntheticGlyphTypeface(
IGlyphTypeface glyphTypeface,
FontStyle style,
FontWeight weight,
FontStretch stretch,
[NotNullWhen(true)] out IGlyphTypeface? syntheticGlyphTypeface)
{
syntheticGlyphTypeface = null;
if(_ignorables is not null)
{
foreach (var ignorable in _ignorables)
{
if (glyphTypeface.FamilyName == ignorable.Name || glyphTypeface is IGlyphTypeface2 glyphTypeface2 && glyphTypeface2.TypographicFamilyName == ignorable.Name)
{
return false;
}
}
}
return base.TryCreateSyntheticGlyphTypeface(glyphTypeface, style, weight, stretch, out syntheticGlyphTypeface);
}
}
} }
} }

Loading…
Cancel
Save