Browse Source

Introduce GlyphMetrics

pull/9276/head
Benedikt Stebner 3 years ago
parent
commit
2a547d7161
  1. 27
      src/Avalonia.Base/Media/FontSimulations.cs
  2. 24
      src/Avalonia.Base/Media/GlyphMetrics.cs
  3. 13
      src/Avalonia.Base/Media/IGlyphTypeface.cs
  4. 13
      src/Avalonia.Headless/HeadlessPlatformStubs.cs
  5. 16
      src/Skia/Avalonia.Skia/FontManagerImpl.cs
  6. 28
      src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs
  7. 25
      src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs
  8. 32
      tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs
  9. 13
      tests/Avalonia.UnitTests/MockGlyphTypeface.cs

27
src/Avalonia.Base/Media/FontSimulations.cs

@ -0,0 +1,27 @@
using System;
namespace Avalonia.Media
{
/// <summary>
/// Specifies algorithmic style simulations to be applied to the typeface.
/// Bold and oblique simulations can be combined via bitwise OR operation.
/// </summary>
[Flags]
public enum FontSimulations : byte
{
/// <summary>
/// No simulations are performed.
/// </summary>
None = 0x0000,
/// <summary>
/// Algorithmic emboldening is performed.
/// </summary>
Bold = 0x0001,
/// <summary>
/// Algorithmic italicization is performed.
/// </summary>
Oblique = 0x0002
}
}

24
src/Avalonia.Base/Media/GlyphMetrics.cs

@ -0,0 +1,24 @@
namespace Avalonia.Media;
public readonly struct GlyphMetrics
{
/// <summary>
/// Distance from the x-origin to the left extremum of the glyph.
/// </summary>
public int XBearing { get; init; }
/// <summary>
/// Distance from the top extremum of the glyph to the y-origin.
/// </summary>
public int YBearing{ get; init; }
/// <summary>
/// Distance from the left extremum of the glyph to the right extremum.
/// </summary>
public int Width{ get; init; }
/// <summary>
/// Distance from the top extremum of the glyph to the bottom extremum.
/// </summary>
public int Height{ get; init; }
}

13
src/Avalonia.Base/Media/IGlyphTypeface.cs

@ -19,6 +19,19 @@ namespace Avalonia.Media
/// </returns>
FontMetrics Metrics { get; }
/// <summary>
/// Gets the algorithmic style simulations applied to this glyph typeface.
/// </summary>
FontSimulations FontSimulations { get; }
/// <summary>
///
/// </summary>
/// <param name="glyph"></param>
/// <param name="metrics"></param>
/// <returns></returns>
bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics);
/// <summary>
/// Returns an glyph index for the specified codepoint.
/// </summary>

13
src/Avalonia.Headless/HeadlessPlatformStubs.cs

@ -102,6 +102,8 @@ namespace Avalonia.Headless
public int GlyphCount => 1337;
public FontSimulations FontSimulations => throw new NotImplementedException();
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

16
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);
}
}
}

28
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;
}
/// <inheritdoc cref="IGlyphTypeface"/>
public ushort GetGlyph(uint codepoint)
{

25
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;
/// <inheritdoc cref="IGlyphTypeface"/>
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)

32
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; }
/// <inheritdoc cref="IGlyphTypeface"/>
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;
}
}
}

13
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;
}
}
}

Loading…
Cancel
Save