-- ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); ++ start = i; + - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); _AT_@ -504,7 +550,7 @@ index 2a3bd38..5feac09 100644 } return numspecs; -_AT_@ -1517,14 +1556,17 @@ xdrawglyph(Glyph g, int x, int y) +_AT_@ -1517,14 +1567,17 @@ xdrawglyph(Glyph g, int x, int y) } void _AT_@ -524,3 +570,39 @@ index 2a3bd38..5feac09 100644 if (IS_SET(MODE_HIDE)) return; +_AT_@ -1652,18 +1705,16 @@ xdrawline(Line line, int x1, int y1, int x2) + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { ++ for (x = x1; x < x2; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; ++ if ((i > 0) && ATTRCMP(base, new)) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + i = 0; + } + if (i == 0) { +_AT_@ -1672,8 +1723,10 @@ xdrawline(Line line, int x1, int y1, int x2) + } + i++; + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); ++ if (i > 0) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); ++ } + } + + void diff --git a/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-20221120-0.9.diff b/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-20230105-0.9.diff similarity index 74% rename from st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-20221120-0.9.diff rename to st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-20230105-0.9.diff index 83c8f9fe..ddee323b 100644 --- a/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-20221120-0.9.diff +++ b/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-20230105-0.9.diff _AT_@ -22,7 +22,7 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk diff --git a/config.mk b/config.mk -index 47c615e..1ce493a 100644 +index 47c615e..d7439a3 100644 --- a/config.mk +++ b/config.mk _AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config _AT_@ -30,9 +30,10 @@ index 47c615e..1ce493a 100644 INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ - `$(PKG_CONFIG) --cflags freetype2` +-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --cflags freetype2` \ + `$(PKG_CONFIG) --cflags harfbuzz` - LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ ++LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` + `$(PKG_CONFIG) --libs freetype2` \ _AT_@ -42,10 +43,10 @@ index 47c615e..1ce493a 100644 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 diff --git a/hb.c b/hb.c new file mode 100644 -index 0000000..59b9200 +index 0000000..528c040 --- /dev/null +++ b/hb.c -_AT_@ -0,0 +1,107 @@ +_AT_@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <stdio.h> +#include <math.h> _AT_@ -58,6 +59,7 @@ index 0000000..59b9200 +#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); + _AT_@ -66,8 +68,19 @@ index 0000000..59b9200 + 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 }; + +/* + * Poplulate the array with a list of font features, wrapped in FEATURE macro, _AT_@ -79,45 +92,44 @@ index 0000000..59b9200 +void +hbunloadfonts() +{ -+ for (int i = 0; i < hbfontslen; i++) { -+ hb_font_destroy(hbfontcache[i].font); -+ XftUnlockFace(hbfontcache[i].match); ++ 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; + unsigned int glyph_count; -+ int i, end = start + length; ++ int rune_idx, glyph_idx, end = start + length; + + hb_font_t *font = hbfindfont(xfont); + if (font == NULL) _AT_@ -126,14 +138,20 @@ index 0000000..59b9200 + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + ++ /* 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); ++ } ++ + /* 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)); _AT_@ -142,7 +160,7 @@ index 0000000..59b9200 + 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; _AT_@ -215,7 +233,7 @@ index 6de960d..94679e4 100644 void xfinishdraw(void); void xloadcols(void); diff --git a/x.c b/x.c -index 27e81d1..34cb768 100644 +index 27e81d1..9d84793 100644 --- a/x.c +++ b/x.c _AT_@ -19,6 +19,7 @@ char *argv0; _AT_@ -234,6 +252,15 @@ index 27e81d1..34cb768 100644 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); +_AT_@ -759,7 +761,7 @@ xresize(int col, int row) + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +- xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); ++ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4); + } + + ushort _AT_@ -1071,6 +1073,9 @@ xunloadfont(Font *f) void xunloadfonts(void) _AT_@ -244,6 +271,15 @@ index 27e81d1..34cb768 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); +_AT_@ -1202,7 +1207,7 @@ xinit(int cols, int rows) + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ +- xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); ++ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); _AT_@ -1256,6 +1261,22 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } _AT_@ -251,7 +287,7 @@ index 27e81d1..34cb768 100644 +void +xresetfontsettings(ushort mode, Font **font, int *frcflags) +{ -+ *font = &dc.font; ++ *font = &dc.font; + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + *font = &dc.ibfont; + *frcflags = FRC_ITALICBOLD; _AT_@ -267,12 +303,13 @@ index 27e81d1..34cb768 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1270,119 +1291,137 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x +_AT_@ -1270,121 +1291,151 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + int i, f, length = 0, start = 0, numspecs = 0; ++ float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; + + /* Initial values. */ _AT_@ -286,7 +323,7 @@ index 27e81d1..34cb768 100644 /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY) ++ if (mode & ATTR_WDUMMY && i < (len - 1)) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -344,23 +381,34 @@ index 27e81d1..34cb768 100644 - break; + /* Shape the segment. */ + hbtransform(&shaped, font->match, glyphs, start, length); ++ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ cluster_xp = xp; cluster_yp = yp; + for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ rune = glyphs[start + code_idx].u; -+ runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ int idx = shaped.glyphs[code_idx].cluster; + -+ if (glyphs[start + code_idx].mode & ATTR_WDUMMY) ++ if (glyphs[start + idx].mode & ATTR_WDUMMY) + continue; + ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; ++ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ } ++ + if (shaped.glyphs[code_idx].codepoint != 0) { + /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; + specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset; -+ specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset; -+ xp += runewidth; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; + } else { + /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[start + idx].u; + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ _AT_@ -429,21 +477,17 @@ index 27e81d1..34cb768 100644 + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; -+ xp += runewidth; + numspecs++; + } } - } - +- - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - /* - * Nothing was found in the cache. Now use _AT_@ -459,7 +503,10 @@ index 27e81d1..34cb768 100644 - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -- ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); ++ start = i; + - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); _AT_@ -503,8 +550,11 @@ index 27e81d1..34cb768 100644 - numspecs++; } ++ hbcleanup(&shaped); return numspecs; -_AT_@ -1534,14 +1573,17 @@ xdrawglyph(Glyph g, int x, int y) + } + +_AT_@ -1534,14 +1585,17 @@ xdrawglyph(Glyph g, int x, int y) } void _AT_@ -524,3 +574,39 @@ index 27e81d1..34cb768 100644 if (IS_SET(MODE_HIDE)) return; +_AT_@ -1669,18 +1723,16 @@ xdrawline(Line line, int x1, int y1, int x2) + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { ++ for (x = x1; x < x2; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; ++ if ((i > 0) && ATTRCMP(base, new)) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + i = 0; + } + if (i == 0) { +_AT_@ -1689,8 +1741,10 @@ xdrawline(Line line, int x1, int y1, int x2) + } + i++; + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); ++ if (i > 0) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); ++ } + } + + void diff --git a/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-20221120-0.9.diff b/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-20230105-0.9.diff similarity index 74% rename from st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-20221120-0.9.diff rename to st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-20230105-0.9.diff index 230e177f..e49bc9d3 100644 --- a/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-20221120-0.9.diff +++ b/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-20230105-0.9.diff _AT_@ -22,7 +22,7 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk diff --git a/config.mk b/config.mk -index 47c615e..1ce493a 100644 +index 47c615e..d7439a3 100644 --- a/config.mk +++ b/config.mk _AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config _AT_@ -30,9 +30,10 @@ index 47c615e..1ce493a 100644 INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ - `$(PKG_CONFIG) --cflags freetype2` +-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --cflags freetype2` \ + `$(PKG_CONFIG) --cflags harfbuzz` - LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ ++LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` + `$(PKG_CONFIG) --libs freetype2` \ _AT_@ -42,10 +43,10 @@ index 47c615e..1ce493a 100644 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 diff --git a/hb.c b/hb.c new file mode 100644 -index 0000000..59b9200 +index 0000000..528c040 --- /dev/null +++ b/hb.c -_AT_@ -0,0 +1,107 @@ +_AT_@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <stdio.h> +#include <math.h> _AT_@ -58,6 +59,7 @@ index 0000000..59b9200 +#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); + _AT_@ -66,8 +68,19 @@ index 0000000..59b9200 + 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 }; + +/* + * Poplulate the array with a list of font features, wrapped in FEATURE macro, _AT_@ -79,45 +92,44 @@ index 0000000..59b9200 +void +hbunloadfonts() +{ -+ for (int i = 0; i < hbfontslen; i++) { -+ hb_font_destroy(hbfontcache[i].font); -+ XftUnlockFace(hbfontcache[i].match); ++ 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; + unsigned int glyph_count; -+ int i, end = start + length; ++ int rune_idx, glyph_idx, end = start + length; + + hb_font_t *font = hbfindfont(xfont); + if (font == NULL) _AT_@ -126,14 +138,20 @@ index 0000000..59b9200 + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + ++ /* 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); ++ } ++ + /* 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)); _AT_@ -142,7 +160,7 @@ index 0000000..59b9200 + 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; _AT_@ -174,16 +192,17 @@ index 0000000..88de9bd +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index 79ee9ba..7675db6 100644 +index 79ee9ba..454771d 100644 --- a/st.c +++ b/st.c -_AT_@ -2711,7 +2711,8 @@ draw(void) +_AT_@ -2711,7 +2711,9 @@ draw(void) drawregion(0, 0, term.col, term.row); if (term.scr == 0) xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], - term.ocx, term.ocy, term.line[term.ocy][term.ocx]); + term.ocx, term.ocy, term.line[term.ocy][term.ocx], + term.line[term.ocy], term.col); ++ term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); _AT_@ -215,7 +234,7 @@ index 6de960d..94679e4 100644 void xfinishdraw(void); void xloadcols(void); diff --git a/x.c b/x.c -index 27e81d1..34cb768 100644 +index 27e81d1..5d19ed7 100644 --- a/x.c +++ b/x.c _AT_@ -19,6 +19,7 @@ char *argv0; _AT_@ -234,6 +253,15 @@ index 27e81d1..34cb768 100644 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); +_AT_@ -759,7 +761,7 @@ xresize(int col, int row) + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +- xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); ++ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4); + } + + ushort _AT_@ -1071,6 +1073,9 @@ xunloadfont(Font *f) void xunloadfonts(void) _AT_@ -244,6 +272,15 @@ index 27e81d1..34cb768 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); +_AT_@ -1202,7 +1207,7 @@ xinit(int cols, int rows) + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ +- xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); ++ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); _AT_@ -1256,6 +1261,22 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } _AT_@ -251,7 +288,7 @@ index 27e81d1..34cb768 100644 +void +xresetfontsettings(ushort mode, Font **font, int *frcflags) +{ -+ *font = &dc.font; ++ *font = &dc.font; + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + *font = &dc.ibfont; + *frcflags = FRC_ITALICBOLD; _AT_@ -267,12 +304,13 @@ index 27e81d1..34cb768 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1270,119 +1291,137 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x +_AT_@ -1270,119 +1291,148 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + int i, f, length = 0, start = 0, numspecs = 0; ++ float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; + + /* Initial values. */ _AT_@ -286,7 +324,7 @@ index 27e81d1..34cb768 100644 /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY) ++ if (mode & ATTR_WDUMMY && i < (len - 1)) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -344,23 +382,34 @@ index 27e81d1..34cb768 100644 - break; + /* Shape the segment. */ + hbtransform(&shaped, font->match, glyphs, start, length); ++ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ cluster_xp = xp; cluster_yp = yp; + for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ rune = glyphs[start + code_idx].u; -+ runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ int idx = shaped.glyphs[code_idx].cluster; + -+ if (glyphs[start + code_idx].mode & ATTR_WDUMMY) ++ if (glyphs[start + idx].mode & ATTR_WDUMMY) + continue; + ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; ++ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ } ++ + if (shaped.glyphs[code_idx].codepoint != 0) { + /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; + specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset; -+ specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset; -+ xp += runewidth; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; + } else { + /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[start + idx].u; + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ _AT_@ -429,21 +478,17 @@ index 27e81d1..34cb768 100644 + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; -+ xp += runewidth; + numspecs++; + } } - } - +- - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - /* - * Nothing was found in the cache. Now use _AT_@ -459,7 +504,10 @@ index 27e81d1..34cb768 100644 - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -- ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); ++ start = i; + - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); _AT_@ -504,7 +552,7 @@ index 27e81d1..34cb768 100644 } return numspecs; -_AT_@ -1534,14 +1573,17 @@ xdrawglyph(Glyph g, int x, int y) +_AT_@ -1534,14 +1584,17 @@ xdrawglyph(Glyph g, int x, int y) } void _AT_@ -524,3 +572,39 @@ index 27e81d1..34cb768 100644 if (IS_SET(MODE_HIDE)) return; +_AT_@ -1669,18 +1722,16 @@ xdrawline(Line line, int x1, int y1, int x2) + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { ++ for (x = x1; x < x2; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; ++ if ((i > 0) && ATTRCMP(base, new)) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + i = 0; + } + if (i == 0) { +_AT_@ -1689,8 +1740,10 @@ xdrawline(Line line, int x1, int y1, int x2) + } + i++; + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); ++ if (i > 0) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); ++ } + } + + void diff --git a/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-ringbuffer-20221120-0.9.diff b/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-ringbuffer-20230105-0.9.diff similarity index 74% rename from st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-ringbuffer-20221120-0.9.diff rename to st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-ringbuffer-20230105-0.9.diff index 586cbbce..b4a23522 100644 --- a/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-ringbuffer-20221120-0.9.diff +++ b/st.suckless.org/patches/ligatures/0.9/st-ligatures-alpha-scrollback-ringbuffer-20230105-0.9.diff _AT_@ -22,7 +22,7 @@ index 470ac86..38240da 100644 $(OBJ): config.h config.mk diff --git a/config.mk b/config.mk -index 47c615e..1ce493a 100644 +index 47c615e..d7439a3 100644 --- a/config.mk +++ b/config.mk _AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config _AT_@ -30,9 +30,10 @@ index 47c615e..1ce493a 100644 INCS = -I$(X11INC) \ `$(PKG_CONFIG) --cflags fontconfig` \ - `$(PKG_CONFIG) --cflags freetype2` +-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ + `$(PKG_CONFIG) --cflags freetype2` \ + `$(PKG_CONFIG) --cflags harfbuzz` - LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ ++LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` + `$(PKG_CONFIG) --libs freetype2` \ _AT_@ -42,10 +43,10 @@ index 47c615e..1ce493a 100644 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 diff --git a/hb.c b/hb.c new file mode 100644 -index 0000000..59b9200 +index 0000000..528c040 --- /dev/null +++ b/hb.c -_AT_@ -0,0 +1,107 @@ +_AT_@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <stdio.h> +#include <math.h> _AT_@ -58,6 +59,7 @@ index 0000000..59b9200 +#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); + _AT_@ -66,8 +68,19 @@ index 0000000..59b9200 + 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 }; + +/* + * Poplulate the array with a list of font features, wrapped in FEATURE macro, _AT_@ -79,45 +92,44 @@ index 0000000..59b9200 +void +hbunloadfonts() +{ -+ for (int i = 0; i < hbfontslen; i++) { -+ hb_font_destroy(hbfontcache[i].font); -+ XftUnlockFace(hbfontcache[i].match); ++ 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; + unsigned int glyph_count; -+ int i, end = start + length; ++ int rune_idx, glyph_idx, end = start + length; + + hb_font_t *font = hbfindfont(xfont); + if (font == NULL) _AT_@ -126,14 +138,20 @@ index 0000000..59b9200 + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + ++ /* 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); ++ } ++ + /* 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)); _AT_@ -142,7 +160,7 @@ index 0000000..59b9200 + 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; _AT_@ -174,16 +192,17 @@ index 0000000..88de9bd +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index 79ee9ba..7675db6 100644 +index 79ee9ba..454771d 100644 --- a/st.c +++ b/st.c -_AT_@ -2762,7 +2762,8 @@ draw(void) +_AT_@ -2711,7 +2711,9 @@ draw(void) drawregion(0, 0, term.col, term.row); if (TSCREEN.off == 0) xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], - term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]); + term.ocx, term.ocy, TLINE(term.ocy)[term.ocx], + TLINE(term.ocy), term.col); ++ term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); _AT_@ -215,7 +234,7 @@ index 6de960d..94679e4 100644 void xfinishdraw(void); void xloadcols(void); diff --git a/x.c b/x.c -index 27e81d1..34cb768 100644 +index 27e81d1..5d19ed7 100644 --- a/x.c +++ b/x.c _AT_@ -19,6 +19,7 @@ char *argv0; _AT_@ -234,6 +253,15 @@ index 27e81d1..34cb768 100644 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); +_AT_@ -759,7 +761,7 @@ xresize(int col, int row) + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +- xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); ++ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4); + } + + ushort _AT_@ -1071,6 +1073,9 @@ xunloadfont(Font *f) void xunloadfonts(void) _AT_@ -244,6 +272,15 @@ index 27e81d1..34cb768 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); +_AT_@ -1202,7 +1207,7 @@ xinit(int cols, int rows) + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ +- xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); ++ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); _AT_@ -1256,6 +1261,22 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } _AT_@ -251,7 +288,7 @@ index 27e81d1..34cb768 100644 +void +xresetfontsettings(ushort mode, Font **font, int *frcflags) +{ -+ *font = &dc.font; ++ *font = &dc.font; + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + *font = &dc.ibfont; + *frcflags = FRC_ITALICBOLD; _AT_@ -267,12 +304,13 @@ index 27e81d1..34cb768 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1270,119 +1291,137 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x +_AT_@ -1270,119 +1291,148 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + int i, f, length = 0, start = 0, numspecs = 0; ++ float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; + + /* Initial values. */ _AT_@ -286,7 +324,7 @@ index 27e81d1..34cb768 100644 /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY) ++ if (mode & ATTR_WDUMMY && i < (len - 1)) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -344,23 +382,34 @@ index 27e81d1..34cb768 100644 - break; + /* Shape the segment. */ + hbtransform(&shaped, font->match, glyphs, start, length); ++ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ cluster_xp = xp; cluster_yp = yp; + for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ rune = glyphs[start + code_idx].u; -+ runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ int idx = shaped.glyphs[code_idx].cluster; + -+ if (glyphs[start + code_idx].mode & ATTR_WDUMMY) ++ if (glyphs[start + idx].mode & ATTR_WDUMMY) + continue; + ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; ++ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ } ++ + if (shaped.glyphs[code_idx].codepoint != 0) { + /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; + specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset; -+ specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset; -+ xp += runewidth; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; + } else { + /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[start + idx].u; + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ _AT_@ -429,21 +478,17 @@ index 27e81d1..34cb768 100644 + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; -+ xp += runewidth; + numspecs++; + } } - } - +- - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - /* - * Nothing was found in the cache. Now use _AT_@ -459,7 +504,10 @@ index 27e81d1..34cb768 100644 - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -- ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); ++ start = i; + - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); _AT_@ -504,7 +552,7 @@ index 27e81d1..34cb768 100644 } return numspecs; -_AT_@ -1534,14 +1573,17 @@ xdrawglyph(Glyph g, int x, int y) +_AT_@ -1534,14 +1584,17 @@ xdrawglyph(Glyph g, int x, int y) } void _AT_@ -524,3 +572,39 @@ index 27e81d1..34cb768 100644 if (IS_SET(MODE_HIDE)) return; +_AT_@ -1669,18 +1722,16 @@ xdrawline(Line line, int x1, int y1, int x2) + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { ++ for (x = x1; x < x2; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; ++ if ((i > 0) && ATTRCMP(base, new)) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + i = 0; + } + if (i == 0) { +_AT_@ -1689,8 +1740,10 @@ xdrawline(Line line, int x1, int y1, int x2) + } + i++; + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); ++ if (i > 0) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); ++ } + } + + void diff --git a/st.suckless.org/patches/ligatures/0.9/st-ligatures-boxdraw-20221120-0.9.diff b/st.suckless.org/patches/ligatures/0.9/st-ligatures-boxdraw-20230105-0.9.diff similarity index 76% rename from st.suckless.org/patches/ligatures/0.9/st-ligatures-boxdraw-20221120-0.9.diff rename to st.suckless.org/patches/ligatures/0.9/st-ligatures-boxdraw-20230105-0.9.diff index fa11b28b..6191e7fd 100644 --- a/st.suckless.org/patches/ligatures/0.9/st-ligatures-boxdraw-20221120-0.9.diff +++ b/st.suckless.org/patches/ligatures/0.9/st-ligatures-boxdraw-20230105-0.9.diff _AT_@ -43,10 +43,10 @@ index 1e306f8..3e13e53 100644 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 diff --git a/hb.c b/hb.c new file mode 100644 -index 0000000..59b9200 +index 0000000..528c040 --- /dev/null +++ b/hb.c -_AT_@ -0,0 +1,107 @@ +_AT_@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <stdio.h> +#include <math.h> _AT_@ -59,6 +59,7 @@ index 0000000..59b9200 +#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); + _AT_@ -67,8 +68,19 @@ index 0000000..59b9200 + 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 }; + +/* + * Poplulate the array with a list of font features, wrapped in FEATURE macro, _AT_@ -80,45 +92,44 @@ index 0000000..59b9200 +void +hbunloadfonts() +{ -+ for (int i = 0; i < hbfontslen; i++) { -+ hb_font_destroy(hbfontcache[i].font); -+ XftUnlockFace(hbfontcache[i].match); ++ 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; + unsigned int glyph_count; -+ int i, end = start + length; ++ int rune_idx, glyph_idx, end = start + length; + + hb_font_t *font = hbfindfont(xfont); + if (font == NULL) _AT_@ -127,14 +138,20 @@ index 0000000..59b9200 + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + ++ /* 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); ++ } ++ + /* 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)); _AT_@ -143,7 +160,7 @@ index 0000000..59b9200 + 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; _AT_@ -216,7 +233,7 @@ index 6de960d..94679e4 100644 void xfinishdraw(void); void xloadcols(void); diff --git a/x.c b/x.c -index bf6bbf9..440bd2a 100644 +index bf6bbf9..929a59a 100644 --- a/x.c +++ b/x.c _AT_@ -19,6 +19,7 @@ char *argv0; _AT_@ -235,6 +252,15 @@ index bf6bbf9..440bd2a 100644 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); +_AT_@ -757,7 +759,7 @@ xresize(int col, int row) + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +- xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); ++ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4); + } + + ushort _AT_@ -1062,6 +1064,9 @@ xunloadfont(Font *f) void xunloadfonts(void) _AT_@ -245,6 +271,15 @@ index bf6bbf9..440bd2a 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); +_AT_@ -1185,7 +1190,7 @@ xinit(int cols, int rows) + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ +- xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); ++ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); _AT_@ -1241,6 +1246,22 @@ xinit(int cols, int rows) boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); } _AT_@ -252,7 +287,7 @@ index bf6bbf9..440bd2a 100644 +void +xresetfontsettings(ushort mode, Font **font, int *frcflags) +{ -+ *font = &dc.font; ++ *font = &dc.font; + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + *font = &dc.ibfont; + *frcflags = FRC_ITALICBOLD; _AT_@ -268,12 +303,13 @@ index bf6bbf9..440bd2a 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1255,124 +1276,145 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x +_AT_@ -1255,126 +1276,158 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + int i, f, length = 0, start = 0, numspecs = 0; ++ float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; + + /* Initial values. */ _AT_@ -287,7 +323,7 @@ index bf6bbf9..440bd2a 100644 /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY) ++ if (mode & ATTR_WDUMMY && i < (len - 1)) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -350,31 +386,41 @@ index bf6bbf9..440bd2a 100644 - break; + /* Shape the segment. */ + hbtransform(&shaped, font->match, glyphs, start, length); ++ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ cluster_xp = xp; cluster_yp = yp; + for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ rune = glyphs[start + code_idx].u; -+ runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ int idx = shaped.glyphs[code_idx].cluster; + -+ if (glyphs[start + code_idx].mode & ATTR_WDUMMY) ++ if (glyphs[start + idx].mode & ATTR_WDUMMY) + continue; + ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; ++ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ } ++ + if (glyphs[start + code_idx].mode & ATTR_BOXDRAW) { + /* minor shoehorning: boxdraw uses only this ushort */ + specs[numspecs].font = font->match; + specs[numspecs].glyph = boxdrawindex(&glyphs[start + code_idx]); + specs[numspecs].x = xp; + specs[numspecs].y = yp; -+ xp += runewidth; + numspecs++; + } else if (shaped.glyphs[code_idx].codepoint != 0) { + /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; + specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset; -+ specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset; -+ xp += runewidth; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; + } else { + /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[start + idx].u; + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ _AT_@ -443,7 +489,6 @@ index bf6bbf9..440bd2a 100644 + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; -+ xp += runewidth; + numspecs++; + } } _AT_@ -517,8 +562,11 @@ index bf6bbf9..440bd2a 100644 - numspecs++; } ++ hbcleanup(&shaped); return numspecs; -_AT_@ -1528,14 +1570,17 @@ xdrawglyph(Glyph g, int x, int y) + } + +_AT_@ -1528,14 +1581,17 @@ xdrawglyph(Glyph g, int x, int y) } void _AT_@ -538,3 +586,39 @@ index bf6bbf9..440bd2a 100644 if (IS_SET(MODE_HIDE)) return; +_AT_@ -1663,18 +1719,16 @@ xdrawline(Line line, int x1, int y1, int x2) + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { ++ for (x = x1; x < x2; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; ++ if ((i > 0) && ATTRCMP(base, new)) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + i = 0; + } + if (i == 0) { +_AT_@ -1683,8 +1737,10 @@ xdrawline(Line line, int x1, int y1, int x2) + } + i++; + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); ++ if (i > 0) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); ++ } + } + + void diff --git a/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-20221120-0.9.diff b/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-20230105-0.9.diff similarity index 75% rename from st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-20221120-0.9.diff rename to st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-20230105-0.9.diff index 9a5686f8..9255c55a 100644 --- a/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-20221120-0.9.diff +++ b/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-20230105-0.9.diff _AT_@ -42,10 +42,10 @@ index 1e306f8..3e13e53 100644 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 diff --git a/hb.c b/hb.c new file mode 100644 -index 0000000..59b9200 +index 0000000..528c040 --- /dev/null +++ b/hb.c -_AT_@ -0,0 +1,107 @@ +_AT_@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <stdio.h> +#include <math.h> _AT_@ -58,6 +58,7 @@ index 0000000..59b9200 +#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); + _AT_@ -66,8 +67,19 @@ index 0000000..59b9200 + 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 }; + +/* + * Poplulate the array with a list of font features, wrapped in FEATURE macro, _AT_@ -79,45 +91,44 @@ index 0000000..59b9200 +void +hbunloadfonts() +{ -+ for (int i = 0; i < hbfontslen; i++) { -+ hb_font_destroy(hbfontcache[i].font); -+ XftUnlockFace(hbfontcache[i].match); ++ 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; + unsigned int glyph_count; -+ int i, end = start + length; ++ int rune_idx, glyph_idx, end = start + length; + + hb_font_t *font = hbfindfont(xfont); + if (font == NULL) _AT_@ -126,14 +137,20 @@ index 0000000..59b9200 + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + ++ /* 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); ++ } ++ + /* 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)); _AT_@ -142,7 +159,7 @@ index 0000000..59b9200 + 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; _AT_@ -215,7 +232,7 @@ index 6de960d..94679e4 100644 void xfinishdraw(void); void xloadcols(void); diff --git a/x.c b/x.c -index 2a3bd38..5feac09 100644 +index 2a3bd38..e66cf0c 100644 --- a/x.c +++ b/x.c _AT_@ -19,6 +19,7 @@ char *argv0; _AT_@ -234,6 +251,15 @@ index 2a3bd38..5feac09 100644 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); +_AT_@ -757,7 +759,7 @@ xresize(int col, int row) + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +- xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); ++ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4); + } + + ushort _AT_@ -1062,6 +1064,9 @@ xunloadfont(Font *f) void xunloadfonts(void) _AT_@ -244,6 +270,15 @@ index 2a3bd38..5feac09 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); +_AT_@ -1185,7 +1190,7 @@ xinit(int cols, int rows) + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ +- xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); ++ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); _AT_@ -1239,6 +1244,22 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } _AT_@ -251,7 +286,7 @@ index 2a3bd38..5feac09 100644 +void +xresetfontsettings(ushort mode, Font **font, int *frcflags) +{ -+ *font = &dc.font; ++ *font = &dc.font; + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + *font = &dc.ibfont; + *frcflags = FRC_ITALICBOLD; _AT_@ -267,12 +302,13 @@ index 2a3bd38..5feac09 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1253,119 +1274,137 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x +_AT_@ -1253,121 +1274,151 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + int i, f, length = 0, start = 0, numspecs = 0; ++ float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; + + /* Initial values. */ _AT_@ -286,7 +322,7 @@ index 2a3bd38..5feac09 100644 /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY) ++ if (mode & ATTR_WDUMMY && i < (len - 1)) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -344,23 +380,34 @@ index 2a3bd38..5feac09 100644 - break; + /* Shape the segment. */ + hbtransform(&shaped, font->match, glyphs, start, length); ++ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ cluster_xp = xp; cluster_yp = yp; + for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ rune = glyphs[start + code_idx].u; -+ runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ int idx = shaped.glyphs[code_idx].cluster; + -+ if (glyphs[start + code_idx].mode & ATTR_WDUMMY) ++ if (glyphs[start + idx].mode & ATTR_WDUMMY) + continue; + ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; ++ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ } ++ + if (shaped.glyphs[code_idx].codepoint != 0) { + /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; + specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset; -+ specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset; -+ xp += runewidth; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; + } else { + /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[start + idx].u; + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ _AT_@ -429,21 +476,17 @@ index 2a3bd38..5feac09 100644 + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; -+ xp += runewidth; + numspecs++; + } } - } - +- - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - /* - * Nothing was found in the cache. Now use _AT_@ -459,7 +502,10 @@ index 2a3bd38..5feac09 100644 - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -- ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); ++ start = i; + - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); _AT_@ -503,8 +549,11 @@ index 2a3bd38..5feac09 100644 - numspecs++; } ++ hbcleanup(&shaped); return numspecs; -_AT_@ -1517,14 +1556,17 @@ xdrawglyph(Glyph g, int x, int y) + } + +_AT_@ -1517,14 +1568,17 @@ xdrawglyph(Glyph g, int x, int y) } void _AT_@ -524,3 +573,39 @@ index 2a3bd38..5feac09 100644 if (IS_SET(MODE_HIDE)) return; +_AT_@ -1652,18 +1706,16 @@ xdrawline(Line line, int x1, int y1, int x2) + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { ++ for (x = x1; x < x2; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; ++ if ((i > 0) && ATTRCMP(base, new)) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + i = 0; + } + if (i == 0) { +_AT_@ -1672,8 +1724,10 @@ xdrawline(Line line, int x1, int y1, int x2) + } + i++; + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); ++ if (i > 0) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); ++ } + } + + void diff --git a/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-ringbuffer-20221120-0.9.diff b/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-ringbuffer-20230105-0.9.diff similarity index 74% rename from st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-ringbuffer-20221120-0.9.diff rename to st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-ringbuffer-20230105-0.9.diff index 294f511d..69652198 100644 --- a/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-ringbuffer-20221120-0.9.diff +++ b/st.suckless.org/patches/ligatures/0.9/st-ligatures-scrollback-ringbuffer-20230105-0.9.diff _AT_@ -42,10 +42,10 @@ index 1e306f8..3e13e53 100644 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 diff --git a/hb.c b/hb.c new file mode 100644 -index 0000000..59b9200 +index 0000000..528c040 --- /dev/null +++ b/hb.c -_AT_@ -0,0 +1,107 @@ +_AT_@ -0,0 +1,124 @@ +#include <stdlib.h> +#include <stdio.h> +#include <math.h> _AT_@ -58,6 +58,7 @@ index 0000000..59b9200 +#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); + _AT_@ -66,8 +67,19 @@ index 0000000..59b9200 + 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 }; + +/* + * Poplulate the array with a list of font features, wrapped in FEATURE macro, _AT_@ -79,45 +91,44 @@ index 0000000..59b9200 +void +hbunloadfonts() +{ -+ for (int i = 0; i < hbfontslen; i++) { -+ hb_font_destroy(hbfontcache[i].font); -+ XftUnlockFace(hbfontcache[i].match); ++ 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; + unsigned int glyph_count; -+ int i, end = start + length; ++ int rune_idx, glyph_idx, end = start + length; + + hb_font_t *font = hbfindfont(xfont); + if (font == NULL) _AT_@ -126,14 +137,20 @@ index 0000000..59b9200 + hb_buffer_t *buffer = hb_buffer_create(); + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); + ++ /* 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); ++ } ++ + /* 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)); _AT_@ -142,7 +159,7 @@ index 0000000..59b9200 + 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; _AT_@ -174,10 +191,10 @@ index 0000000..88de9bd +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); +void hbcleanup(HbTransformData *); diff --git a/st.c b/st.c -index 79ee9ba..7675db6 100644 +index c44797b..91f54dc 100644 --- a/st.c +++ b/st.c -_AT_@ -2762,7 +2762,8 @@ draw(void) +_AT_@ -2759,7 +2759,8 @@ draw(void) drawregion(0, 0, term.col, term.row); if (TSCREEN.off == 0) xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], _AT_@ -188,7 +205,7 @@ index 79ee9ba..7675db6 100644 term.ocy = term.c.y; xfinishdraw(); diff --git a/st.h b/st.h -index 818a6f8..4e584b6 100644 +index 3cea73b..709a369 100644 --- a/st.h +++ b/st.h _AT_@ -11,7 +11,8 @@ _AT_@ -215,7 +232,7 @@ index 6de960d..94679e4 100644 void xfinishdraw(void); void xloadcols(void); diff --git a/x.c b/x.c -index 2a3bd38..5feac09 100644 +index 9891e91..ec3567a 100644 --- a/x.c +++ b/x.c _AT_@ -19,6 +19,7 @@ char *argv0; _AT_@ -226,7 +243,7 @@ index 2a3bd38..5feac09 100644 /* types used in config.h */ typedef struct { -_AT_@ -141,6 +142,7 @@ typedef struct { +_AT_@ -143,6 +144,7 @@ typedef struct { } DC; static inline ushort sixd_to_16bit(int); _AT_@ -234,7 +251,16 @@ index 2a3bd38..5feac09 100644 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); -_AT_@ -1062,6 +1064,9 @@ xunloadfont(Font *f) +_AT_@ -759,7 +761,7 @@ xresize(int col, int row) + xclear(0, 0, win.w, win.h); + + /* resize to new width */ +- xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); ++ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4); + } + + ushort +_AT_@ -1064,6 +1066,9 @@ xunloadfont(Font *f) void xunloadfonts(void) { _AT_@ -244,14 +270,23 @@ index 2a3bd38..5feac09 100644 /* Free the loaded fonts in the font cache. */ while (frclen > 0) XftFontClose(xw.dpy, frc[--frclen].font); -_AT_@ -1239,6 +1244,22 @@ xinit(int cols, int rows) +_AT_@ -1187,7 +1192,7 @@ xinit(int cols, int rows) + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + + /* font spec buffer */ +- xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); ++ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); + + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); +_AT_@ -1241,6 +1246,22 @@ xinit(int cols, int rows) xsel.xtarget = XA_STRING; } +void +xresetfontsettings(ushort mode, Font **font, int *frcflags) +{ -+ *font = &dc.font; ++ *font = &dc.font; + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + *font = &dc.ibfont; + *frcflags = FRC_ITALICBOLD; _AT_@ -267,12 +302,13 @@ index 2a3bd38..5feac09 100644 int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) { -_AT_@ -1253,119 +1274,137 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x +_AT_@ -1255,119 +1276,148 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + int i, f, length = 0, start = 0, numspecs = 0; ++ float cluster_xp = xp, cluster_yp = yp; + HbTransformData shaped = { 0 }; + + /* Initial values. */ _AT_@ -286,7 +322,7 @@ index 2a3bd38..5feac09 100644 /* Skip dummy wide-character spacing. */ - if (mode == ATTR_WDUMMY) -+ if (mode & ATTR_WDUMMY) ++ if (mode & ATTR_WDUMMY && i < (len - 1)) continue; - /* Determine font for glyph if different from previous glyph. */ _AT_@ -344,23 +380,34 @@ index 2a3bd38..5feac09 100644 - break; + /* Shape the segment. */ + hbtransform(&shaped, font->match, glyphs, start, length); ++ runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ cluster_xp = xp; cluster_yp = yp; + for (int code_idx = 0; code_idx < shaped.count; code_idx++) { -+ rune = glyphs[start + code_idx].u; -+ runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ int idx = shaped.glyphs[code_idx].cluster; + -+ if (glyphs[start + code_idx].mode & ATTR_WDUMMY) ++ if (glyphs[start + idx].mode & ATTR_WDUMMY) + continue; + ++ /* Advance the drawing cursor if we've moved to a new cluster */ ++ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { ++ xp += runewidth; ++ cluster_xp = xp; ++ cluster_yp = yp; ++ runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); ++ } ++ + if (shaped.glyphs[code_idx].codepoint != 0) { + /* If symbol is found, put it into the specs. */ + specs[numspecs].font = font->match; + specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; -+ specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset; -+ specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset; -+ xp += runewidth; ++ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); ++ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); ++ cluster_xp += shaped.positions[code_idx].x_advance / 64.; ++ cluster_yp += shaped.positions[code_idx].y_advance / 64.; + numspecs++; + } else { + /* If it's not found, try to fetch it through the font cache. */ ++ rune = glyphs[start + idx].u; + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ _AT_@ -429,21 +476,17 @@ index 2a3bd38..5feac09 100644 + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; -+ xp += runewidth; + numspecs++; + } } - } - +- - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; -+ /* Cleanup and get ready for next segment. */ -+ hbcleanup(&shaped); -+ start = i; - /* - * Nothing was found in the cache. Now use _AT_@ -459,7 +502,10 @@ index 2a3bd38..5feac09 100644 - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); -- ++ /* Cleanup and get ready for next segment. */ ++ hbcleanup(&shaped); ++ start = i; + - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); _AT_@ -504,7 +550,7 @@ index 2a3bd38..5feac09 100644 } return numspecs; -_AT_@ -1517,14 +1556,17 @@ xdrawglyph(Glyph g, int x, int y) +_AT_@ -1519,14 +1569,17 @@ xdrawglyph(Glyph g, int x, int y) } void _AT_@ -524,3 +570,39 @@ index 2a3bd38..5feac09 100644 if (IS_SET(MODE_HIDE)) return; +_AT_@ -1654,18 +1707,16 @@ xdrawline(Line line, int x1, int y1, int x2) + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; + +- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; +- for (x = x1; x < x2 && i < numspecs; x++) { ++ for (x = x1; x < x2; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; +- if (i > 0 && ATTRCMP(base, new)) { +- xdrawglyphfontspecs(specs, base, i, ox, y1); +- specs += i; +- numspecs -= i; ++ if ((i > 0) && ATTRCMP(base, new)) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + i = 0; + } + if (i == 0) { +_AT_@ -1674,8 +1725,10 @@ xdrawline(Line line, int x1, int y1, int x2) + } + i++; + } +- if (i > 0) +- xdrawglyphfontspecs(specs, base, i, ox, y1); ++ if (i > 0) { ++ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); ++ xdrawglyphfontspecs(specs, base, numspecs, ox, y1); ++ } + } + + voidReceived on Sat Mar 04 2023 - 21:49:22 CET
This archive was generated by hypermail 2.3.0 : Sat Mar 04 2023 - 22:00:53 CET