hb.c (3453B)
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <math.h> 4 #include <time.h> 5 #include <X11/Xft/Xft.h> 6 #include <X11/cursorfont.h> 7 #include <hb.h> 8 #include <hb-ft.h> 9 10 #include "st.h" 11 #include "hb.h" 12 13 #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 } 14 #define BUFFER_STEP 256 15 16 hb_font_t *hbfindfont(XftFont *match); 17 18 typedef struct { 19 XftFont *match; 20 hb_font_t *font; 21 } HbFontMatch; 22 23 typedef struct { 24 size_t capacity; 25 HbFontMatch *fonts; 26 } HbFontCache; 27 28 static HbFontCache hbfontcache = { 0, NULL }; 29 30 typedef struct { 31 size_t capacity; 32 Rune *runes; 33 } RuneBuffer; 34 35 static RuneBuffer hbrunebuffer = { 0, NULL }; 36 static hb_buffer_t *hbbuffer; 37 38 /* 39 * Poplulate the array with a list of font features, wrapped in FEATURE macro, 40 * e. g. 41 * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g') 42 */ 43 hb_feature_t features[] = { }; 44 45 void 46 hbcreatebuffer(void) 47 { 48 hbbuffer = hb_buffer_create(); 49 } 50 51 void 52 hbdestroybuffer(void) 53 { 54 hb_buffer_destroy(hbbuffer); 55 } 56 57 void 58 hbunloadfonts(void) 59 { 60 for (int i = 0; i < hbfontcache.capacity; i++) { 61 hb_font_destroy(hbfontcache.fonts[i].font); 62 XftUnlockFace(hbfontcache.fonts[i].match); 63 } 64 65 if (hbfontcache.fonts != NULL) { 66 free(hbfontcache.fonts); 67 hbfontcache.fonts = NULL; 68 } 69 hbfontcache.capacity = 0; 70 } 71 72 hb_font_t * 73 hbfindfont(XftFont *match) 74 { 75 for (int i = 0; i < hbfontcache.capacity; i++) { 76 if (hbfontcache.fonts[i].match == match) 77 return hbfontcache.fonts[i].font; 78 } 79 80 /* Font not found in cache, caching it now. */ 81 hbfontcache.fonts = realloc(hbfontcache.fonts, sizeof(HbFontMatch) * (hbfontcache.capacity + 1)); 82 FT_Face face = XftLockFace(match); 83 hb_font_t *font = hb_ft_font_create(face, NULL); 84 if (font == NULL) 85 die("Failed to load Harfbuzz font."); 86 87 hbfontcache.fonts[hbfontcache.capacity].match = match; 88 hbfontcache.fonts[hbfontcache.capacity].font = font; 89 hbfontcache.capacity += 1; 90 91 return font; 92 } 93 94 void 95 hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length) 96 { 97 uint32_t mode; 98 unsigned int glyph_count; 99 int rune_idx, glyph_idx, end = start + length; 100 hb_buffer_t *buffer = hbbuffer; 101 102 hb_font_t *font = hbfindfont(xfont); 103 if (font == NULL) { 104 data->count = 0; 105 return; 106 } 107 108 hb_buffer_reset(buffer); 109 hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); 110 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); 111 112 /* Resize the buffer if required length is larger. */ 113 if (hbrunebuffer.capacity < length) { 114 hbrunebuffer.capacity = (length / BUFFER_STEP + 1) * BUFFER_STEP; 115 hbrunebuffer.runes = realloc(hbrunebuffer.runes, hbrunebuffer.capacity * sizeof(Rune)); 116 } 117 118 /* Fill buffer with codepoints. */ 119 for (rune_idx = 0, glyph_idx = start; glyph_idx < end; glyph_idx++, rune_idx++) { 120 hbrunebuffer.runes[rune_idx] = glyphs[glyph_idx].u; 121 mode = glyphs[glyph_idx].mode; 122 if (mode & ATTR_WDUMMY) 123 hbrunebuffer.runes[rune_idx] = 0x0020; 124 } 125 hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length); 126 127 /* Shape the segment. */ 128 hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t)); 129 130 /* Get new glyph info. */ 131 hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count); 132 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); 133 134 /* Fill the output. */ 135 data->buffer = buffer; 136 data->glyphs = info; 137 data->positions = pos; 138 data->count = glyph_count; 139 }