Browse Source

Merge pull request #2162 from Gillibald/feature/SkiaTypefaceFallback

Skia: FontWeight and FontStyle fallback for embedded fonts
pull/2188/head
Jumar Macato 7 years ago
committed by GitHub
parent
commit
b4fae84e81
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 79
      src/Skia/Avalonia.Skia/SKTypefaceCollection.cs
  2. 3
      src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs

79
src/Skia/Avalonia.Skia/SKTypefaceCollection.cs

@ -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.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Media; using Avalonia.Media;
using SkiaSharp; using SkiaSharp;
namespace Avalonia.Skia namespace Avalonia.Skia
{ {
internal class SKTypefaceCollection internal class SKTypefaceCollection
{ {
private readonly ConcurrentDictionary<FontKey, SKTypeface> _cachedTypefaces = private readonly ConcurrentDictionary<string, ConcurrentDictionary<FontKey, SKTypeface>> _fontFamilies =
new ConcurrentDictionary<FontKey, SKTypeface>(); new ConcurrentDictionary<string, ConcurrentDictionary<FontKey, SKTypeface>>();
public void AddTypeFace(SKTypeface typeface) 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) public SKTypeface GetTypeFace(Typeface typeface)
{ {
SKFontStyleSlant skStyle = SKFontStyleSlant.Upright; var styleSlant = SKFontStyleSlant.Upright;
switch (typeface.Style) switch (typeface.Style)
{ {
case FontStyle.Italic: case FontStyle.Italic:
skStyle = SKFontStyleSlant.Italic; styleSlant = SKFontStyleSlant.Italic;
break; break;
case FontStyle.Oblique: case FontStyle.Oblique:
skStyle = SKFontStyleSlant.Oblique; styleSlant = SKFontStyleSlant.Oblique;
break; 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 private struct FontKey
{ {
public readonly string Name;
public readonly SKFontStyleSlant Slant; public readonly SKFontStyleSlant Slant;
public readonly SKFontStyleWeight Weight; public readonly SKFontStyleWeight Weight;
public FontKey(string name, SKFontStyleWeight weight, SKFontStyleSlant slant) public FontKey(SKFontStyleWeight weight, SKFontStyleSlant slant)
{ {
Name = name;
Slant = slant; Slant = slant;
Weight = weight; Weight = weight;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
int hash = 17; var hash = 17;
hash = hash * 31 + Name.GetHashCode(); hash = (hash * 31) + (int)Slant;
hash = hash * 31 + (int)Slant; hash = (hash * 31) + (int)Weight;
hash = hash * 31 + (int)Weight;
return hash; return hash;
} }
public override bool Equals(object other) 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) private bool Equals(FontKey other)
{ {
return Name == other.Name && Slant == other.Slant && return Slant == other.Slant &&
Weight == other.Weight; Weight == other.Weight;
} }
} }

3
src/Skia/Avalonia.Skia/SKTypefaceCollectionCache.cs

@ -1,3 +1,6 @@
// 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.Concurrent;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Fonts; using Avalonia.Media.Fonts;

Loading…
Cancel
Save