diff --git a/src/Avalonia.Base/Media/FontSimulations.cs b/src/Avalonia.Base/Media/FontSimulations.cs
new file mode 100644
index 0000000000..2faf53f1d8
--- /dev/null
+++ b/src/Avalonia.Base/Media/FontSimulations.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Avalonia.Media
+{
+ ///
+ /// Specifies algorithmic style simulations to be applied to the typeface.
+ /// Bold and oblique simulations can be combined via bitwise OR operation.
+ ///
+ [Flags]
+ public enum FontSimulations : byte
+ {
+ ///
+ /// No simulations are performed.
+ ///
+ None = 0x0000,
+
+ ///
+ /// Algorithmic emboldening is performed.
+ ///
+ Bold = 0x0001,
+
+ ///
+ /// Algorithmic italicization is performed.
+ ///
+ Oblique = 0x0002
+ }
+}
diff --git a/src/Avalonia.Base/Media/GlyphMetrics.cs b/src/Avalonia.Base/Media/GlyphMetrics.cs
new file mode 100644
index 0000000000..2ee1f87d38
--- /dev/null
+++ b/src/Avalonia.Base/Media/GlyphMetrics.cs
@@ -0,0 +1,24 @@
+namespace Avalonia.Media;
+
+public readonly struct GlyphMetrics
+{
+ ///
+ /// Distance from the x-origin to the left extremum of the glyph.
+ ///
+ public int XBearing { get; init; }
+
+ ///
+ /// Distance from the top extremum of the glyph to the y-origin.
+ ///
+ public int YBearing{ get; init; }
+
+ ///
+ /// Distance from the left extremum of the glyph to the right extremum.
+ ///
+ public int Width{ get; init; }
+
+ ///
+ /// Distance from the top extremum of the glyph to the bottom extremum.
+ ///
+ public int Height{ get; init; }
+}
diff --git a/src/Avalonia.Base/Media/IGlyphTypeface.cs b/src/Avalonia.Base/Media/IGlyphTypeface.cs
index de2a2309ee..9e1e52cb73 100644
--- a/src/Avalonia.Base/Media/IGlyphTypeface.cs
+++ b/src/Avalonia.Base/Media/IGlyphTypeface.cs
@@ -19,6 +19,21 @@ namespace Avalonia.Media
///
FontMetrics Metrics { get; }
+ ///
+ /// Gets the algorithmic style simulations applied to this glyph typeface.
+ ///
+ FontSimulations FontSimulations { get; }
+
+ ///
+ /// Tries to get a glyph's metrics in em units.
+ ///
+ /// The glyph id.
+ /// The glyph metrics.
+ ///
+ /// true if an glyph's metrics was found, false otherwise.
+ ///
+ bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics);
+
///
/// Returns an glyph index for the specified codepoint.
///
diff --git a/src/Avalonia.Headless/HeadlessPlatformStubs.cs b/src/Avalonia.Headless/HeadlessPlatformStubs.cs
index c8ac947c16..76948e9286 100644
--- a/src/Avalonia.Headless/HeadlessPlatformStubs.cs
+++ b/src/Avalonia.Headless/HeadlessPlatformStubs.cs
@@ -102,6 +102,8 @@ namespace Avalonia.Headless
public int GlyphCount => 1337;
+ public FontSimulations FontSimulations { get; }
+
public void Dispose()
{
}
@@ -138,6 +140,17 @@ namespace Avalonia.Headless
table = null;
return false;
}
+
+ public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+ {
+ metrics = new GlyphMetrics
+ {
+ Height = 10,
+ Width = 10
+ };
+
+ return true;
+ }
}
class HeadlessTextShaperStub : ITextShaperImpl
diff --git a/src/Skia/Avalonia.Skia/FontManagerImpl.cs b/src/Skia/Avalonia.Skia/FontManagerImpl.cs
index 6b5e0b3db5..90ff9652d8 100644
--- a/src/Skia/Avalonia.Skia/FontManagerImpl.cs
+++ b/src/Skia/Avalonia.Skia/FontManagerImpl.cs
@@ -148,11 +148,19 @@ namespace Avalonia.Skia
$"Could not create glyph typeface for: {typeface.FontFamily.Name}.");
}
- var isFakeBold = (int)typeface.Weight >= 600 && !skTypeface.IsBold;
+ var fontSimulations = FontSimulations.None;
- var isFakeItalic = typeface.Style == FontStyle.Italic && !skTypeface.IsItalic;
-
- return new GlyphTypefaceImpl(skTypeface, isFakeBold, isFakeItalic);
+ if((int)typeface.Weight >= 600 && !skTypeface.IsBold)
+ {
+ fontSimulations |= FontSimulations.Bold;
+ }
+
+ if(typeface.Style == FontStyle.Italic && !skTypeface.IsItalic)
+ {
+ fontSimulations |= FontSimulations.Oblique;
+ }
+
+ return new GlyphTypefaceImpl(skTypeface, fontSimulations);
}
}
}
diff --git a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
index 7f3faf251f..d11f4aa7d3 100644
--- a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
+++ b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
@@ -12,7 +12,7 @@ namespace Avalonia.Skia
{
private bool _isDisposed;
- public GlyphTypefaceImpl(SKTypeface typeface, bool isFakeBold = false, bool isFakeItalic = false)
+ public GlyphTypefaceImpl(SKTypeface typeface, FontSimulations fontSimulations)
{
Typeface = typeface ?? throw new ArgumentNullException(nameof(typeface));
@@ -52,9 +52,7 @@ namespace Avalonia.Skia
GlyphCount = Typeface.GlyphCount;
- IsFakeBold = isFakeBold;
-
- IsFakeItalic = isFakeItalic;
+ FontSimulations = fontSimulations;
}
public Face Face { get; }
@@ -63,6 +61,8 @@ namespace Avalonia.Skia
public SKTypeface Typeface { get; }
+ public FontSimulations FontSimulations { get; }
+
public int ReplacementCodepoint { get; }
public FontMetrics Metrics { get; }
@@ -73,6 +73,26 @@ namespace Avalonia.Skia
public bool IsFakeItalic { get; }
+ public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+ {
+ metrics = default;
+
+ if (!Font.TryGetGlyphExtents(glyph, out var extents))
+ {
+ return false;
+ }
+
+ metrics = new GlyphMetrics
+ {
+ XBearing = extents.XBearing,
+ YBearing = extents.YBearing,
+ Width = extents.Width,
+ Height = extents.Height
+ };
+
+ return true;
+ }
+
///
public ushort GetGlyph(uint codepoint)
{
diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
index 77d0e58d3d..705c715455 100644
--- a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
+++ b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
@@ -1,10 +1,11 @@
using System;
-using System.Drawing.Drawing2D;
using Avalonia.Media;
using Avalonia.Metadata;
using HarfBuzzSharp;
using SharpDX.DirectWrite;
using FontMetrics = Avalonia.Media.FontMetrics;
+using FontSimulations = Avalonia.Media.FontSimulations;
+using GlyphMetrics = Avalonia.Media.GlyphMetrics;
namespace Avalonia.Direct2D1.Media
{
@@ -82,6 +83,8 @@ namespace Avalonia.Direct2D1.Media
public int GlyphCount { get; set; }
+ public FontSimulations FontSimulations => FontSimulations.None;
+
///
public ushort GetGlyph(uint codepoint)
{
@@ -135,6 +138,26 @@ namespace Avalonia.Direct2D1.Media
return Font.GetHorizontalGlyphAdvances(glyphIndices);
}
+ public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+ {
+ metrics = default;
+
+ if (!Font.TryGetGlyphExtents(glyph, out var extents))
+ {
+ return false;
+ }
+
+ metrics = new GlyphMetrics
+ {
+ XBearing = extents.XBearing,
+ YBearing = extents.YBearing,
+ Width = extents.Width,
+ Height = extents.Height
+ };
+
+ return true;
+ }
+
private void Dispose(bool disposing)
{
if (_isDisposed)
diff --git a/tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs b/tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs
index 7998c95877..a748f6cf00 100644
--- a/tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs
+++ b/tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs
@@ -103,7 +103,7 @@ namespace Avalonia.Skia.UnitTests.Media
}
}
- return new GlyphTypefaceImpl(skTypeface);
+ return new GlyphTypefaceImpl(skTypeface, FontSimulations.None);
}
}
}
diff --git a/tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs b/tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs
index 3bcbc2efbd..5b11345f16 100644
--- a/tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs
+++ b/tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs
@@ -10,7 +10,7 @@ namespace Avalonia.UnitTests
private bool _isDisposed;
private Blob _blob;
- public HarfBuzzGlyphTypefaceImpl(Stream data, bool isFakeBold = false, bool isFakeItalic = false)
+ public HarfBuzzGlyphTypefaceImpl(Stream data)
{
_blob = Blob.FromStream(data);
@@ -45,10 +45,6 @@ namespace Avalonia.UnitTests
};
GlyphCount = Face.GlyphCount;
-
- IsFakeBold = isFakeBold;
-
- IsFakeItalic = isFakeItalic;
}
public FontMetrics Metrics { get; }
@@ -58,10 +54,8 @@ namespace Avalonia.UnitTests
public Font Font { get; }
public int GlyphCount { get; set; }
-
- public bool IsFakeBold { get; }
-
- public bool IsFakeItalic { get; }
+
+ public FontSimulations FontSimulations { get; }
///
public ushort GetGlyph(uint codepoint)
@@ -162,5 +156,25 @@ namespace Avalonia.UnitTests
Dispose(true);
GC.SuppressFinalize(this);
}
+
+ public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+ {
+ metrics = default;
+
+ if (!Font.TryGetGlyphExtents(glyph, out var extents))
+ {
+ return false;
+ }
+
+ metrics = new GlyphMetrics
+ {
+ XBearing = extents.XBearing,
+ YBearing = extents.YBearing,
+ Width = extents.Width,
+ Height = extents.Height
+ };
+
+ return true;
+ }
}
}
diff --git a/tests/Avalonia.UnitTests/MockGlyphTypeface.cs b/tests/Avalonia.UnitTests/MockGlyphTypeface.cs
index a1c492a7f1..bd9d8e5adf 100644
--- a/tests/Avalonia.UnitTests/MockGlyphTypeface.cs
+++ b/tests/Avalonia.UnitTests/MockGlyphTypeface.cs
@@ -15,6 +15,8 @@ namespace Avalonia.UnitTests
public int GlyphCount => 1337;
+ public FontSimulations FontSimulations => throw new NotImplementedException();
+
public ushort GetGlyph(uint codepoint)
{
return (ushort)codepoint;
@@ -56,5 +58,16 @@ namespace Avalonia.UnitTests
table = null;
return false;
}
+
+ public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+ {
+ metrics = new GlyphMetrics
+ {
+ Width = 10,
+ Height = 10
+ };
+
+ return true;
+ }
}
}