ligatures: upgrading

This commit is contained in:
Bakkeby 2024-03-07 15:34:21 +01:00
parent 677c2da0be
commit 0f50ef072c
4 changed files with 326 additions and 185 deletions

101
hb.c
View file

@ -11,6 +11,7 @@
#include "hb.h"
#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 }
#define BUFFER_STEP 256
hb_font_t *hbfindfont(XftFont *match);
@ -19,74 +20,109 @@ typedef struct {
hb_font_t *font;
} HbFontMatch;
static int hbfontslen = 0;
static HbFontMatch *hbfontcache = NULL;
typedef struct {
size_t capacity;
HbFontMatch *fonts;
} HbFontCache;
static HbFontCache hbfontcache = { 0, NULL };
typedef struct {
size_t capacity;
Rune *runes;
} RuneBuffer;
static RuneBuffer hbrunebuffer = { 0, NULL };
static hb_buffer_t *hbbuffer;
/*
* Poplulate the array 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 };
hb_feature_t features[] = { };
void
hbunloadfonts()
hbcreatebuffer(void)
{
for (int i = 0; i < hbfontslen; i++) {
hb_font_destroy(hbfontcache[i].font);
XftUnlockFace(hbfontcache[i].match);
hbbuffer = hb_buffer_create();
}
void
hbdestroybuffer(void)
{
hb_buffer_destroy(hbbuffer);
}
void
hbunloadfonts(void)
{
for (int i = 0; i < hbfontcache.capacity; i++) {
hb_font_destroy(hbfontcache.fonts[i].font);
XftUnlockFace(hbfontcache.fonts[i].match);
}
if (hbfontcache != NULL) {
free(hbfontcache);
hbfontcache = NULL;
if (hbfontcache.fonts != NULL) {
free(hbfontcache.fonts);
hbfontcache.fonts = NULL;
}
hbfontslen = 0;
hbfontcache.capacity = 0;
}
hb_font_t *
hbfindfont(XftFont *match)
{
for (int i = 0; i < hbfontslen; i++) {
if (hbfontcache[i].match == match)
return hbfontcache[i].font;
for (int i = 0; i < hbfontcache.capacity; i++) {
if (hbfontcache.fonts[i].match == match)
return hbfontcache.fonts[i].font;
}
/* Font not found in cache, caching it now. */
hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
hbfontcache.fonts = realloc(hbfontcache.fonts, sizeof(HbFontMatch) * (hbfontcache.capacity + 1));
FT_Face face = XftLockFace(match);
hb_font_t *font = hb_ft_font_create(face, NULL);
if (font == NULL)
die("Failed to load Harfbuzz font.");
hbfontcache[hbfontslen].match = match;
hbfontcache[hbfontslen].font = font;
hbfontslen += 1;
hbfontcache.fonts[hbfontcache.capacity].match = match;
hbfontcache.fonts[hbfontcache.capacity].font = font;
hbfontcache.capacity += 1;
return font;
}
void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length) {
Rune rune;
ushort mode = USHRT_MAX;
void
hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length)
{
uint32_t mode;
unsigned int glyph_count;
int i, end = start + length;
int rune_idx, glyph_idx, end = start + length;
hb_buffer_t *buffer = hbbuffer;
hb_font_t *font = hbfindfont(xfont);
if (font == NULL)
if (font == NULL) {
data->count = 0;
return;
}
hb_buffer_t *buffer = hb_buffer_create();
hb_buffer_reset(buffer);
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
/* Resize the buffer if required length is larger. */
if (hbrunebuffer.capacity < length) {
hbrunebuffer.capacity = (length / BUFFER_STEP + 1) * BUFFER_STEP;
hbrunebuffer.runes = realloc(hbrunebuffer.runes, hbrunebuffer.capacity * sizeof(Rune));
}
/* Fill buffer with codepoints. */
for (i = start; i < end; i++) {
rune = glyphs[i].u;
mode = glyphs[i].mode;
for (rune_idx = 0, glyph_idx = start; glyph_idx < end; glyph_idx++, rune_idx++) {
hbrunebuffer.runes[rune_idx] = glyphs[glyph_idx].u;
mode = glyphs[glyph_idx].mode;
if (mode & ATTR_WDUMMY)
rune = 0x0020;
hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
hbrunebuffer.runes[rune_idx] = 0x0020;
}
hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length);
/* Shape the segment. */
hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t));
@ -95,14 +131,9 @@ void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count);
/** Fill the output. */
/* Fill the output. */
data->buffer = buffer;
data->glyphs = info;
data->positions = pos;
data->count = glyph_count;
}
void hbcleanup(HbTransformData *data) {
hb_buffer_destroy(data->buffer);
memset(data, 0, sizeof(HbTransformData));
}