dotfiles

[void/arch] linux dotfiles
git clone git://git.mdnr.space/dotfiles
Log | Files | Refs

hb.c (4006B)


      1 #include <stdlib.h>
      2 #include <stdio.h>
      3 #include <math.h>
      4 #include <X11/Xft/Xft.h>
      5 #include <X11/cursorfont.h>
      6 #include <hb.h>
      7 #include <hb-ft.h>
      8 
      9 #include "st.h"
     10 
     11 #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 }
     12 
     13 /*
     14  * Replace 0 with a list of font features, wrapped in FEATURE macro, e.g.
     15  * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
     16  * 
     17  * Uncomment either one of the 2 lines below. Uncomment the prior to disable (any) font features. Uncomment the 
     18  * latter to enable the (selected) font features.
     19  */
     20 
     21 hb_feature_t features[] = { 0 };
     22 //hb_feature_t features[] = { FEATURE('s','s','0','1'), FEATURE('s','s','0','2'), FEATURE('s','s','0','3'), FEATURE('s','s','0','5'), FEATURE('s','s','0','6'), FEATURE('s','s','0','7'), FEATURE('s','s','0','8'), FEATURE('z','e','r','o') };
     23 
     24 void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length);
     25 hb_font_t *hbfindfont(XftFont *match);
     26 
     27 typedef struct {
     28 	XftFont *match;
     29 	hb_font_t *font;
     30 } HbFontMatch;
     31 
     32 static int hbfontslen = 0;
     33 static HbFontMatch *hbfontcache = NULL;
     34 
     35 void
     36 hbunloadfonts()
     37 {
     38 	for (int i = 0; i < hbfontslen; i++) {
     39 		hb_font_destroy(hbfontcache[i].font);
     40 		XftUnlockFace(hbfontcache[i].match);
     41 	}
     42 
     43 	if (hbfontcache != NULL) {
     44 		free(hbfontcache);
     45 		hbfontcache = NULL;
     46 	}
     47 	hbfontslen = 0;
     48 }
     49 
     50 hb_font_t *
     51 hbfindfont(XftFont *match)
     52 {
     53 	for (int i = 0; i < hbfontslen; i++) {
     54 		if (hbfontcache[i].match == match)
     55 			return hbfontcache[i].font;
     56 	}
     57 
     58 	/* Font not found in cache, caching it now. */
     59 	hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
     60 	FT_Face face = XftLockFace(match);
     61 	hb_font_t *font = hb_ft_font_create(face, NULL);
     62 	if (font == NULL)
     63 		die("Failed to load Harfbuzz font.");
     64 
     65 	hbfontcache[hbfontslen].match = match;
     66 	hbfontcache[hbfontslen].font = font;
     67 	hbfontslen += 1;
     68 
     69 	return font;
     70 }
     71 
     72 void
     73 hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
     74 {
     75 	int start = 0, length = 1, gstart = 0;
     76 	hb_codepoint_t *codepoints = calloc((unsigned int)len, sizeof(hb_codepoint_t));
     77 
     78 	for (int idx = 1, specidx = 1; idx < len; idx++) {
     79 		if (glyphs[idx].mode & ATTR_WDUMMY) {
     80 			length += 1;
     81 			continue;
     82 		}
     83 
     84 		if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx]) || selected(x + idx, y) != selected(x + gstart, y)) {
     85 			hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
     86 
     87 			/* Reset the sequence. */
     88 			length = 1;
     89 			start = specidx;
     90 			gstart = idx;
     91 		} else {
     92 			length += 1;
     93 		}
     94 
     95 		specidx++;
     96 	}
     97 
     98 	/* EOL. */
     99 	hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
    100 
    101 	/* Apply the transformation to glyph specs. */
    102 	for (int i = 0, specidx = 0; i < len; i++) {
    103 		if (glyphs[i].mode & ATTR_WDUMMY)
    104 			continue;
    105 		if (glyphs[i].mode & ATTR_BOXDRAW) {
    106 			specidx++;
    107 			continue;
    108 		}
    109 
    110 		if (codepoints[i] != specs[specidx].glyph)
    111 			((Glyph *)glyphs)[i].mode |= ATTR_LIGA;
    112 
    113 		specs[specidx++].glyph = codepoints[i];
    114 	}
    115 
    116 	free(codepoints);
    117 }
    118 
    119 void
    120 hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length)
    121 {
    122 	hb_font_t *font = hbfindfont(xfont);
    123 	if (font == NULL)
    124 		return;
    125 
    126 	Rune rune;
    127 	ushort mode = USHRT_MAX;
    128 	hb_buffer_t *buffer = hb_buffer_create();
    129 	hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
    130 
    131 	/* Fill buffer with codepoints. */
    132 	for (int i = start; i < (start+length); i++) {
    133 		rune = string[i].u;
    134 		mode = string[i].mode;
    135 		if (mode & ATTR_WDUMMY)
    136 			rune = 0x0020;
    137 		hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
    138 	}
    139 
    140 	/* Shape the segment. */
    141 	hb_shape(font, buffer, features, sizeof(features));
    142 
    143 	/* Get new glyph info. */
    144 	hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);
    145 
    146 	/* Write new codepoints. */
    147 	for (int i = 0; i < length; i++) {
    148 		hb_codepoint_t gid = info[i].codepoint;
    149 		codepoints[start+i] = gid;
    150 	}
    151 
    152 	/* Cleanup. */
    153 	hb_buffer_destroy(buffer);
    154 }