Skip to content

Commit

Permalink
[Text] Multiple text processing fixes (#15837)
Browse files Browse the repository at this point in the history
* Add font table loading

* Add localized family names

* Adjust license reference

* Add support for localized family names to the FontManager

* Add supported font features list

* Add unit test

* Fix font metrics

* Fix TextLineImpl baseline calculation of drawable runs

* Invert InlineRun baseline

* Adjust drawable run ascent offset calculation
  • Loading branch information
Gillibald authored Jun 5, 2024
1 parent e7b196c commit 2dfd9be
Show file tree
Hide file tree
Showing 23 changed files with 1,977 additions and 40 deletions.
52 changes: 35 additions & 17 deletions src/Avalonia.Base/Media/Fonts/EmbeddedFontCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,11 @@ public override void Initialize(IFontManagerImpl fontManager)

if (fontManager.TryCreateGlyphTypeface(stream, FontSimulations.None, out var glyphTypeface))
{
if (!_glyphTypefaceCache.TryGetValue(glyphTypeface.FamilyName, out var glyphTypefaces))
{
glyphTypefaces = new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();

if (_glyphTypefaceCache.TryAdd(glyphTypeface.FamilyName, glyphTypefaces))
{
_fontFamilies.Add(new FontFamily(_key, glyphTypeface.FamilyName));
}
}

var key = new FontCollectionKey(
glyphTypeface.Style,
glyphTypeface.Weight,
glyphTypeface.Stretch);

glyphTypefaces.TryAdd(key, glyphTypeface);
AddGlyphTypeface(glyphTypeface);
}
}
}


public override bool TryGetGlyphTypeface(string familyName, FontStyle style, FontWeight weight,
FontStretch stretch, [NotNullWhen(true)] out IGlyphTypeface? glyphTypeface)
{
Expand Down Expand Up @@ -142,5 +126,39 @@ public override bool TryGetGlyphTypeface(string familyName, FontStyle style, Fon
}

public override IEnumerator<FontFamily> GetEnumerator() => _fontFamilies.GetEnumerator();

private void AddGlyphTypeface(IGlyphTypeface glyphTypeface)
{
if (glyphTypeface is IGlyphTypeface2 glyphTypeface2)
{
foreach (var kvp in glyphTypeface2.FamilyNames)
{
var familyName = kvp.Value;

AddGlyphTypefaceByFamilyName(familyName, glyphTypeface);
}
}
else
{
AddGlyphTypefaceByFamilyName(glyphTypeface.FamilyName, glyphTypeface);
}

return;

void AddGlyphTypefaceByFamilyName(string familyName, IGlyphTypeface glyphTypeface)
{
var typefaces = _glyphTypefaceCache.GetOrAdd(familyName,
x =>
{
_fontFamilies.Add(new FontFamily(_key, glyphTypeface.FamilyName));

return new ConcurrentDictionary<FontCollectionKey, IGlyphTypeface?>();
});

typefaces.TryAdd(
new FontCollectionKey(glyphTypeface.Style, glyphTypeface.Weight, glyphTypeface.Stretch),
glyphTypeface);
}
}
}
}
71 changes: 71 additions & 0 deletions src/Avalonia.Base/Media/Fonts/OpenTypeTag.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;

namespace Avalonia.Media.Fonts
{
internal readonly record struct OpenTypeTag
{
public static readonly OpenTypeTag None = new OpenTypeTag(0, 0, 0, 0);
public static readonly OpenTypeTag Max = new OpenTypeTag(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
public static readonly OpenTypeTag MaxSigned = new OpenTypeTag((byte)sbyte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);

private readonly uint _value;

public OpenTypeTag(uint value)
{
_value = value;
}

public OpenTypeTag(char c1, char c2, char c3, char c4)
{
_value = (uint)(((byte)c1 << 24) | ((byte)c2 << 16) | ((byte)c3 << 8) | (byte)c4);
}

private OpenTypeTag(byte c1, byte c2, byte c3, byte c4)
{
_value = (uint)((c1 << 24) | (c2 << 16) | (c3 << 8) | c4);
}

public static OpenTypeTag Parse(string tag)
{
if (string.IsNullOrEmpty(tag))
return None;

var realTag = new char[4];

var len = Math.Min(4, tag.Length);
var i = 0;
for (; i < len; i++)
realTag[i] = tag[i];
for (; i < 4; i++)
realTag[i] = ' ';

return new OpenTypeTag(realTag[0], realTag[1], realTag[2], realTag[3]);
}

public override string ToString()
{
if (_value == None)
{
return nameof(None);
}
if (_value == Max)
{
return nameof(Max);
}
if (_value == MaxSigned)
{
return nameof(MaxSigned);
}

return string.Concat(
(char)(byte)(_value >> 24),
(char)(byte)(_value >> 16),
(char)(byte)(_value >> 8),
(char)(byte)_value);
}

public static implicit operator uint(OpenTypeTag tag) => tag._value;

public static implicit operator OpenTypeTag(uint tag) => new OpenTypeTag(tag);
}
}
Loading

0 comments on commit 2dfd9be

Please sign in to comment.