Universal GlyphTypeface implementation (#19852)

* Introduce a universal IGlyphTypeface implementation that does not rely on any platform implementation

* Revert changes

* Fix Android

* Make the test happy

* Fix build

* Update baseline

* Fix naming

* Fix headless

* Move interfaces to dedicated files
Make GlyphTypeface.GlyphCount an integer

* Fix GlyphCount

* Make IGlyphTypeface NotClientImplementable

* Make sure we cache platform typefaces by their desired name, style, weight and stretch

* Update baseline

* Only use IGlyphTypeface

* Fix Android

* Try to clear the buffer before we encode somethimg

* Add needed test font

* Add more unit tests

* Reduce allocations

* Remove Direct2D1 test files

* More tests

* More complete table implementations

* More adjustments

* Use batch APIs

* Handle invalid timestamps

* Update baseline

* Introduce a CharacterToGlyphMap struct for faster access

* Remove AggressiveInlining

* Remove AggressiveInlining

* Make the head table optional for legacy fonts

* Remove Load method. Fix TextBlockTests

* Fix nullables

* Remove redundant folder

* Update Api baseline

* revert diff helper changes

* revert changes

* Use bare minimum font for Headless platform and introduce a test font manager that uses the Inter font for testing.

* Add missing font file for Headless platform

---------

Co-authored-by: Gillibald <stebner@avaloniaui.net>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
This commit is contained in:
Benedikt Stebner
2026-01-09 16:07:28 +01:00
committed by GitHub
parent 5d3a9c167a
commit e8424283fe
138 changed files with 7736 additions and 3004 deletions
@@ -10,7 +10,7 @@ using static Android.Content.Intent;
namespace ControlCatalog.Android
{
[Activity(Name = "com.Avalonia.ControlCatalog.MainActivity", Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, Exported = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
[Activity(Label = "ControlCatalog.Android", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", MainLauncher = true, Exported = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize | ConfigChanges.UiMode)]
// CategoryLeanbackLauncher is required for Android TV.
[IntentFilter(new[] { ActionView }, Categories = new[] { CategoryDefault, CategoryLeanbackLauncher })]
public class MainActivity : AvaloniaMainActivity
+1 -3
View File
@@ -1,6 +1,5 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
@@ -9,7 +8,6 @@ using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Skia;
using Avalonia.Threading;
using Avalonia.Utilities;
using SkiaSharp;
namespace RenderDemo.Pages
@@ -21,7 +19,7 @@ namespace RenderDemo.Pages
{
ClipToBounds = true;
var text = "Current rendering API is not Skia";
var glyphs = text.Select(ch => Typeface.Default.GlyphTypeface.GetGlyph(ch)).ToArray();
var glyphs = text.Select(ch => Typeface.Default.GlyphTypeface.CharacterToGlyphMap[ch]).ToArray();
_noSkia = new GlyphRun(Typeface.Default.GlyphTypeface, 12, text.AsMemory(), glyphs);
}
@@ -22,7 +22,7 @@ namespace RenderDemo.Pages
public class GlyphRunControl : Control
{
private IGlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
private char[] _characters = new char[1];
@@ -69,7 +69,7 @@ namespace RenderDemo.Pages
_fontSize += _direction;
_glyphIndices[0] = _glyphTypeface.GetGlyph(c);
_glyphIndices[0] = _glyphTypeface.CharacterToGlyphMap[c];
_characters[0] = c;
@@ -81,7 +81,7 @@ namespace RenderDemo.Pages
public class GlyphRunGeometryControl : Control
{
private IGlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1];
private char[] _characters = new char[1];
@@ -128,7 +128,7 @@ namespace RenderDemo.Pages
_fontSize += _direction;
_glyphIndices[0] = _glyphTypeface.GetGlyph(c);
_glyphIndices[0] = _glyphTypeface.CharacterToGlyphMap[c];
_characters[0] = c;
+2 -2
View File
@@ -223,12 +223,12 @@ namespace TextTestApp
}
}
private IImage CreateGlyphDrawing(IGlyphTypeface glyphTypeface, double emSize, GlyphInfo info)
private IImage CreateGlyphDrawing(GlyphTypeface glyphTypeface, double emSize, GlyphInfo info)
{
return new DrawingImage { Drawing = new GeometryDrawing { Brush = Brushes.Black, Geometry = GetGlyphOutline(glyphTypeface, emSize, info) } };
}
private Geometry GetGlyphOutline(IGlyphTypeface typeface, double emSize, GlyphInfo info)
private Geometry GetGlyphOutline(GlyphTypeface typeface, double emSize, GlyphInfo info)
{
// substitute for GlyphTypeface.GetGlyphOutline
return new GlyphRun(typeface, emSize, new[] { '\0' }, [info]).BuildGeometry();