|
|
@ -1,6 +1,6 @@ |
|
|
using System; |
|
|
using System.Collections.Concurrent; |
|
|
using System.Collections.Generic; |
|
|
using System.Collections.Generic; |
|
|
using System.Text; |
|
|
using System.Linq; |
|
|
using Avalonia.Media; |
|
|
using Avalonia.Media; |
|
|
using Avalonia.Media.Fonts; |
|
|
using Avalonia.Media.Fonts; |
|
|
using Avalonia.Platform; |
|
|
using Avalonia.Platform; |
|
|
@ -40,13 +40,13 @@ namespace Avalonia.Skia |
|
|
public bool Equals(FontKey other) |
|
|
public bool Equals(FontKey other) |
|
|
{ |
|
|
{ |
|
|
return Slant == other.Slant && |
|
|
return Slant == other.Slant && |
|
|
Weight == other.Weight; |
|
|
Weight == other.Weight; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Equals and GetHashCode ommitted
|
|
|
// Equals and GetHashCode ommitted
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
unsafe static SKTypeface GetTypeface(FontFamily fontFamily, FontKey key) |
|
|
static SKTypeface GetTypeface(FontFamily fontFamily, FontKey key) |
|
|
{ |
|
|
{ |
|
|
var familyKey = fontFamily.Name; |
|
|
var familyKey = fontFamily.Name; |
|
|
|
|
|
|
|
|
@ -57,53 +57,95 @@ namespace Avalonia.Skia |
|
|
|
|
|
|
|
|
if (!entry.TryGetValue(key, out var typeface)) |
|
|
if (!entry.TryGetValue(key, out var typeface)) |
|
|
{ |
|
|
{ |
|
|
if (fontFamily.Key != null) |
|
|
typeface = SKTypeface.FromFamilyName(familyKey, key.Weight, SKFontStyleWidth.Normal, key.Slant); |
|
|
|
|
|
|
|
|
|
|
|
if (typeface == null) |
|
|
{ |
|
|
{ |
|
|
var cachedFontFamily = FontFamilyCache.GetOrAddFontFamily(fontFamily.Key); |
|
|
typeface = SKTypeface.FromFamilyName(null); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
|
|
entry[key] = typeface; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
foreach (var fontResource in cachedFontFamily.FontResources) |
|
|
return typeface; |
|
|
{ |
|
|
} |
|
|
var stream = assetLoader.Open(fontResource.Source); |
|
|
|
|
|
|
|
|
|
|
|
typeface = SKTypeface.FromStream(stream); |
|
|
public static SKTypeface GetTypeface(FontFamily fontFamily, FontStyle style, FontWeight weight) |
|
|
|
|
|
{ |
|
|
|
|
|
SKFontStyleSlant skStyle = SKFontStyleSlant.Upright; |
|
|
|
|
|
|
|
|
if (typeface.FamilyName != familyKey) continue; |
|
|
switch (style) |
|
|
|
|
|
{ |
|
|
|
|
|
case FontStyle.Italic: |
|
|
|
|
|
skStyle = SKFontStyleSlant.Italic; |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
var fontKey = new FontKey((SKFontStyleWeight)typeface.FontWeight, typeface.FontSlant); |
|
|
case FontStyle.Oblique: |
|
|
|
|
|
skStyle = SKFontStyleSlant.Oblique; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
entry[fontKey] = typeface; |
|
|
return GetTypeface(fontFamily, new FontKey((SKFontStyleWeight)weight, skStyle)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
entry.TryGetValue(key, out typeface); |
|
|
} |
|
|
|
|
|
|
|
|
if (typeface == null) |
|
|
internal class SKTypefaceCollection |
|
|
{ |
|
|
{ |
|
|
typeface = SKTypeface.FromFamilyName(null); |
|
|
private static readonly SKTypeface s_defaultTypeface = SKTypeface.FromFamilyName(null); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return typeface; |
|
|
struct FontKey |
|
|
} |
|
|
{ |
|
|
|
|
|
public readonly string Name; |
|
|
|
|
|
public readonly SKFontStyleSlant Slant; |
|
|
|
|
|
public readonly SKFontStyleWeight Weight; |
|
|
|
|
|
|
|
|
typeface = SKTypeface.FromFamilyName(familyKey, key.Weight, SKFontStyleWidth.Normal, key.Slant); |
|
|
public FontKey(string name, SKFontStyleWeight weight, SKFontStyleSlant slant) |
|
|
|
|
|
{ |
|
|
|
|
|
Name = name; |
|
|
|
|
|
Slant = slant; |
|
|
|
|
|
Weight = weight; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (typeface == null) |
|
|
public override int GetHashCode() |
|
|
{ |
|
|
{ |
|
|
typeface = SKTypeface.FromFamilyName(null); |
|
|
int hash = 17; |
|
|
} |
|
|
hash = hash * 31 + Name.GetHashCode(); |
|
|
|
|
|
hash = hash * 31 + (int)Slant; |
|
|
|
|
|
hash = hash * 31 + (int)Weight; |
|
|
|
|
|
|
|
|
entry[key] = typeface; |
|
|
return hash; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return typeface; |
|
|
public override bool Equals(object other) |
|
|
|
|
|
{ |
|
|
|
|
|
return other is FontKey ? Equals((FontKey)other) : false; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public bool Equals(FontKey other) |
|
|
|
|
|
{ |
|
|
|
|
|
return Name == other.Name && Slant == other.Slant && |
|
|
|
|
|
Weight == other.Weight; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Equals and GetHashCode ommitted
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public static SKTypeface GetTypeface(FontFamily fontFamily, FontStyle style, FontWeight weight) |
|
|
private readonly ConcurrentDictionary<FontKey, SKTypeface> _cachedTypefaces = |
|
|
|
|
|
new ConcurrentDictionary<FontKey, SKTypeface>(); |
|
|
|
|
|
|
|
|
|
|
|
public void AddTypeFace(FontFamily fontFamily, SKTypeface typeface) |
|
|
|
|
|
{ |
|
|
|
|
|
var key = new FontKey(fontFamily.Name, (SKFontStyleWeight)typeface.FontWeight, typeface.FontSlant); |
|
|
|
|
|
|
|
|
|
|
|
_cachedTypefaces.TryAdd(key, typeface); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public SKTypeface GetTypeFace(Typeface typeface) |
|
|
{ |
|
|
{ |
|
|
SKFontStyleSlant skStyle = SKFontStyleSlant.Upright; |
|
|
SKFontStyleSlant skStyle = SKFontStyleSlant.Upright; |
|
|
|
|
|
|
|
|
switch (style) |
|
|
switch (typeface.Style) |
|
|
{ |
|
|
{ |
|
|
case FontStyle.Italic: |
|
|
case FontStyle.Italic: |
|
|
skStyle = SKFontStyleSlant.Italic; |
|
|
skStyle = SKFontStyleSlant.Italic; |
|
|
@ -114,8 +156,42 @@ namespace Avalonia.Skia |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return GetTypeface(fontFamily, new FontKey((SKFontStyleWeight)weight, skStyle)); |
|
|
var key = new FontKey(typeface.FontFamily.Name, (SKFontStyleWeight)typeface.Weight, skStyle); |
|
|
|
|
|
|
|
|
|
|
|
return _cachedTypefaces.TryGetValue(key, out var skTypeface) ? skTypeface : s_defaultTypeface; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
internal static class SKTypefaceCollectionCache |
|
|
|
|
|
{ |
|
|
|
|
|
private static readonly ConcurrentDictionary<FontFamilyKey, SKTypefaceCollection> s_cachedCollections = |
|
|
|
|
|
new ConcurrentDictionary<FontFamilyKey, SKTypefaceCollection>(); |
|
|
|
|
|
|
|
|
|
|
|
public static SKTypefaceCollection GetOrAddTypefaceCollection(FontFamily fontFamily) |
|
|
|
|
|
{ |
|
|
|
|
|
return s_cachedCollections.GetOrAdd(fontFamily.Key, x => CreateCustomFontCollection(fontFamily)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static SKTypefaceCollection CreateCustomFontCollection(FontFamily fontFamily) |
|
|
|
|
|
{ |
|
|
|
|
|
var cachedFontFamily = FontFamilyCache.GetOrAddFontFamily(fontFamily.Key); |
|
|
|
|
|
|
|
|
|
|
|
var typeFaceCollection = new SKTypefaceCollection(); |
|
|
|
|
|
|
|
|
|
|
|
if (!cachedFontFamily.FontResources.Any()) return typeFaceCollection; |
|
|
|
|
|
|
|
|
|
|
|
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>(); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var fontResource in cachedFontFamily.FontResources) |
|
|
|
|
|
{ |
|
|
|
|
|
var stream = assetLoader.Open(fontResource.Source); |
|
|
|
|
|
|
|
|
|
|
|
var typeface = SKTypeface.FromStream(stream); |
|
|
|
|
|
|
|
|
|
|
|
typeFaceCollection.AddTypeFace(fontFamily, typeface); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return typeFaceCollection; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |