csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
5.9 KiB
152 lines
5.9 KiB
#nullable enable
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using Avalonia.Media;
|
|
using Avalonia.Media.Fonts;
|
|
using Avalonia.Platform;
|
|
using Avalonia.UnitTests;
|
|
using Xunit;
|
|
|
|
namespace Avalonia.Skia.UnitTests.Media
|
|
{
|
|
public class FontCollectionTests
|
|
{
|
|
private const string NotoMono =
|
|
"resm:Avalonia.Skia.UnitTests.Assets?assembly=Avalonia.Skia.UnitTests";
|
|
|
|
[Win32Fact("Relies on some installed font family")]
|
|
public void Should_Cache_Nearest_Match()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new FontManagerImpl())))
|
|
{
|
|
var fontCollection = new TestSystemFontCollection(FontManager.Current.PlatformImpl);
|
|
|
|
Assert.True(fontCollection.TryGetGlyphTypeface("Arial", FontStyle.Normal, FontWeight.ExtraBlack, FontStretch.Normal, out var glyphTypeface));
|
|
|
|
Assert.True(fontCollection.GlyphTypefaceCache.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(IFontManagerImpl platformImpl) : base(platformImpl)
|
|
{
|
|
}
|
|
|
|
public IDictionary<string, ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>> GlyphTypefaceCache => _glyphTypefaceCache;
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Use_Fallback()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface.With(fontManagerImpl: new CustomFontManagerImpl())))
|
|
{
|
|
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 });
|
|
|
|
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.With(fontManagerImpl: new CustomFontManagerImpl())))
|
|
{
|
|
var key = new Uri(NotoMono, UriKind.Absolute);
|
|
|
|
var ignorable = new FontFamily(new Uri(NotoMono, UriKind.Absolute), "Noto Mono");
|
|
|
|
var fontCollection = new CustomizableFontCollection(key, key, null, new[] { ignorable });
|
|
|
|
var typeface = new Typeface(ignorable);
|
|
|
|
var glyphTypeface = typeface.GlyphTypeface;
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|