-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Universal GlyphTypeface implementation #19852
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
base: master
Are you sure you want to change the base?
Conversation
API diff between 12.0.999-cibuild0060659-alpha and 12.0.999Avalonia.Base (net10.0, net8.0) namespace Avalonia.Media
{
public sealed class GlyphMetrics
{
- public int Height { get; init; }
+ public ushort Height { get; init; }
- public int Width { get; init; }
+ public ushort Width { get; init; }
}
public interface IGlyphTypeface
{
- ushort GetGlyph(uint codepoint);
- int GetGlyphAdvance(ushort glyph);
+ ushort GetGlyphAdvance(ushort glyph);
- int[] GetGlyphAdvances(System.ReadOnlySpan<ushort> glyphs);
- ushort[] GetGlyphs(System.ReadOnlySpan<uint> codepoints);
- bool TryGetGlyph(uint codepoint, out ushort glyph);
- bool TryGetTable(uint tag, out byte[] table);
+ System.Collections.Generic.IReadOnlyDictionary<int, ushort> CharacterToGlyphMap { get; }
+ System.Collections.Generic.IReadOnlyDictionary<System.Globalization.CultureInfo, string> FaceNames { get; }
+ System.Collections.Generic.IReadOnlyDictionary<System.Globalization.CultureInfo, string> FamilyNames { get; }
+ Avalonia.Media.IPlatformTypeface PlatformTypeface { get; }
+ System.Collections.Generic.IReadOnlyList<Avalonia.Media.Fonts.OpenTypeTag> SupportedFeatures { get; }
+ Avalonia.Media.ITextShaperTypeface TextShaperTypeface { get; }
+ string TypographicFamilyName { get; }
}
+ public sealed class GlyphTypeface : Avalonia.Media.IGlyphTypeface
+ {
+ public GlyphTypeface(Avalonia.Media.IPlatformTypeface typeface, Avalonia.Media.FontSimulations fontSimulations = 0);
+ public void Dispose();
+ public ushort GetGlyphAdvance(ushort glyphId);
+ public bool TryGetGlyphMetrics(ushort glyph, out Avalonia.Media.GlyphMetrics metrics);
+ public System.Collections.Generic.IReadOnlyDictionary<int, ushort> CharacterToGlyphMap { get; }
+ public System.Collections.Generic.IReadOnlyDictionary<System.Globalization.CultureInfo, string> FaceNames { get; }
+ public string FamilyName { get; }
+ public System.Collections.Generic.IReadOnlyDictionary<System.Globalization.CultureInfo, string> FamilyNames { get; }
+ public Avalonia.Media.FontSimulations FontSimulations { get; }
+ public int GlyphCount { get; }
+ public Avalonia.Media.FontMetrics Metrics { get; }
+ public Avalonia.Media.IPlatformTypeface PlatformTypeface { get; }
+ public Avalonia.Media.FontStretch Stretch { get; }
+ public Avalonia.Media.FontStyle Style { get; }
+ public System.Collections.Generic.IReadOnlyList<Avalonia.Media.Fonts.OpenTypeTag> SupportedFeatures { get; }
+ public Avalonia.Media.ITextShaperTypeface TextShaperTypeface { get; }
+ public string TypographicFamilyName { get; }
+ public Avalonia.Media.FontWeight Weight { get; }
+ }
+ public interface IFontMemory
+ {
+ bool TryGetTable(Avalonia.Media.Fonts.OpenTypeTag tag, out System.ReadOnlyMemory<byte> table);
+ }
+ public interface IPlatformTypeface : Avalonia.Media.IFontMemory
+ {
+ bool? TryGetStream(out System.IO.Stream? stream);
+ string FamilyName { get; }
+ Avalonia.Media.FontSimulations FontSimulations { get; }
+ Avalonia.Media.FontStretch Stretch { get; }
+ Avalonia.Media.FontStyle Style { get; }
+ Avalonia.Media.FontWeight Weight { get; }
+ }
+ public interface ITextShaperTypeface
+ {
+ }
}
namespace Avalonia.Media.Fonts
{
public abstract class FontCollectionBase : Avalonia.Media.Fonts.IFontCollection
{
+ public bool TryAddGlyphTypeface(Avalonia.Media.IGlyphTypeface glyphTypeface, Avalonia.Media.Fonts.FontCollectionKey key);
}
public interface IFontCollection
{
+ bool TryCreateSyntheticGlyphTypeface(Avalonia.Media.IGlyphTypeface glyphTypeface, Avalonia.Media.FontStyle style, Avalonia.Media.FontWeight weight, Avalonia.Media.FontStretch stretch, out Avalonia.Media.IGlyphTypeface? syntheticGlyphTypeface);
+ bool TryGetFamilyTypefaces(string familyName, out System.Collections.Generic.IReadOnlyList<Avalonia.Media.Typeface?>? familyTypefaces);
+ bool TryGetNearestMatch(string familyName, Avalonia.Media.FontStyle style, Avalonia.Media.FontWeight weight, Avalonia.Media.FontStretch stretch, out Avalonia.Media.IGlyphTypeface? glyphTypeface);
}
+ public static class FontCollectionKeyExtensions
+ {
+ public static Avalonia.Media.Fonts.FontCollectionKey ToFontCollectionKey(this Avalonia.Media.IGlyphTypeface glyphTypeface);
+ public static Avalonia.Media.Fonts.FontCollectionKey ToFontCollectionKey(this Avalonia.Media.IPlatformTypeface platformTypeface);
+ public static Avalonia.Media.Fonts.FontCollectionKey ToFontCollectionKey(this Avalonia.Media.Typeface typeface);
+ }
+ public sealed class OpenTypeTag
+ {
+ public static readonly Avalonia.Media.Fonts.OpenTypeTag Max;
+ public static readonly Avalonia.Media.Fonts.OpenTypeTag MaxSigned;
+ public static readonly Avalonia.Media.Fonts.OpenTypeTag None;
+ public OpenTypeTag(char c1, char c2, char c3, char c4);
+ public OpenTypeTag(uint value);
+ public bool Equals(Avalonia.Media.Fonts.OpenTypeTag other);
+ public override bool Equals(object obj);
+ public override int GetHashCode();
+ public static bool operator ==(Avalonia.Media.Fonts.OpenTypeTag left, Avalonia.Media.Fonts.OpenTypeTag right);
+ public static implicit operator uint(Avalonia.Media.Fonts.OpenTypeTag tag);
+ public static implicit operator Avalonia.Media.Fonts.OpenTypeTag(uint tag);
+ public static bool operator !=(Avalonia.Media.Fonts.OpenTypeTag left, Avalonia.Media.Fonts.OpenTypeTag right);
+ public static Avalonia.Media.Fonts.OpenTypeTag Parse(string tag);
+ public override string ToString();
+ }
}
namespace Avalonia.Media.TextFormatting
{
public sealed class TextShaperOptions
{
- public Avalonia.Media.IGlyphTypeface Typeface { get; }
+ public Avalonia.Media.IGlyphTypeface GlyphTypeface { get; }
}
}
namespace Avalonia.Platform
{
public interface IFontManagerImpl
{
- bool TryCreateGlyphTypeface(System.IO.Stream stream, Avalonia.Media.FontSimulations fontSimulations, out Avalonia.Media.IGlyphTypeface? glyphTypeface);
- bool TryCreateGlyphTypeface(string familyName, Avalonia.Media.FontStyle style, Avalonia.Media.FontWeight weight, Avalonia.Media.FontStretch stretch, out Avalonia.Media.IGlyphTypeface? glyphTypeface);
- bool? TryMatchCharacter(int? codepoint, Avalonia.Media.FontStyle? fontStyle, Avalonia.Media.FontWeight? fontWeight, Avalonia.Media.FontStretch? fontStretch, string? familyName, System.Globalization.CultureInfo? culture, out Avalonia.Media.Typeface? typeface);
+ bool TryCreateGlyphTypeface(System.IO.Stream stream, Avalonia.Media.FontSimulations fontSimulations, out Avalonia.Media.IPlatformTypeface? platformTypeface);
+ bool TryCreateGlyphTypeface(string familyName, Avalonia.Media.FontStyle style, Avalonia.Media.FontWeight weight, Avalonia.Media.FontStretch stretch, out Avalonia.Media.IPlatformTypeface? platformTypeface);
+ bool TryGetFamilyTypefaces(string familyName, out System.Collections.Generic.IReadOnlyList<Avalonia.Media.Typeface?>? familyTypefaces);
+ bool? TryMatchCharacter(int? codepoint, Avalonia.Media.FontStyle? fontStyle, Avalonia.Media.FontWeight? fontWeight, Avalonia.Media.FontStretch? fontStretch, string? familyName, System.Globalization.CultureInfo? culture, out Avalonia.Media.IPlatformTypeface? platformTypeface);
}
public interface IGlyphRunImpl
{
- Avalonia.Media.IGlyphTypeface GlyphTypeface { get; }
}
public interface ITextShaperImpl
{
+ Avalonia.Media.ITextShaperTypeface CreateTypeface(Avalonia.Media.IGlyphTypeface glyphTypeface);
}
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements a universal GlyphTypeface implementation that abstracts platform-specific font handling through new interfaces (IPlatformTypeface, ITextShaperTypeface, IFontMemory). The changes consolidate glyph typeface functionality, moving from direct platform implementations to a unified architecture.
Key changes:
- Introduced new interfaces to separate platform-specific font operations from the core
IGlyphTypefaceinterface - Replaced direct method calls like
GetGlyph()with aCharacterToGlyphMapdictionary lookup - Implemented OpenType table parsing classes for CMAP, metrics, and other font tables
Reviewed Changes
Copilot reviewed 68 out of 70 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Avalonia.Base/Media/IGlyphTypeface.cs | Expanded interface with new properties and removed deprecated methods; added IPlatformTypeface, ITextShaperTypeface, IFontMemory interfaces |
| src/Avalonia.Base/Media/GlyphTypeface.cs | New universal implementation using platform typeface abstraction and OpenType table parsing |
| src/Avalonia.Base/Media/Fonts/Tables/Cmap/*.cs | Added CMAP table parsing for character-to-glyph mapping |
| src/Skia/Avalonia.Skia/SkiaTypeface.cs | New platform-specific implementation for Skia |
| src/Windows/Avalonia.Direct2D1/Media/DWriteTypeface.cs | New platform-specific implementation for DirectWrite |
| src/Avalonia.Base/Media/Fonts/Tables/BigEndianBinaryReader.cs | Converted from stream-based to span-based for better performance |
| tests/* | Updated to use CharacterToGlyphMap instead of GetGlyph() |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
|
You can test this PR using the following package version. |
…y on any platform implementation
610d0fc to
628d2e4
Compare
|
Notes from the API review meeting:
|
Make GlyphTypeface.GlyphCount an integer
|
You can test this PR using the following package version. |
What does the pull request do?
This PR implements a universal GlyphTypeface implementation that abstracts platform-specific font handling through new interfaces (IPlatformTypeface, ITextShaperTypeface, IFontMemory). The changes consolidate glyph typeface functionality, moving from direct platform implementations to a unified architecture.
Key changes:
What is the current behavior?
Currently, we rely on the platform glyph typeface implementation to get certain text metrics, etc. That makes it hard to get a consistent behavior.
What is the updated/expected behavior with this PR?
How was the solution implemented (if it's not obvious)?
Checklist
Breaking changes
Obsoletions / Deprecations
Fixed issues
Fixes: #20190