HarfBuzzGlyphTypefaceImpl.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System;
  2. using System.IO;
  3. using Avalonia.Media;
  4. using HarfBuzzSharp;
  5. namespace Avalonia.UnitTests
  6. {
  7. public class HarfBuzzGlyphTypefaceImpl : IGlyphTypeface
  8. {
  9. private bool _isDisposed;
  10. private Blob _blob;
  11. public HarfBuzzGlyphTypefaceImpl(Stream data)
  12. {
  13. _blob = Blob.FromStream(data);
  14. Face = new Face(_blob, 0);
  15. Font = new Font(Face);
  16. Font.SetFunctionsOpenType();
  17. Font.GetScale(out var scale, out _);
  18. const double defaultFontRenderingEmSize = 12.0;
  19. var metrics = Font.OpenTypeMetrics;
  20. Metrics = new FontMetrics
  21. {
  22. DesignEmHeight = (short)scale,
  23. Ascent = (int)(metrics.GetXVariation(OpenTypeMetricsTag.HorizontalAscender) / defaultFontRenderingEmSize * scale),
  24. Descent = (int)(metrics.GetXVariation(OpenTypeMetricsTag.HorizontalDescender) / defaultFontRenderingEmSize * scale),
  25. LineGap = (int)(metrics.GetXVariation(OpenTypeMetricsTag.HorizontalLineGap) / defaultFontRenderingEmSize * scale),
  26. UnderlinePosition = (int)(metrics.GetXVariation(OpenTypeMetricsTag.UnderlineOffset) / defaultFontRenderingEmSize * scale),
  27. UnderlineThickness = (int)(metrics.GetXVariation(OpenTypeMetricsTag.UnderlineSize) / defaultFontRenderingEmSize * scale),
  28. StrikethroughPosition = (int)(metrics.GetXVariation(OpenTypeMetricsTag.StrikeoutOffset) / defaultFontRenderingEmSize * scale),
  29. StrikethroughThickness = (int)(metrics.GetXVariation(OpenTypeMetricsTag.StrikeoutSize) / defaultFontRenderingEmSize * scale),
  30. IsFixedPitch = GetGlyphAdvance(GetGlyph('a')) == GetGlyphAdvance(GetGlyph('b'))
  31. };
  32. GlyphCount = Face.GlyphCount;
  33. }
  34. public FontMetrics Metrics { get; }
  35. public Face Face { get; }
  36. public Font Font { get; }
  37. public int GlyphCount { get; set; }
  38. public FontSimulations FontSimulations { get; }
  39. public string FamilyName => "$Default";
  40. public FontWeight Weight { get; }
  41. public FontStyle Style { get; }
  42. public FontStretch Stretch { get; }
  43. /// <inheritdoc cref="IGlyphTypeface"/>
  44. public ushort GetGlyph(uint codepoint)
  45. {
  46. if (Font.TryGetGlyph(codepoint, out var glyph))
  47. {
  48. return (ushort)glyph;
  49. }
  50. return 0;
  51. }
  52. public bool TryGetGlyph(uint codepoint,out ushort glyph)
  53. {
  54. glyph = 0;
  55. if (Font.TryGetGlyph(codepoint, out var glyphId))
  56. {
  57. glyph = (ushort)glyphId;
  58. return true;
  59. }
  60. return false;
  61. }
  62. /// <inheritdoc cref="IGlyphTypeface"/>
  63. public ushort[] GetGlyphs(ReadOnlySpan<uint> codepoints)
  64. {
  65. var glyphs = new ushort[codepoints.Length];
  66. for (var i = 0; i < codepoints.Length; i++)
  67. {
  68. if (Font.TryGetGlyph(codepoints[i], out var glyph))
  69. {
  70. glyphs[i] = (ushort)glyph;
  71. }
  72. }
  73. return glyphs;
  74. }
  75. /// <inheritdoc cref="IGlyphTypeface"/>
  76. public int GetGlyphAdvance(ushort glyph)
  77. {
  78. return Font.GetHorizontalGlyphAdvance(glyph);
  79. }
  80. /// <inheritdoc cref="IGlyphTypeface"/>
  81. public int[] GetGlyphAdvances(ReadOnlySpan<ushort> glyphs)
  82. {
  83. var glyphIndices = new uint[glyphs.Length];
  84. for (var i = 0; i < glyphs.Length; i++)
  85. {
  86. glyphIndices[i] = glyphs[i];
  87. }
  88. return Font.GetHorizontalGlyphAdvances(glyphIndices);
  89. }
  90. public bool TryGetTable(uint tag, out byte[] table)
  91. {
  92. table = null;
  93. var blob = Face.ReferenceTable(tag);
  94. if (blob.Length > 0)
  95. {
  96. table = blob.AsSpan().ToArray();
  97. return true;
  98. }
  99. return false;
  100. }
  101. private void Dispose(bool disposing)
  102. {
  103. if (_isDisposed)
  104. {
  105. return;
  106. }
  107. _isDisposed = true;
  108. if (!disposing)
  109. {
  110. return;
  111. }
  112. Font?.Dispose();
  113. Face?.Dispose();
  114. _blob?.Dispose();
  115. }
  116. public void Dispose()
  117. {
  118. Dispose(true);
  119. GC.SuppressFinalize(this);
  120. }
  121. public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
  122. {
  123. metrics = default;
  124. if (!Font.TryGetGlyphExtents(glyph, out var extents))
  125. {
  126. return false;
  127. }
  128. metrics = new GlyphMetrics
  129. {
  130. XBearing = extents.XBearing,
  131. YBearing = extents.YBearing,
  132. Width = extents.Width,
  133. Height = extents.Height
  134. };
  135. return true;
  136. }
  137. }
  138. }