39 changed files with 641 additions and 301 deletions
@ -0,0 +1,4 @@ |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests")] |
|||
[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests")] |
|||
@ -1,47 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System.Collections.Concurrent; |
|||
using Avalonia.Media; |
|||
using SkiaSharp; |
|||
|
|||
namespace Avalonia.Skia |
|||
{ |
|||
/// <summary>
|
|||
/// Cache for Skia typefaces.
|
|||
/// </summary>
|
|||
internal static class TypefaceCache |
|||
{ |
|||
private static readonly ConcurrentDictionary<string, ConcurrentDictionary<FontKey, TypefaceCollectionEntry>> s_cache = |
|||
new ConcurrentDictionary<string, ConcurrentDictionary<FontKey, TypefaceCollectionEntry>>(); |
|||
|
|||
public static TypefaceCollectionEntry Get(FontFamily fontFamily, FontWeight fontWeight, FontStyle fontStyle) |
|||
{ |
|||
if (fontFamily.Key != null) |
|||
{ |
|||
return SKTypefaceCollectionCache.GetOrAddTypefaceCollection(fontFamily) |
|||
.Get(fontFamily.Name, fontWeight, fontStyle); |
|||
} |
|||
|
|||
var typefaceCollection = s_cache.GetOrAdd(fontFamily.Name, new ConcurrentDictionary<FontKey, TypefaceCollectionEntry>()); |
|||
|
|||
var key = new FontKey(fontWeight, fontStyle); |
|||
|
|||
if (typefaceCollection.TryGetValue(key, out var entry)) |
|||
{ |
|||
return entry; |
|||
} |
|||
|
|||
var skTypeface = SKTypeface.FromFamilyName(fontFamily.Name, (SKFontStyleWeight)fontWeight, |
|||
SKFontStyleWidth.Normal, (SKFontStyleSlant)fontStyle) ?? SKTypeface.Default; |
|||
|
|||
var typeface = new Typeface(fontFamily.Name, fontWeight, fontStyle); |
|||
|
|||
entry = new TypefaceCollectionEntry(typeface, skTypeface); |
|||
|
|||
typefaceCollection[key] = entry; |
|||
|
|||
return entry; |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using Avalonia.Media; |
|||
using SkiaSharp; |
|||
|
|||
namespace Avalonia.Skia |
|||
{ |
|||
internal class TypefaceCollectionEntry |
|||
{ |
|||
public TypefaceCollectionEntry(Typeface typeface, SKTypeface skTypeface) |
|||
{ |
|||
Typeface = typeface; |
|||
SKTypeface = skTypeface; |
|||
} |
|||
public Typeface Typeface { get; } |
|||
public SKTypeface SKTypeface { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
using System; |
|||
using System.Reflection; |
|||
using Avalonia.Direct2D1.Media; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using Avalonia.UnitTests; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Direct2D1.UnitTests.Media |
|||
{ |
|||
public class FontManagerImplTests |
|||
{ |
|||
private static string s_fontUri = "resm:Avalonia.UnitTests.Assets?assembly=Avalonia.UnitTests#Noto Mono"; |
|||
|
|||
[Fact] |
|||
public void Should_Create_Typeface_From_Fallback() |
|||
{ |
|||
using (AvaloniaLocator.EnterScope()) |
|||
{ |
|||
Direct2D1Platform.Initialize(); |
|||
|
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var defaultName = fontManager.GetDefaultFontFamilyName(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily("A, B, Arial"))); |
|||
|
|||
var font = glyphTypeface.DWFont; |
|||
|
|||
Assert.Equal("Arial", font.FontFamily.FamilyNames.GetString(0)); |
|||
|
|||
Assert.Equal(SharpDX.DirectWrite.FontWeight.Normal, font.Weight); |
|||
|
|||
Assert.Equal(SharpDX.DirectWrite.FontStyle.Normal, font.Style); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Create_Typeface_For_Unknown_Font() |
|||
{ |
|||
using (AvaloniaLocator.EnterScope()) |
|||
{ |
|||
Direct2D1Platform.Initialize(); |
|||
|
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily("Unknown"))); |
|||
|
|||
var font = glyphTypeface.DWFont; |
|||
|
|||
var defaultName = fontManager.GetDefaultFontFamilyName(); |
|||
|
|||
Assert.Equal(defaultName, font.FontFamily.FamilyNames.GetString(0)); |
|||
|
|||
Assert.Equal(SharpDX.DirectWrite.FontWeight.Normal, font.Weight); |
|||
|
|||
Assert.Equal(SharpDX.DirectWrite.FontStyle.Normal, font.Style); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Load_Typeface_From_Resource() |
|||
{ |
|||
using (AvaloniaLocator.EnterScope()) |
|||
{ |
|||
Direct2D1Platform.Initialize(); |
|||
|
|||
var assetLoaderType = typeof(TestRoot).Assembly.GetType("Avalonia.Shared.PlatformSupport.AssetLoader"); |
|||
|
|||
var assetLoader = (IAssetLoader)Activator.CreateInstance(assetLoaderType, (Assembly)null); |
|||
|
|||
AvaloniaLocator.CurrentMutable.Bind<IAssetLoader>().ToConstant(assetLoader); |
|||
|
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily(s_fontUri))); |
|||
|
|||
var font = glyphTypeface.DWFont; |
|||
|
|||
Assert.Equal("Noto Mono", font.FontFamily.FamilyNames.GetString(0)); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Load_Nearest_Matching_Font() |
|||
{ |
|||
using (AvaloniaLocator.EnterScope()) |
|||
{ |
|||
Direct2D1Platform.Initialize(); |
|||
|
|||
var assetLoaderType = typeof(TestRoot).Assembly.GetType("Avalonia.Shared.PlatformSupport.AssetLoader"); |
|||
|
|||
var assetLoader = (IAssetLoader)Activator.CreateInstance(assetLoaderType, (Assembly)null); |
|||
|
|||
AvaloniaLocator.CurrentMutable.Bind<IAssetLoader>().ToConstant(assetLoader); |
|||
|
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily(s_fontUri), FontWeight.Black, FontStyle.Italic)); |
|||
|
|||
var font = glyphTypeface.DWFont; |
|||
|
|||
Assert.Equal("Noto Mono", font.FontFamily.FamilyNames.GetString(0)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,93 @@ |
|||
using System; |
|||
using System.Reflection; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using Avalonia.UnitTests; |
|||
using SkiaSharp; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Skia.UnitTests |
|||
{ |
|||
public class FontManagerImplTests |
|||
{ |
|||
private static string s_fontUri = "resm:Avalonia.UnitTests.Assets?assembly=Avalonia.UnitTests#Noto Mono"; |
|||
|
|||
[Fact] |
|||
public void Should_Create_Typeface_From_Fallback() |
|||
{ |
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily("A, B, " + fontManager.GetDefaultFontFamilyName()))); |
|||
|
|||
var skTypeface = glyphTypeface.Typeface; |
|||
|
|||
Assert.Equal(SKTypeface.Default.FamilyName, skTypeface.FamilyName); |
|||
|
|||
Assert.Equal(SKTypeface.Default.FontWeight, skTypeface.FontWeight); |
|||
|
|||
Assert.Equal(SKTypeface.Default.FontSlant, skTypeface.FontSlant); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Create_Typeface_For_Unknown_Font() |
|||
{ |
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily("Unknown"))); |
|||
|
|||
var skTypeface = glyphTypeface.Typeface; |
|||
|
|||
Assert.Equal(SKTypeface.Default.FamilyName, skTypeface.FamilyName); |
|||
|
|||
Assert.Equal(SKTypeface.Default.FontWeight, skTypeface.FontWeight); |
|||
|
|||
Assert.Equal(SKTypeface.Default.FontSlant, skTypeface.FontSlant); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Load_Typeface_From_Resource() |
|||
{ |
|||
using (AvaloniaLocator.EnterScope()) |
|||
{ |
|||
var assetLoaderType = typeof(TestRoot).Assembly.GetType("Avalonia.Shared.PlatformSupport.AssetLoader"); |
|||
|
|||
var assetLoader = (IAssetLoader)Activator.CreateInstance(assetLoaderType, (Assembly)null); |
|||
|
|||
AvaloniaLocator.CurrentMutable.Bind<IAssetLoader>().ToConstant(assetLoader); |
|||
|
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily(s_fontUri))); |
|||
|
|||
var skTypeface = glyphTypeface.Typeface; |
|||
|
|||
Assert.Equal("Noto Mono", skTypeface.FamilyName); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Load_Nearest_Matching_Font() |
|||
{ |
|||
using (AvaloniaLocator.EnterScope()) |
|||
{ |
|||
var assetLoaderType = typeof(TestRoot).Assembly.GetType("Avalonia.Shared.PlatformSupport.AssetLoader"); |
|||
|
|||
var assetLoader = (IAssetLoader)Activator.CreateInstance(assetLoaderType, (Assembly)null); |
|||
|
|||
AvaloniaLocator.CurrentMutable.Bind<IAssetLoader>().ToConstant(assetLoader); |
|||
|
|||
var fontManager = new FontManagerImpl(); |
|||
|
|||
var glyphTypeface = (GlyphTypefaceImpl)fontManager.CreateGlyphTypeface( |
|||
new Typeface(new FontFamily(s_fontUri), FontWeight.Black, FontStyle.Italic)); |
|||
|
|||
var skTypeface = glyphTypeface.Typeface; |
|||
|
|||
Assert.Equal("Noto Mono", skTypeface.FamilyName); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Binary file not shown.
@ -0,0 +1,35 @@ |
|||
using System.Collections.Generic; |
|||
using System.Globalization; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Fonts; |
|||
using Avalonia.Platform; |
|||
using Moq; |
|||
|
|||
namespace Avalonia.UnitTests |
|||
{ |
|||
public class MockFontManagerImpl : IFontManagerImpl |
|||
{ |
|||
public string GetDefaultFontFamilyName() |
|||
{ |
|||
return "Default"; |
|||
} |
|||
|
|||
public IEnumerable<string> GetInstalledFontFamilyNames(bool checkForUpdates = false) |
|||
{ |
|||
return new[] { "Default" }; |
|||
} |
|||
|
|||
public bool TryMatchCharacter(int codepoint, FontWeight fontWeight, FontStyle fontStyle, FontFamily fontFamily, |
|||
CultureInfo culture, out FontKey fontKey) |
|||
{ |
|||
fontKey = default; |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public IGlyphTypefaceImpl CreateGlyphTypeface(Typeface typeface) |
|||
{ |
|||
return Mock.Of<IGlyphTypefaceImpl>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using Avalonia.UnitTests; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Visuals.UnitTests.Media |
|||
{ |
|||
public class FontManagerTests |
|||
{ |
|||
[Fact] |
|||
public void Should_Create_Single_Instance_Typeface() |
|||
{ |
|||
using (AvaloniaLocator.EnterScope()) |
|||
{ |
|||
AvaloniaLocator.CurrentMutable.Bind<IPlatformRenderInterface>().ToConstant(new MockPlatformRenderInterface()); |
|||
|
|||
var fontFamily = new FontFamily("MyFont"); |
|||
|
|||
var typeface = FontManager.Current.GetOrAddTypeface(fontFamily); |
|||
|
|||
Assert.Same(typeface, FontManager.Current.GetOrAddTypeface(fontFamily)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue