diff options
Diffstat (limited to 'src/ui/text.c')
-rw-r--r-- | src/ui/text.c | 72 |
1 files changed, 66 insertions, 6 deletions
diff --git a/src/ui/text.c b/src/ui/text.c index c8177096..7d141217 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -131,18 +131,25 @@ struct Impl_Font { | |||
131 | int baseline; | 131 | int baseline; |
132 | iHash glyphs; /* key is glyph index in the font */ /* TODO: does not need to be a Hash */ | 132 | iHash glyphs; /* key is glyph index in the font */ /* TODO: does not need to be a Hash */ |
133 | iBool isMonospaced; | 133 | iBool isMonospaced; |
134 | iBool manualKernOnly; | 134 | // iBool manualKernOnly; |
135 | enum iFontSize sizeId; /* used to look up different fonts of matching size */ | 135 | enum iFontSize sizeId; /* used to look up different fonts of matching size */ |
136 | uint32_t indexTable[128 - 32]; /* quick ASCII lookup */ | 136 | uint32_t indexTable[128 - 32]; /* quick ASCII lookup */ |
137 | #if defined (LAGRANGE_ENABLE_HARFBUZZ) | 137 | #if defined (LAGRANGE_ENABLE_HARFBUZZ) |
138 | hb_blob_t * hbBlob; /* raw TrueType data */ | 138 | hb_blob_t * hbBlob; /* raw TrueType data */ |
139 | hb_face_t * hbFace; | 139 | hb_face_t * hbFace; |
140 | hb_font_t * hbFont; | 140 | hb_font_t * hbMainFont; |
141 | hb_font_t * hbFont; /* may be a sub-font with customized font metrics */ | ||
141 | #endif | 142 | #endif |
142 | }; | 143 | }; |
143 | 144 | ||
144 | static iFont *font_Text_(enum iFontId id); | 145 | static iFont *font_Text_(enum iFontId id); |
145 | 146 | ||
147 | static hb_position_t hbGlyphHKernForNunito_(hb_font_t *font, void *fontData, | ||
148 | hb_codepoint_t firstGlyph, hb_codepoint_t secondGlyph, | ||
149 | void *userData) { | ||
150 | return 100; | ||
151 | } | ||
152 | |||
146 | static void init_Font(iFont *d, const iBlock *data, int height, float scale, | 153 | static void init_Font(iFont *d, const iBlock *data, int height, float scale, |
147 | enum iFontSize sizeId, iBool isMonospaced) { | 154 | enum iFontSize sizeId, iBool isMonospaced) { |
148 | init_Hash(&d->glyphs); | 155 | init_Hash(&d->glyphs); |
@@ -191,7 +198,23 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, | |||
191 | d->hbBlob = hb_blob_create(constData_Block(data), size_Block(data), | 198 | d->hbBlob = hb_blob_create(constData_Block(data), size_Block(data), |
192 | HB_MEMORY_MODE_READONLY, NULL, NULL); | 199 | HB_MEMORY_MODE_READONLY, NULL, NULL); |
193 | d->hbFace = hb_face_create(d->hbBlob, 0); | 200 | d->hbFace = hb_face_create(d->hbBlob, 0); |
194 | d->hbFont = hb_font_create(d->hbFace); | 201 | d->hbMainFont = hb_font_create(d->hbFace); |
202 | #if 0 | ||
203 | /* TODO: The custom kerning function doesn't get called? | ||
204 | Maybe HarfBuzz needs FreeType to do kerning? */ | ||
205 | if (d->family == nunito_TextFont) { | ||
206 | /* Customize the kerning of Nunito. */ | ||
207 | d->hbFont = hb_font_create_sub_font(d->hbMainFont); | ||
208 | hb_font_funcs_t *ffs = hb_font_funcs_create(); | ||
209 | hb_font_funcs_set_glyph_h_kerning_func(ffs, hbGlyphHKernForNunito_, d, NULL); | ||
210 | hb_font_set_funcs(d->hbFont, ffs, NULL, NULL); | ||
211 | hb_font_funcs_destroy(ffs); | ||
212 | } | ||
213 | else | ||
214 | #endif | ||
215 | { | ||
216 | d->hbFont = hb_font_reference(d->hbMainFont); | ||
217 | } | ||
195 | } | 218 | } |
196 | #endif | 219 | #endif |
197 | } | 220 | } |
@@ -207,6 +230,7 @@ static void deinit_Font(iFont *d) { | |||
207 | #if defined(LAGRANGE_ENABLE_HARFBUZZ) | 230 | #if defined(LAGRANGE_ENABLE_HARFBUZZ) |
208 | /* HarfBuzz objects. */ { | 231 | /* HarfBuzz objects. */ { |
209 | hb_font_destroy(d->hbFont); | 232 | hb_font_destroy(d->hbFont); |
233 | hb_font_destroy(d->hbMainFont); | ||
210 | hb_face_destroy(d->hbFace); | 234 | hb_face_destroy(d->hbFace); |
211 | hb_blob_destroy(d->hbBlob); | 235 | hb_blob_destroy(d->hbBlob); |
212 | } | 236 | } |
@@ -395,9 +419,9 @@ static void initFonts_Text_(iText *d) { | |||
395 | fontData[i].scaling, | 419 | fontData[i].scaling, |
396 | fontData[i].sizeId, | 420 | fontData[i].sizeId, |
397 | fontData[i].ttf == &fontIosevkaTermExtended_Embedded); | 421 | fontData[i].ttf == &fontIosevkaTermExtended_Embedded); |
398 | if (i == default_FontId || i == defaultMedium_FontId) { | 422 | // if (i == default_FontId || i == defaultMedium_FontId) { |
399 | font->manualKernOnly = iTrue; | 423 | // font->manualKernOnly = iTrue; |
400 | } | 424 | // } |
401 | } | 425 | } |
402 | gap_Text = iRound(gap_UI * d->contentFontSize); | 426 | gap_Text = iRound(gap_UI * d->contentFontSize); |
403 | } | 427 | } |
@@ -1065,6 +1089,32 @@ static iBool notify_WrapText_(iWrapText *d, const char *ending, int advance) { | |||
1065 | return iTrue; | 1089 | return iTrue; |
1066 | } | 1090 | } |
1067 | 1091 | ||
1092 | float horizKern_Font_(iFont *d, uint32_t glyph1, uint32_t glyph2) { | ||
1093 | #if defined (LAGRANGE_ENABLE_KERNING) | ||
1094 | if (!enableKerning_Text || d->family != nunito_TextFont) { | ||
1095 | return 0.0f; | ||
1096 | } | ||
1097 | if (glyph1 && glyph2) { | ||
1098 | /* These indices will be quickly found from the lookup table. */ | ||
1099 | const uint32_t gi_h = glyphIndex_Font_(d, 'h'); | ||
1100 | const uint32_t gi_i = glyphIndex_Font_(d, 'i'); | ||
1101 | int kern = 0; | ||
1102 | /* Nunito needs some kerning fixes. */ | ||
1103 | if (glyph1 == glyphIndex_Font_(d, 'W') && (glyph2 == gi_h || glyph2 == gi_i)) { | ||
1104 | kern = -60; | ||
1105 | } | ||
1106 | else if (glyph1 == glyphIndex_Font_(d, 'T') && glyph2 == gi_h) { | ||
1107 | kern = -25; | ||
1108 | } | ||
1109 | else if (glyph1 == glyphIndex_Font_(d, 'V') && glyph2 == gi_i) { | ||
1110 | kern = -40; | ||
1111 | } | ||
1112 | return d->xScale * kern; | ||
1113 | } | ||
1114 | #endif | ||
1115 | return 0.0f; | ||
1116 | } | ||
1117 | |||
1068 | #if defined (LAGRANGE_ENABLE_HARFBUZZ) | 1118 | #if defined (LAGRANGE_ENABLE_HARFBUZZ) |
1069 | static iRect run_Font_(iFont *d, const iRunArgs *args) { | 1119 | static iRect run_Font_(iFont *d, const iRunArgs *args) { |
1070 | const int mode = args->mode; | 1120 | const int mode = args->mode; |
@@ -1168,6 +1218,11 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1168 | break; | 1218 | break; |
1169 | } | 1219 | } |
1170 | x += xAdvance; | 1220 | x += xAdvance; |
1221 | /* Additional kerning tweak. It would be better to use HarfBuzz font callbacks, | ||
1222 | but they don't seem to get called? */ | ||
1223 | if (i + 1 < glyphCount) { | ||
1224 | x += horizKern_Font_(run->font, glyphId, glyphInfo[i + 1].codepoint); | ||
1225 | } | ||
1171 | } | 1226 | } |
1172 | /* Make a callback for each wrapped line. */ | 1227 | /* Make a callback for each wrapped line. */ |
1173 | if (breakPos) { | 1228 | if (breakPos) { |
@@ -1244,6 +1299,11 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1244 | } | 1299 | } |
1245 | xCursor += xAdvance; | 1300 | xCursor += xAdvance; |
1246 | yCursor += yAdvance; | 1301 | yCursor += yAdvance; |
1302 | /* Additional kerning tweak. It would be better to use HarfBuzz font callbacks, | ||
1303 | but they don't seem to get called? */ | ||
1304 | if (i + 1 < glyphCount) { | ||
1305 | xCursor += horizKern_Font_(run->font, glyphId, glyphInfo[i + 1].codepoint); | ||
1306 | } | ||
1247 | xCursorMax = iMax(xCursorMax, xCursor); | 1307 | xCursorMax = iMax(xCursorMax, xCursor); |
1248 | } | 1308 | } |
1249 | if (willAbortDueToWrap) { | 1309 | if (willAbortDueToWrap) { |