|
|
|
@ -1,72 +1,115 @@ |
|
|
|
// 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 System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
|
|
|
|
using Avalonia.Media; |
|
|
|
|
|
|
|
using SkiaSharp; |
|
|
|
|
|
|
|
namespace Avalonia.Skia |
|
|
|
{ |
|
|
|
internal class SKTypefaceCollection |
|
|
|
{ |
|
|
|
private readonly ConcurrentDictionary<FontKey, SKTypeface> _cachedTypefaces = |
|
|
|
new ConcurrentDictionary<FontKey, SKTypeface>(); |
|
|
|
private readonly ConcurrentDictionary<string, ConcurrentDictionary<FontKey, SKTypeface>> _fontFamilies = |
|
|
|
new ConcurrentDictionary<string, ConcurrentDictionary<FontKey, SKTypeface>>(); |
|
|
|
|
|
|
|
public void AddTypeFace(SKTypeface typeface) |
|
|
|
{ |
|
|
|
var key = new FontKey(typeface.FamilyName, (SKFontStyleWeight)typeface.FontWeight, typeface.FontSlant); |
|
|
|
var key = new FontKey((SKFontStyleWeight)typeface.FontWeight, typeface.FontSlant); |
|
|
|
|
|
|
|
_cachedTypefaces.TryAdd(key, typeface); |
|
|
|
if (!_fontFamilies.TryGetValue(typeface.FamilyName, out var fontFamily)) |
|
|
|
{ |
|
|
|
fontFamily = new ConcurrentDictionary<FontKey, SKTypeface>(); |
|
|
|
|
|
|
|
_fontFamilies.TryAdd(typeface.FamilyName, fontFamily); |
|
|
|
} |
|
|
|
|
|
|
|
fontFamily.TryAdd(key, typeface); |
|
|
|
} |
|
|
|
|
|
|
|
public SKTypeface GetTypeFace(Typeface typeface) |
|
|
|
{ |
|
|
|
SKFontStyleSlant skStyle = SKFontStyleSlant.Upright; |
|
|
|
var styleSlant = SKFontStyleSlant.Upright; |
|
|
|
|
|
|
|
switch (typeface.Style) |
|
|
|
{ |
|
|
|
case FontStyle.Italic: |
|
|
|
skStyle = SKFontStyleSlant.Italic; |
|
|
|
styleSlant = SKFontStyleSlant.Italic; |
|
|
|
break; |
|
|
|
|
|
|
|
case FontStyle.Oblique: |
|
|
|
skStyle = SKFontStyleSlant.Oblique; |
|
|
|
styleSlant = SKFontStyleSlant.Oblique; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
var key = new FontKey(typeface.FontFamily.Name, (SKFontStyleWeight)typeface.Weight, skStyle); |
|
|
|
if (!_fontFamilies.TryGetValue(typeface.FontFamily.Name, out var fontFamily)) |
|
|
|
{ |
|
|
|
return TypefaceCache.Default; |
|
|
|
} |
|
|
|
|
|
|
|
var weight = (SKFontStyleWeight)typeface.Weight; |
|
|
|
|
|
|
|
var key = new FontKey(weight, styleSlant); |
|
|
|
|
|
|
|
return fontFamily.GetOrAdd(key, GetFallback(fontFamily, key)); |
|
|
|
} |
|
|
|
|
|
|
|
private static SKTypeface GetFallback(IDictionary<FontKey, SKTypeface> fontFamily, FontKey key) |
|
|
|
{ |
|
|
|
var keys = fontFamily.Keys.Where( |
|
|
|
x => ((int)x.Weight <= (int)key.Weight || (int)x.Weight > (int)key.Weight) && x.Slant == key.Slant).ToArray(); |
|
|
|
|
|
|
|
if (!keys.Any()) |
|
|
|
{ |
|
|
|
keys = fontFamily.Keys.Where( |
|
|
|
x => x.Weight == key.Weight && (x.Slant >= key.Slant || x.Slant < key.Slant)).ToArray(); |
|
|
|
|
|
|
|
if (!keys.Any()) |
|
|
|
{ |
|
|
|
keys = fontFamily.Keys.Where( |
|
|
|
x => ((int)x.Weight <= (int)key.Weight || (int)x.Weight > (int)key.Weight) && |
|
|
|
(x.Slant >= key.Slant || x.Slant < key.Slant)).ToArray(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
key = keys.FirstOrDefault(); |
|
|
|
|
|
|
|
fontFamily.TryGetValue(key, out var typeface); |
|
|
|
|
|
|
|
return _cachedTypefaces.TryGetValue(key, out var skTypeface) ? skTypeface : TypefaceCache.Default; |
|
|
|
return typeface; |
|
|
|
} |
|
|
|
|
|
|
|
private struct FontKey |
|
|
|
{ |
|
|
|
public readonly string Name; |
|
|
|
public readonly SKFontStyleSlant Slant; |
|
|
|
public readonly SKFontStyleWeight Weight; |
|
|
|
|
|
|
|
public FontKey(string name, SKFontStyleWeight weight, SKFontStyleSlant slant) |
|
|
|
public FontKey(SKFontStyleWeight weight, SKFontStyleSlant slant) |
|
|
|
{ |
|
|
|
Name = name; |
|
|
|
Slant = slant; |
|
|
|
Weight = weight; |
|
|
|
} |
|
|
|
|
|
|
|
public override int GetHashCode() |
|
|
|
{ |
|
|
|
int hash = 17; |
|
|
|
hash = hash * 31 + Name.GetHashCode(); |
|
|
|
hash = hash * 31 + (int)Slant; |
|
|
|
hash = hash * 31 + (int)Weight; |
|
|
|
var hash = 17; |
|
|
|
hash = (hash * 31) + (int)Slant; |
|
|
|
hash = (hash * 31) + (int)Weight; |
|
|
|
|
|
|
|
return hash; |
|
|
|
} |
|
|
|
|
|
|
|
public override bool Equals(object other) |
|
|
|
{ |
|
|
|
return other is FontKey ? Equals((FontKey)other) : false; |
|
|
|
return other is FontKey key && this.Equals(key); |
|
|
|
} |
|
|
|
|
|
|
|
private bool Equals(FontKey other) |
|
|
|
{ |
|
|
|
return Name == other.Name && Slant == other.Slant && |
|
|
|
return Slant == other.Slant && |
|
|
|
Weight == other.Weight; |
|
|
|
} |
|
|
|
} |
|
|
|
|