1 /* 2 Copyright Chris Jones 2020. 3 Distributed under the Boost Software License, Version 1.0. 4 See accompanying file Licence.txt or copy at... 5 https://www.boost.org/LICENSE_1_0.txt 6 */ 7 8 module dg2d.font; 9 10 import dg2d.misc; 11 import dg2d.truetype; 12 import dg2d.path; 13 14 /* 15 This is very much "just get it working so I can print something on screen", 16 */ 17 18 Font loadFont(string filename) 19 { 20 import dg2d.misc; 21 22 ubyte[] tmp = loadFileMalloc(filename); 23 if (tmp.ptr == null) return null; 24 25 ttFontInfo finfo; 26 if (ttLoadFont(finfo, tmp) == ttFail) return null; 27 Font font = new Font(); 28 font.m_data = tmp; 29 font.m_fontinfo = finfo; 30 return font; 31 } 32 33 // cast away const on font data for now till I can fix truetype stuff to work with const 34 35 Font loadFont(const(ubyte)[] rawfont) 36 { 37 import dg2d.misc; 38 39 ttFontInfo finfo; 40 if (ttLoadFont(finfo, cast(ubyte[]) rawfont) == ttFail) return null; 41 Font font = new Font(); 42 font.m_data = cast(ubyte[]) rawfont; 43 font.m_fontinfo = finfo; 44 return font; 45 } 46 47 class Font 48 { 49 this() 50 { 51 } 52 53 ~this() 54 { 55 dg2dFree(m_data.ptr); 56 } 57 58 // setSize, just going on this for now... 59 // https://docs.microsoft.com/en-us/typography/opentype/spec/ttch01 60 61 void setSize(float size) 62 { 63 m_size = clip(size, 1, 200); // what are plausible limits for size? 64 m_scale = size * 72.0 / (72.0 * 2048.0); 65 } 66 67 float addChar(ref Path path, float x, float y, uint charCode) 68 { 69 int gid = ttCharToGlyph(m_fontinfo, charCode); 70 if (gid == 0) return 0.0f; 71 72 if (m_prevGlyph > 0) 73 { 74 x += ttGetKerning(m_fontinfo, m_prevGlyph, gid)*m_scale; 75 } 76 ttAddGlyphToPath(m_fontinfo, gid, path, x, y, m_scale, -m_scale); 77 return ttGetAdvanceWidth(m_fontinfo, gid)*m_scale; 78 } 79 80 float lineHeight() 81 { 82 return (ttGetFontAscent(m_fontinfo) - ttGetFontDescent(m_fontinfo) 83 + ttGetFontLineGap(m_fontinfo)) * m_scale; 84 } 85 86 float height() 87 { 88 return (ttGetFontAscent(m_fontinfo) + ttGetFontDescent(m_fontinfo)) * m_scale; 89 } 90 91 // horizontal advance for a given glyph taking into account kerning. It needs the 92 // next character to properly evaluate, pass 0 if there is none 93 94 float glyphAdvance(uint charCode, uint nextCode) 95 { 96 int g0 = ttCharToGlyph(m_fontinfo, charCode); 97 int g1 = ttCharToGlyph(m_fontinfo, nextCode); 98 return (ttGetAdvanceWidth(m_fontinfo, g0) + 99 ttGetKerning(m_fontinfo, g0, g1)) * m_scale; 100 } 101 102 // getTextSpacing, calculates the spacing for each character in txt, 103 // note: advance array must have same length as txt 104 105 void getTextSpacing(const char[] txt, ref float[] advance) 106 { 107 assert(txt.length == advance.length); 108 109 int lb1 = cast(int)txt.length-1; 110 for(int i = 0; i < lb1; i++) 111 { 112 int g0 = ttCharToGlyph(m_fontinfo, txt[i]); 113 int g1 = ttCharToGlyph(m_fontinfo, txt[i+1]); 114 advance[i] = (ttGetAdvanceWidth(m_fontinfo, g0) + 115 ttGetKerning(m_fontinfo, g0, g1)) * m_scale; 116 } 117 advance[$-1] = ttGetAdvanceWidth(m_fontinfo, ttCharToGlyph(m_fontinfo, txt[$-1])); 118 } 119 120 // get width of txt 121 122 float getStrWidth(const char[] txt) 123 { 124 if (txt.length == 0) return 0; 125 126 float w = 0; 127 for(int i = 0; i < txt.length-1; i++) 128 { 129 int g0 = ttCharToGlyph(m_fontinfo, txt[i]); 130 int g1 = ttCharToGlyph(m_fontinfo, txt[i+1]); 131 w += (ttGetAdvanceWidth(m_fontinfo, g0) + 132 ttGetKerning(m_fontinfo, g0, g1)) * m_scale; 133 } 134 return w + ttGetAdvanceWidth(m_fontinfo, ttCharToGlyph(m_fontinfo, txt[$-1])) * m_scale; 135 } 136 137 private: 138 ubyte[] m_data; 139 ttFontInfo m_fontinfo; 140 float m_size; 141 float m_scale; 142 uint m_prevGlyph = -1; 143 bool m_doKerning = true; 144 } 145