|
|
|
@ -15,9 +15,11 @@ namespace Avalonia.Media |
|
|
|
/// </summary>
|
|
|
|
public sealed class FontManager |
|
|
|
{ |
|
|
|
internal static Uri SystemFontsKey = new Uri("fonts:SystemFonts"); |
|
|
|
internal static Uri SystemFontsKey = new Uri("fonts:SystemFonts", UriKind.Absolute); |
|
|
|
|
|
|
|
public const string FontCollectionScheme = "fonts"; |
|
|
|
public const string SystemFontScheme = "systemfont"; |
|
|
|
public const string CompositeFontScheme = "compositefont"; |
|
|
|
|
|
|
|
private readonly ConcurrentDictionary<Uri, IFontCollection> _fontCollections = new ConcurrentDictionary<Uri, IFontCollection>(); |
|
|
|
private readonly IReadOnlyList<FontFallback>? _fontFallbacks; |
|
|
|
@ -95,69 +97,86 @@ namespace Avalonia.Media |
|
|
|
|
|
|
|
var fontFamily = typeface.FontFamily; |
|
|
|
|
|
|
|
if(typeface.FontFamily.Name == FontFamily.DefaultFontFamilyName) |
|
|
|
if (typeface.FontFamily.Name == FontFamily.DefaultFontFamilyName) |
|
|
|
{ |
|
|
|
return TryGetGlyphTypeface(new Typeface(DefaultFontFamily, typeface.Style, typeface.Weight, typeface.Stretch), out glyphTypeface); |
|
|
|
} |
|
|
|
|
|
|
|
if (fontFamily.Key is FontFamilyKey key) |
|
|
|
if (fontFamily.Key is FontFamilyKey) |
|
|
|
{ |
|
|
|
var source = key.Source; |
|
|
|
|
|
|
|
if (!source.IsAbsoluteUri) |
|
|
|
if (fontFamily.Key is CompositeFontFamilyKey compositeKey) |
|
|
|
{ |
|
|
|
if (key.BaseUri == null) |
|
|
|
for (int i = 0; i < compositeKey.Keys.Count; i++) |
|
|
|
{ |
|
|
|
throw new NotSupportedException($"{nameof(key.BaseUri)} can't be null."); |
|
|
|
} |
|
|
|
var key = compositeKey.Keys[i]; |
|
|
|
|
|
|
|
source = new Uri(key.BaseUri, source); |
|
|
|
var familyName = fontFamily.FamilyNames[i]; |
|
|
|
|
|
|
|
if (TryGetGlyphTypefaceByKeyAndName(typeface, key, familyName, out glyphTypeface) && |
|
|
|
glyphTypeface.FamilyName.Contains(familyName)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!_fontCollections.TryGetValue(source, out var fontCollection) && (source.IsAbsoluteResm() || source.IsAvares())) |
|
|
|
else |
|
|
|
{ |
|
|
|
var embeddedFonts = new EmbeddedFontCollection(source, source); |
|
|
|
|
|
|
|
embeddedFonts.Initialize(PlatformImpl); |
|
|
|
|
|
|
|
if (embeddedFonts.Count > 0 && _fontCollections.TryAdd(source, embeddedFonts)) |
|
|
|
if (TryGetGlyphTypefaceByKeyAndName(typeface, fontFamily.Key, fontFamily.FamilyNames.PrimaryFamilyName, out glyphTypeface)) |
|
|
|
{ |
|
|
|
fontCollection = embeddedFonts; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (fontCollection != null && fontCollection.TryGetGlyphTypeface(fontFamily.FamilyNames.PrimaryFamilyName, |
|
|
|
typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface)) |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (SystemFonts.TryGetGlyphTypeface(fontFamily.FamilyNames.PrimaryFamilyName, typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!fontFamily.FamilyNames.HasFallbacks) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (typeface.FontFamily == DefaultFontFamily) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
for (var i = 0; i < fontFamily.FamilyNames.Count; i++) |
|
|
|
//Nothing was found so use the default
|
|
|
|
return TryGetGlyphTypeface(new Typeface(FontFamily.DefaultFontFamilyName, typeface.Style, typeface.Weight, typeface.Stretch), out glyphTypeface); |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetGlyphTypefaceByKeyAndName(Typeface typeface, FontFamilyKey key, string familyName, [NotNullWhen(true)] out IGlyphTypeface? glyphTypeface) |
|
|
|
{ |
|
|
|
var source = key.Source; |
|
|
|
|
|
|
|
if (source.Scheme == SystemFontScheme) |
|
|
|
{ |
|
|
|
var familyName = fontFamily.FamilyNames[i]; |
|
|
|
return SystemFonts.TryGetGlyphTypeface(familyName, typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface); |
|
|
|
} |
|
|
|
|
|
|
|
if (SystemFonts.TryGetGlyphTypeface(familyName, typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface)) |
|
|
|
if (!source.IsAbsoluteUri) |
|
|
|
{ |
|
|
|
if (key.BaseUri == null) |
|
|
|
{ |
|
|
|
if (!fontFamily.FamilyNames.HasFallbacks || glyphTypeface.FamilyName != DefaultFontFamily.Name) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
throw new NotSupportedException($"{nameof(key.BaseUri)} can't be null."); |
|
|
|
} |
|
|
|
|
|
|
|
source = new Uri(key.BaseUri, source); |
|
|
|
} |
|
|
|
|
|
|
|
if(typeface.FontFamily == DefaultFontFamily) |
|
|
|
if (TryGetFontCollection(source, out var fontCollection) && |
|
|
|
fontCollection.TryGetGlyphTypeface(familyName, typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface)) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
if (glyphTypeface.FamilyName.Contains(familyName)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//Nothing was found so use the default
|
|
|
|
return TryGetGlyphTypeface(new Typeface(FontFamily.DefaultFontFamilyName, typeface.Style, typeface.Weight, typeface.Stretch), out glyphTypeface); |
|
|
|
glyphTypeface = null; |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -230,18 +249,17 @@ namespace Avalonia.Media |
|
|
|
} |
|
|
|
|
|
|
|
//Try to match against fallbacks first
|
|
|
|
if (fontFamily != null && fontFamily.FamilyNames.HasFallbacks) |
|
|
|
if (fontFamily != null && fontFamily.Key is CompositeFontFamilyKey compositeKey) |
|
|
|
{ |
|
|
|
for (int i = 1; i < fontFamily.FamilyNames.Count; i++) |
|
|
|
for (int i = 0; i < compositeKey.Keys.Count; i++) |
|
|
|
{ |
|
|
|
var key = compositeKey.Keys[i]; |
|
|
|
var familyName = fontFamily.FamilyNames[i]; |
|
|
|
|
|
|
|
foreach (var fontCollection in _fontCollections.Values) |
|
|
|
if (TryGetFontCollection(key.Source, out var fontCollection) && |
|
|
|
fontCollection.TryMatchCharacter(codepoint, fontStyle, fontWeight, fontStretch, familyName, culture, out typeface)) |
|
|
|
{ |
|
|
|
if (fontCollection.TryMatchCharacter(codepoint, fontStyle, fontWeight, fontStretch, familyName, culture, out typeface)) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
}; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -249,5 +267,27 @@ namespace Avalonia.Media |
|
|
|
//Try to find a match with the system font manager
|
|
|
|
return PlatformImpl.TryMatchCharacter(codepoint, fontStyle, fontWeight, fontStretch, culture, out typeface); |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetFontCollection(Uri source, [NotNullWhen(true)] out IFontCollection? fontCollection) |
|
|
|
{ |
|
|
|
if(source.Scheme == SystemFontScheme) |
|
|
|
{ |
|
|
|
source = SystemFontsKey; |
|
|
|
} |
|
|
|
|
|
|
|
if (!_fontCollections.TryGetValue(source, out fontCollection) && (source.IsAbsoluteResm() || source.IsAvares())) |
|
|
|
{ |
|
|
|
var embeddedFonts = new EmbeddedFontCollection(source, source); |
|
|
|
|
|
|
|
embeddedFonts.Initialize(PlatformImpl); |
|
|
|
|
|
|
|
if (embeddedFonts.Count > 0 && _fontCollections.TryAdd(source, embeddedFonts)) |
|
|
|
{ |
|
|
|
fontCollection = embeddedFonts; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return fontCollection != null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|