Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Text] Multiple text processing fixes #15837

Merged
merged 14 commits into from
Jun 5, 2024
Merged
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
Loading