Browse Source

Merge pull request #10620 from Gillibald/feature/invariantFamilyNames

FontManager fixes
pull/10630/head
Max Katz 4 years ago
committed by GitHub
parent
commit
8423e16658
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/Avalonia.Base/Media/FontManager.cs
  2. 15
      src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs
  3. 2
      src/Avalonia.Base/Media/Fonts/SystemFontCollection.cs
  4. 92
      tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs
  5. 34
      tests/Avalonia.Skia.UnitTests/Media/FontManagerTests.cs
  6. 8
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

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

@ -119,7 +119,9 @@ namespace Avalonia.Media
}
}
if (fontCollection != null && fontCollection.TryGetGlyphTypeface(fontFamily.FamilyNames.PrimaryFamilyName,
var familyName = fontFamily.FamilyNames.PrimaryFamilyName.ToUpperInvariant();
if (fontCollection != null && fontCollection.TryGetGlyphTypeface(familyName,
typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface))
{
return true;
@ -133,13 +135,13 @@ namespace Avalonia.Media
foreach (var familyName in fontFamily.FamilyNames)
{
if (SystemFonts.TryGetGlyphTypeface(familyName, typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface))
if (SystemFonts.TryGetGlyphTypeface(familyName.ToUpperInvariant(), typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface))
{
return true;
}
}
return SystemFonts.TryGetGlyphTypeface(DefaultFontFamilyName, typeface.Style, typeface.Weight, typeface.Stretch, out glyphTypeface);
return TryGetGlyphTypeface(new Typeface(DefaultFontFamilyName, typeface.Style, typeface.Weight, typeface.Stretch), out glyphTypeface);
}
/// <summary>

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

@ -3,7 +3,6 @@ using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Avalonia.Platform;
namespace Avalonia.Media.Fonts
@ -43,11 +42,13 @@ namespace Avalonia.Media.Fonts
if (fontManager.TryCreateGlyphTypeface(stream, out var glyphTypeface))
{
if (!_glyphTypefaceCache.TryGetValue(glyphTypeface.FamilyName, out var glyphTypefaces))
var familyName = glyphTypeface.FamilyName.ToUpperInvariant();
if (!_glyphTypefaceCache.TryGetValue(familyName, out var glyphTypefaces))
{
glyphTypefaces = new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface>();
if (_glyphTypefaceCache.TryAdd(glyphTypeface.FamilyName, glyphTypefaces))
if (_glyphTypefaceCache.TryAdd(familyName, glyphTypefaces))
{
_fontFamilies.Add(new FontFamily(_key, glyphTypeface.FamilyName));
}
@ -86,6 +87,8 @@ namespace Avalonia.Media.Fonts
public bool TryGetGlyphTypeface(string familyName, FontStyle style, FontWeight weight,
FontStretch stretch, [NotNullWhen(true)] out IGlyphTypeface? glyphTypeface)
{
familyName = familyName.ToUpperInvariant();
var key = new FontCollectionKey(style, weight, stretch);
if (_glyphTypefaceCache.TryGetValue(familyName, out var glyphTypefaces))
@ -101,9 +104,11 @@ namespace Avalonia.Media.Fonts
{
var fontFamily = _fontFamilies[i];
if (fontFamily.Name.ToLower(CultureInfo.InvariantCulture).StartsWith(familyName.ToLower(CultureInfo.InvariantCulture)))
if (fontFamily.Name.ToUpperInvariant().StartsWith(familyName.ToUpperInvariant()))
{
if (_glyphTypefaceCache.TryGetValue(fontFamily.Name, out glyphTypefaces) &&
familyName = fontFamily.Name.ToUpperInvariant();
if (_glyphTypefaceCache.TryGetValue(familyName, out glyphTypefaces) &&
TryGetNearestMatch(glyphTypefaces, key, out glyphTypeface))
{
return true;

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

@ -42,6 +42,8 @@ namespace Avalonia.Media.Fonts
familyName = _fontManager.DefaultFontFamilyName;
}
familyName = familyName.ToUpperInvariant();
var key = new FontCollectionKey(style, weight, stretch);
if (_glyphTypefaceCache.TryGetValue(familyName, out var glyphTypefaces))

92
tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs

@ -68,66 +68,6 @@ namespace Avalonia.Skia.UnitTests.Media
return true;
}
public IGlyphTypeface CreateGlyphTypeface(Typeface typeface)
{
SKTypeface skTypeface;
Uri source = null;
switch (typeface.FontFamily.Name)
{
case "Twitter Color Emoji":
{
source = _emojiTypeface.FontFamily.Key.Source;
break;
}
case "Noto Sans":
{
source = _italicTypeface.FontFamily.Key.Source;
break;
}
case "Noto Sans Arabic":
{
source = _arabicTypeface.FontFamily.Key.Source;
break;
}
case "Noto Sans Hebrew":
{
source = _hebrewTypeface.FontFamily.Key.Source;
break;
}
case FontFamily.DefaultFontFamilyName:
case "Noto Mono":
{
source = _defaultTypeface.FontFamily.Key.Source;
break;
}
default:
{
break;
}
}
if (source is null)
{
skTypeface = SKTypeface.FromFamilyName(typeface.FontFamily.Name,
(SKFontStyleWeight)typeface.Weight, SKFontStyleWidth.Normal, (SKFontStyleSlant)typeface.Style);
}
else
{
var assetLoader = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
var assetUri = FontFamilyLoader.LoadFontAssets(source).First();
var stream = assetLoader.Open(assetUri);
skTypeface = SKTypeface.FromStream(stream);
}
return new GlyphTypefaceImpl(skTypeface, FontSimulations.None);
}
public bool TryCreateGlyphTypeface(string familyName, FontStyle style, FontWeight weight,
FontStretch stretch, [NotNullWhen(true)] out IGlyphTypeface glyphTypeface)
{
@ -137,54 +77,40 @@ namespace Avalonia.Skia.UnitTests.Media
switch (familyName)
{
case "Twitter Color Emoji":
case "TWITTER COLOR EMOJI":
{
source = _emojiTypeface.FontFamily.Key.Source;
break;
}
case "Noto Sans":
case "NOTO SANS":
{
source = _italicTypeface.FontFamily.Key.Source;
break;
}
case "Noto Sans Arabic":
case "NOTO SANS ARABIC":
{
source = _arabicTypeface.FontFamily.Key.Source;
break;
}
case "Noto Sans Hebrew":
case "NOTO SANS HEBREW":
{
source = _hebrewTypeface.FontFamily.Key.Source;
break;
}
case FontFamily.DefaultFontFamilyName:
case "Noto Mono":
{
source = _defaultTypeface.FontFamily.Key.Source;
break;
}
default:
{
source = _defaultTypeface.FontFamily.Key.Source;
break;
}
}
if (source is null)
{
skTypeface = SKTypeface.FromFamilyName(familyName,
(SKFontStyleWeight)weight, SKFontStyleWidth.Normal, (SKFontStyleSlant)style);
}
else
{
var assetLoader = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
var assetLoader = AvaloniaLocator.Current.GetRequiredService<IAssetLoader>();
var assetUri = FontFamilyLoader.LoadFontAssets(source).First();
var assetUri = FontFamilyLoader.LoadFontAssets(source).First();
var stream = assetLoader.Open(assetUri);
var stream = assetLoader.Open(assetUri);
skTypeface = SKTypeface.FromStream(stream);
}
skTypeface = SKTypeface.FromStream(stream);
glyphTypeface = new GlyphTypefaceImpl(skTypeface, FontSimulations.None);

34
tests/Avalonia.Skia.UnitTests/Media/FontManagerImplTests.cs → tests/Avalonia.Skia.UnitTests/Media/FontManagerTests.cs

@ -1,5 +1,4 @@
using System;
using System.Linq;
using Avalonia.Media;
using Avalonia.UnitTests;
using SkiaSharp;
@ -7,7 +6,7 @@ using Xunit;
namespace Avalonia.Skia.UnitTests.Media
{
public class FontManagerImplTests
public class FontManagerTests
{
private static string s_fontUri = "resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests#Noto Mono";
@ -87,5 +86,36 @@ namespace Avalonia.Skia.UnitTests.Media
Assert.False(result);
}
}
[Fact]
public void Should_Load_Embedded_Font_With_Wrong_CharacterCasing()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
var result = FontManager.Current.TryGetGlyphTypeface(new Typeface("resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests#noto mOnO"), out var glyphTypeface);
Assert.True(result);
Assert.Equal("Noto Mono", glyphTypeface.FamilyName);
}
}
[Fact]
public void Should_Load_Embedded_DefaultFontFamily()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
{
using (AvaloniaLocator.EnterScope())
{
AvaloniaLocator.CurrentMutable.BindToSelf(new FontManagerOptions { DefaultFamilyName = s_fontUri });
var result = FontManager.Current.TryGetGlyphTypeface(new Typeface(FontFamily.DefaultFontFamilyName), out var glyphTypeface);
Assert.True(result);
Assert.Equal("Noto Mono", glyphTypeface.FamilyName);
}
}
}
}
}

8
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs

@ -416,14 +416,14 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
}
[InlineData("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor",
new[] { "Lorem ipsum ", "dolor sit amet, ", "consectetur ", "adipisicing elit, ", "sed do eiusmod " })]
new[] { "Lorem ipsum ", "dolor sit ", "amet, ", "consectetur ", "adipisicing ", "elit, sed do ", "eiusmod tempor" })]
[Theory]
public void Should_Produce_Wrapped_And_Trimmed_Lines(string text, string[] expectedLines)
{
using (Start())
{
var typeface = new Typeface("Verdana");
var typeface = Typeface.Default;
var defaultProperties = new GenericTextRunProperties(typeface, 32, foregroundBrush: Brushes.Black);
@ -432,9 +432,9 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
new ValueSpan<TextRunProperties>(0, 5,
new GenericTextRunProperties(typeface, 48)),
new ValueSpan<TextRunProperties>(6, 11,
new GenericTextRunProperties(new Typeface("Verdana", weight: FontWeight.Bold), 32)),
new GenericTextRunProperties(new Typeface(FontFamily.Default, weight: FontWeight.Bold), 32)),
new ValueSpan<TextRunProperties>(28, 28,
new GenericTextRunProperties(new Typeface("Verdana", FontStyle.Italic),32))
new GenericTextRunProperties(new Typeface(FontFamily.Default, FontStyle.Italic),32))
};
var textSource = new FormattedTextSource(text, defaultProperties, styleSpans);

Loading…
Cancel
Save