using System; using System.Runtime.InteropServices; using static StbTrueTypeSharp.StbTrueType; namespace FontStashSharp { internal unsafe class Font: IDisposable { private readonly byte[] Data; private GCHandle? dataPtr = null; private float AscentBase, DescentBase, LineHeightBase; public float Ascent { get; private set; } public float Descent { get; private set; } public float LineHeight { get; private set; } public float Scale { get; private set; } public stbtt_fontinfo _font = new stbtt_fontinfo(); public Font(byte[] data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } Data = data; dataPtr = GCHandle.Alloc(data, GCHandleType.Pinned); } ~Font() { Dispose(); } public void Dispose() { if (dataPtr != null) { dataPtr.Value.Free(); dataPtr = null; } } public void Recalculate(float size) { Ascent = AscentBase * size; Descent = DescentBase * size; LineHeight = LineHeightBase * size; Scale = stbtt_ScaleForPixelHeight(_font, size); } public int GetGlyphIndex(int codepoint) { return stbtt_FindGlyphIndex(_font, codepoint); } public void BuildGlyphBitmap(int glyph, float size, float scale, ref int advance, ref int lsb, ref int x0, ref int y0, ref int x1, ref int y1) { int advanceTemp, lsbTemp; stbtt_GetGlyphHMetrics(_font, glyph, &advanceTemp, &lsbTemp); advance = advanceTemp; lsb = lsbTemp; int x0Temp, y0Temp, x1Temp, y1Temp; stbtt_GetGlyphBitmapBox(_font, glyph, scale, scale, &x0Temp, &y0Temp, &x1Temp, &y1Temp); x0 = x0Temp; y0 = y0Temp; x1 = x1Temp; y1 = y1Temp; } public void RenderGlyphBitmap(byte[] output, int outWidth, int outHeight, int outStride, int glyph) { fixed (byte* outputPtr = output) { stbtt_MakeGlyphBitmap(_font, outputPtr, outWidth, outHeight, outStride, Scale, Scale, glyph); } } public static Font FromMemory(byte[] data) { var font = new Font(data); byte* dataPtr = (byte *)font.dataPtr.Value.AddrOfPinnedObject(); if (stbtt_InitFont(font._font, dataPtr, 0) == 0) throw new Exception("stbtt_InitFont failed"); int ascent, descent, lineGap; stbtt_GetFontVMetrics(font._font , &ascent, &descent, &lineGap); var fh = ascent - descent; font.AscentBase = ascent / (float)fh; font.DescentBase = descent / (float)fh; font.LineHeightBase = (fh + lineGap) / (float)fh; return font; } } }