From 2a32309f9cfc602d478229a6fe8562996a4652c9 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Sat, 9 Oct 2021 10:38:34 -0700 Subject: fix(term): forgot harfbuzz file --- sys/cmd/term/hb.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 sys/cmd/term/hb.c (limited to 'sys') diff --git a/sys/cmd/term/hb.c b/sys/cmd/term/hb.c new file mode 100644 index 0000000..4aed59b --- /dev/null +++ b/sys/cmd/term/hb.c @@ -0,0 +1,147 @@ +#include "term.h" + +#include +#include + +#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END } + +hb_font_t *hbfindfont(XftFont *match); +void hbtransformsegment(XftFont *xfont, const Letter *glyph, rune *codepoints, int start, int end); + +typedef struct +{ + XftFont *match; + hb_font_t *font; +} HbFontMatch; + +static int hbfontslen = 0; +static HbFontMatch *hbfontcache = nil; + +/* + * Replace 0 with a list of font features, wrapped in FEATURE macro, e.g. + * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g') + */ +hb_feature_t features[] = { 0 }; + +void +hbunloadfonts() +{ + int i; + for(i = 0; i < hbfontslen; i++) { + hb_font_destroy(hbfontcache[i].font); + XftUnlockFace(hbfontcache[i].match); + } + + if(hbfontcache != nil) { + free(hbfontcache); + hbfontcache = nil; + } + + hbfontslen = 0; +} + +hb_font_t * +hbfindfont(XftFont *match) +{ + int i; + for (i = 0; i < hbfontslen; i++) { + if (hbfontcache[i].match == match) + return hbfontcache[i].font; + } + + /* Font not found in cache, caching it now. */ + hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1)); + FT_Face face = XftLockFace(match); + hb_font_t *font = hb_ft_font_create(face, NULL); + if(!font) + fatal("failed to load Harfbuzz font."); + + hbfontcache[hbfontslen].match = match; + hbfontcache[hbfontslen].font = font; + hbfontslen += 1; + + return font; +} + +void +hbtransform(XftGlyphFontSpec *specs, const Letter *glyphs, size_t len, int x, int y) +{ + int idx, specidx, start = 0, length = 1, gstart = 0; + rune *runes = calloc((unsigned int)len, sizeof(hb_codepoint_t)); + + for(idx = 1, specidx = 1; idx < len; idx++) { + if(glyphs[idx].mode & Gwdummy) { + length += 1; + continue; + } + + if(specs[specidx].font != specs[start].font + || GLYPHCMP(glyphs[gstart], glyphs[idx]) + || selected(x + idx, y) != selected(x + gstart, y) + ) { + hbtransformsegment(specs[start].font, glyphs, runes, gstart, length); + /* reset the sequence. */ + length = 1; + start = specidx; + gstart = idx; + } else { + length += 1; + } + + specidx++; + } + + /* eol */ + hbtransformsegment(specs[start].font, glyphs, runes, gstart, length); + + /* apply the transformation to glyph specs. */ + for(idx = 0, specidx = 0; idx < len; idx++) { + if(glyphs[idx].mode & Gwdummy) + continue; + + if(runes[idx] != specs[specidx].glyph) + ((Letter *)glyphs)[idx].mode |= Gliga; + + specs[specidx++].glyph = runes[idx]; + } + + free(runes); +} + +void +hbtransformsegment(XftFont *xfont, const Letter *glyph, rune *codepoints, int start, int len) +{ + hb_font_t *font = hbfindfont(xfont); + if(!font) + return; + + int i; + rune r; + ushort mode = USHRT_MAX; + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + + /* Fill buffer with codepoints. */ + for(i=start; i < (start+len); i++) { + r = glyph[i].u; + mode = glyph[i].mode; + if(mode & Gwdummy) + r = 0x0020; + hb_buffer_add_codepoints(buffer, &r, 1, 0, 1); + } + + /* Shape the segment. */ + hb_shape(font, buffer, features, sizeof(features)); + + /* Get new glyph info. */ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL); + + /* Write new codepoints. */ + for(i = 0; i < len; i++) { + r = info[i].codepoint; + codepoints[start+i] = r; + } + + /* Cleanup. */ + hb_buffer_destroy(buffer); +} -- cgit v1.2.1