| st-ligatures-boxdraw-20240105-0.9.diff - sites - public wiki contents of suckle… | |
| git clone git://git.suckless.org/sites | |
| Log | |
| Files | |
| Refs | |
| --- | |
| st-ligatures-boxdraw-20240105-0.9.diff (19269B) | |
| --- | |
| 1 diff --git a/Makefile b/Makefile | |
| 2 index 6dfa212..adfa07a 100644 | |
| 3 --- a/Makefile | |
| 4 +++ b/Makefile | |
| 5 @@ -4,7 +4,7 @@ | |
| 6 | |
| 7 include config.mk | |
| 8 | |
| 9 -SRC = st.c x.c boxdraw.c | |
| 10 +SRC = st.c x.c boxdraw.c hb.c | |
| 11 OBJ = $(SRC:.c=.o) | |
| 12 | |
| 13 all: options st | |
| 14 @@ -22,8 +22,9 @@ config.h: | |
| 15 $(CC) $(STCFLAGS) -c $< | |
| 16 | |
| 17 st.o: config.h st.h win.h | |
| 18 -x.o: arg.h config.h st.h win.h | |
| 19 +x.o: arg.h config.h st.h win.h hb.h | |
| 20 boxdraw.o: config.h st.h boxdraw_data.h | |
| 21 +hb.o: st.h | |
| 22 | |
| 23 $(OBJ): config.h config.mk | |
| 24 | |
| 25 diff --git a/config.mk b/config.mk | |
| 26 index 1e306f8..3e13e53 100644 | |
| 27 --- a/config.mk | |
| 28 +++ b/config.mk | |
| 29 @@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config | |
| 30 # includes and libs | |
| 31 INCS = -I$(X11INC) \ | |
| 32 `$(PKG_CONFIG) --cflags fontconfig` \ | |
| 33 - `$(PKG_CONFIG) --cflags freetype2` | |
| 34 + `$(PKG_CONFIG) --cflags freetype2` \ | |
| 35 + `$(PKG_CONFIG) --cflags harfbuzz` | |
| 36 LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ | |
| 37 `$(PKG_CONFIG) --libs fontconfig` \ | |
| 38 - `$(PKG_CONFIG) --libs freetype2` | |
| 39 + `$(PKG_CONFIG) --libs freetype2` \ | |
| 40 + `$(PKG_CONFIG) --libs harfbuzz` | |
| 41 | |
| 42 # flags | |
| 43 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 | |
| 44 diff --git a/hb.c b/hb.c | |
| 45 new file mode 100644 | |
| 46 index 0000000..99412c8 | |
| 47 --- /dev/null | |
| 48 +++ b/hb.c | |
| 49 @@ -0,0 +1,125 @@ | |
| 50 +#include <stdlib.h> | |
| 51 +#include <stdio.h> | |
| 52 +#include <math.h> | |
| 53 +#include <X11/Xft/Xft.h> | |
| 54 +#include <X11/cursorfont.h> | |
| 55 +#include <hb.h> | |
| 56 +#include <hb-ft.h> | |
| 57 + | |
| 58 +#include "st.h" | |
| 59 +#include "hb.h" | |
| 60 + | |
| 61 +#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, … | |
| 62 +#define BUFFER_STEP 256 | |
| 63 + | |
| 64 +hb_font_t *hbfindfont(XftFont *match); | |
| 65 + | |
| 66 +typedef struct { | |
| 67 + XftFont *match; | |
| 68 + hb_font_t *font; | |
| 69 +} HbFontMatch; | |
| 70 + | |
| 71 +typedef struct { | |
| 72 + size_t capacity; | |
| 73 + HbFontMatch *fonts; | |
| 74 +} HbFontCache; | |
| 75 + | |
| 76 +static HbFontCache hbfontcache = { 0, NULL }; | |
| 77 + | |
| 78 +typedef struct { | |
| 79 + size_t capacity; | |
| 80 + Rune *runes; | |
| 81 +} RuneBuffer; | |
| 82 + | |
| 83 +static RuneBuffer hbrunebuffer = { 0, NULL }; | |
| 84 + | |
| 85 +/* | |
| 86 + * Poplulate the array with a list of font features, wrapped in FEATURE… | |
| 87 + * e. g. | |
| 88 + * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g') | |
| 89 + */ | |
| 90 +hb_feature_t features[] = { }; | |
| 91 + | |
| 92 +void | |
| 93 +hbunloadfonts() | |
| 94 +{ | |
| 95 + for (int i = 0; i < hbfontcache.capacity; i++) { | |
| 96 + hb_font_destroy(hbfontcache.fonts[i].font); | |
| 97 + XftUnlockFace(hbfontcache.fonts[i].match); | |
| 98 + } | |
| 99 + | |
| 100 + if (hbfontcache.fonts != NULL) { | |
| 101 + free(hbfontcache.fonts); | |
| 102 + hbfontcache.fonts = NULL; | |
| 103 + } | |
| 104 + hbfontcache.capacity = 0; | |
| 105 +} | |
| 106 + | |
| 107 +hb_font_t * | |
| 108 +hbfindfont(XftFont *match) | |
| 109 +{ | |
| 110 + for (int i = 0; i < hbfontcache.capacity; i++) { | |
| 111 + if (hbfontcache.fonts[i].match == match) | |
| 112 + return hbfontcache.fonts[i].font; | |
| 113 + } | |
| 114 + | |
| 115 + /* Font not found in cache, caching it now. */ | |
| 116 + hbfontcache.fonts = realloc(hbfontcache.fonts, sizeof(HbFontMat… | |
| 117 + FT_Face face = XftLockFace(match); | |
| 118 + hb_font_t *font = hb_ft_font_create(face, NULL); | |
| 119 + if (font == NULL) | |
| 120 + die("Failed to load Harfbuzz font."); | |
| 121 + | |
| 122 + hbfontcache.fonts[hbfontcache.capacity].match = match; | |
| 123 + hbfontcache.fonts[hbfontcache.capacity].font = font; | |
| 124 + hbfontcache.capacity += 1; | |
| 125 + | |
| 126 + return font; | |
| 127 +} | |
| 128 + | |
| 129 +void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *gl… | |
| 130 + ushort mode = USHRT_MAX; | |
| 131 + unsigned int glyph_count; | |
| 132 + int rune_idx, glyph_idx, end = start + length; | |
| 133 + | |
| 134 + hb_font_t *font = hbfindfont(xfont); | |
| 135 + if (font == NULL) | |
| 136 + return; | |
| 137 + | |
| 138 + hb_buffer_t *buffer = hb_buffer_create(); | |
| 139 + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); | |
| 140 + hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MON… | |
| 141 + | |
| 142 + /* Resize the buffer if required length is larger. */ | |
| 143 + if (hbrunebuffer.capacity < length) { | |
| 144 + hbrunebuffer.capacity = (length / BUFFER_STEP + 1) * BU… | |
| 145 + hbrunebuffer.runes = realloc(hbrunebuffer.runes, hbrune… | |
| 146 + } | |
| 147 + | |
| 148 + /* Fill buffer with codepoints. */ | |
| 149 + for (rune_idx = 0, glyph_idx = start; glyph_idx < end; glyph_id… | |
| 150 + hbrunebuffer.runes[rune_idx] = glyphs[glyph_idx].u; | |
| 151 + mode = glyphs[glyph_idx].mode; | |
| 152 + if (mode & ATTR_WDUMMY) | |
| 153 + hbrunebuffer.runes[rune_idx] = 0x0020; | |
| 154 + } | |
| 155 + hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0,… | |
| 156 + | |
| 157 + /* Shape the segment. */ | |
| 158 + hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_fea… | |
| 159 + | |
| 160 + /* Get new glyph info. */ | |
| 161 + hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyp… | |
| 162 + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer… | |
| 163 + | |
| 164 + /* Fill the output. */ | |
| 165 + data->buffer = buffer; | |
| 166 + data->glyphs = info; | |
| 167 + data->positions = pos; | |
| 168 + data->count = glyph_count; | |
| 169 +} | |
| 170 + | |
| 171 +void hbcleanup(HbTransformData *data) { | |
| 172 + hb_buffer_destroy(data->buffer); | |
| 173 + memset(data, 0, sizeof(HbTransformData)); | |
| 174 +} | |
| 175 diff --git a/hb.h b/hb.h | |
| 176 new file mode 100644 | |
| 177 index 0000000..3b0ef44 | |
| 178 --- /dev/null | |
| 179 +++ b/hb.h | |
| 180 @@ -0,0 +1,14 @@ | |
| 181 +#include <X11/Xft/Xft.h> | |
| 182 +#include <hb.h> | |
| 183 +#include <hb-ft.h> | |
| 184 + | |
| 185 +typedef struct { | |
| 186 + hb_buffer_t *buffer; | |
| 187 + hb_glyph_info_t *glyphs; | |
| 188 + hb_glyph_position_t *positions; | |
| 189 + unsigned int count; | |
| 190 +} HbTransformData; | |
| 191 + | |
| 192 +void hbunloadfonts(); | |
| 193 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); | |
| 194 +void hbcleanup(HbTransformData *); | |
| 195 diff --git a/st.c b/st.c | |
| 196 index 41d5ace..1c2edd6 100644 | |
| 197 --- a/st.c | |
| 198 +++ b/st.c | |
| 199 @@ -2643,7 +2643,8 @@ draw(void) | |
| 200 | |
| 201 drawregion(0, 0, term.col, term.row); | |
| 202 xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], | |
| 203 - term.ocx, term.ocy, term.line[term.ocy][term.oc… | |
| 204 + term.ocx, term.ocy, term.line[term.ocy][term.oc… | |
| 205 + term.line[term.ocy], term.col); | |
| 206 term.ocx = cx; | |
| 207 term.ocy = term.c.y; | |
| 208 xfinishdraw(); | |
| 209 diff --git a/st.h b/st.h | |
| 210 index 808f5f7..ae41368 100644 | |
| 211 --- a/st.h | |
| 212 +++ b/st.h | |
| 213 @@ -11,7 +11,8 @@ | |
| 214 #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) | |
| 215 #define DEFAULT(a, b) (a) = (a) ? (a) : (b) | |
| 216 #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b)… | |
| 217 -#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg !=… | |
| 218 +#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP)) != ((b)… | |
| 219 + (a).fg != (b).fg || \ | |
| 220 (a).bg != (b).bg) | |
| 221 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ | |
| 222 (t1.tv_nsec-t2.tv_nsec)/1E6) | |
| 223 diff --git a/win.h b/win.h | |
| 224 index 6de960d..94679e4 100644 | |
| 225 --- a/win.h | |
| 226 +++ b/win.h | |
| 227 @@ -25,7 +25,7 @@ enum win_mode { | |
| 228 | |
| 229 void xbell(void); | |
| 230 void xclipcopy(void); | |
| 231 -void xdrawcursor(int, int, Glyph, int, int, Glyph); | |
| 232 +void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int); | |
| 233 void xdrawline(Line, int, int, int); | |
| 234 void xfinishdraw(void); | |
| 235 void xloadcols(void); | |
| 236 diff --git a/x.c b/x.c | |
| 237 index bf6bbf9..96b117f 100644 | |
| 238 --- a/x.c | |
| 239 +++ b/x.c | |
| 240 @@ -19,6 +19,7 @@ char *argv0; | |
| 241 #include "arg.h" | |
| 242 #include "st.h" | |
| 243 #include "win.h" | |
| 244 +#include "hb.h" | |
| 245 | |
| 246 /* types used in config.h */ | |
| 247 typedef struct { | |
| 248 @@ -141,8 +142,9 @@ typedef struct { | |
| 249 } DC; | |
| 250 | |
| 251 static inline ushort sixd_to_16bit(int); | |
| 252 +static void xresetfontsettings(ushort mode, Font **font, int *frcflags); | |
| 253 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, … | |
| 254 -static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, i… | |
| 255 +static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, i… | |
| 256 static void xdrawglyph(Glyph, int, int); | |
| 257 static void xclear(int, int, int, int); | |
| 258 static int xgeommasktogravity(int); | |
| 259 @@ -757,7 +759,7 @@ xresize(int col, int row) | |
| 260 xclear(0, 0, win.w, win.h); | |
| 261 | |
| 262 /* resize to new width */ | |
| 263 - xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); | |
| 264 + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) *… | |
| 265 } | |
| 266 | |
| 267 ushort | |
| 268 @@ -1062,6 +1064,9 @@ xunloadfont(Font *f) | |
| 269 void | |
| 270 xunloadfonts(void) | |
| 271 { | |
| 272 + /* Clear Harfbuzz font cache. */ | |
| 273 + hbunloadfonts(); | |
| 274 + | |
| 275 /* Free the loaded fonts in the font cache. */ | |
| 276 while (frclen > 0) | |
| 277 XftFontClose(xw.dpy, frc[--frclen].font); | |
| 278 @@ -1185,7 +1190,7 @@ xinit(int cols, int rows) | |
| 279 XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); | |
| 280 | |
| 281 /* font spec buffer */ | |
| 282 - xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); | |
| 283 + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); | |
| 284 | |
| 285 /* Xft rendering context */ | |
| 286 xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); | |
| 287 @@ -1241,6 +1246,22 @@ xinit(int cols, int rows) | |
| 288 boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); | |
| 289 } | |
| 290 | |
| 291 +void | |
| 292 +xresetfontsettings(ushort mode, Font **font, int *frcflags) | |
| 293 +{ | |
| 294 + *font = &dc.font; | |
| 295 + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { | |
| 296 + *font = &dc.ibfont; | |
| 297 + *frcflags = FRC_ITALICBOLD; | |
| 298 + } else if (mode & ATTR_ITALIC) { | |
| 299 + *font = &dc.ifont; | |
| 300 + *frcflags = FRC_ITALIC; | |
| 301 + } else if (mode & ATTR_BOLD) { | |
| 302 + *font = &dc.bfont; | |
| 303 + *frcflags = FRC_BOLD; | |
| 304 + } | |
| 305 +} | |
| 306 + | |
| 307 int | |
| 308 xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int l… | |
| 309 { | |
| 310 @@ -1255,133 +1276,164 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, c… | |
| 311 FcPattern *fcpattern, *fontpattern; | |
| 312 FcFontSet *fcsets[] = { NULL }; | |
| 313 FcCharSet *fccharset; | |
| 314 - int i, f, numspecs = 0; | |
| 315 + int i, f, length = 0, start = 0, numspecs = 0; | |
| 316 + float cluster_xp = xp, cluster_yp = yp; | |
| 317 + HbTransformData shaped = { 0 }; | |
| 318 + | |
| 319 + /* Initial values. */ | |
| 320 + mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; | |
| 321 + xresetfontsettings(mode, &font, &frcflags); | |
| 322 | |
| 323 for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { | |
| 324 - /* Fetch rune and mode for current glyph. */ | |
| 325 - rune = glyphs[i].u; | |
| 326 - mode = glyphs[i].mode; | |
| 327 + mode = glyphs[i].mode & ~ATTR_WRAP; | |
| 328 | |
| 329 /* Skip dummy wide-character spacing. */ | |
| 330 - if (mode == ATTR_WDUMMY) | |
| 331 + if (mode & ATTR_WDUMMY && i < (len - 1)) | |
| 332 continue; | |
| 333 | |
| 334 - /* Determine font for glyph if different from previous … | |
| 335 - if (prevmode != mode) { | |
| 336 - prevmode = mode; | |
| 337 - font = &dc.font; | |
| 338 - frcflags = FRC_NORMAL; | |
| 339 - runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f… | |
| 340 - if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD))… | |
| 341 - font = &dc.ibfont; | |
| 342 - frcflags = FRC_ITALICBOLD; | |
| 343 - } else if (mode & ATTR_ITALIC) { | |
| 344 - font = &dc.ifont; | |
| 345 - frcflags = FRC_ITALIC; | |
| 346 - } else if (mode & ATTR_BOLD) { | |
| 347 - font = &dc.bfont; | |
| 348 - frcflags = FRC_BOLD; | |
| 349 + if ( | |
| 350 + prevmode != mode | |
| 351 + || ATTRCMP(glyphs[start], glyphs[i]) | |
| 352 + || selected(x + i, y) != selected(x + start, y) | |
| 353 + || i == (len - 1) | |
| 354 + ) { | |
| 355 + /* Handle 1-character wide segments and end of … | |
| 356 + length = i - start; | |
| 357 + if (i == start) { | |
| 358 + length = 1; | |
| 359 + } else if (i == (len - 1)) { | |
| 360 + length = (i - start + 1); | |
| 361 } | |
| 362 - yp = winy + font->ascent; | |
| 363 - } | |
| 364 | |
| 365 - if (mode & ATTR_BOXDRAW) { | |
| 366 - /* minor shoehorning: boxdraw uses only this us… | |
| 367 - glyphidx = boxdrawindex(&glyphs[i]); | |
| 368 - } else { | |
| 369 - /* Lookup character index with default font. */ | |
| 370 - glyphidx = XftCharIndex(xw.dpy, font->match, ru… | |
| 371 - } | |
| 372 - if (glyphidx) { | |
| 373 - specs[numspecs].font = font->match; | |
| 374 - specs[numspecs].glyph = glyphidx; | |
| 375 - specs[numspecs].x = (short)xp; | |
| 376 - specs[numspecs].y = (short)yp; | |
| 377 - xp += runewidth; | |
| 378 - numspecs++; | |
| 379 - continue; | |
| 380 - } | |
| 381 - | |
| 382 - /* Fallback on font cache, search the font cache for ma… | |
| 383 - for (f = 0; f < frclen; f++) { | |
| 384 - glyphidx = XftCharIndex(xw.dpy, frc[f].font, ru… | |
| 385 - /* Everything correct. */ | |
| 386 - if (glyphidx && frc[f].flags == frcflags) | |
| 387 - break; | |
| 388 - /* We got a default font for a not found glyph.… | |
| 389 - if (!glyphidx && frc[f].flags == frcflags | |
| 390 - && frc[f].unicodep == rune) { | |
| 391 - break; | |
| 392 + /* Shape the segment. */ | |
| 393 + hbtransform(&shaped, font->match, glyphs, start… | |
| 394 + runewidth = win.cw * ((glyphs[start].mode & ATT… | |
| 395 + cluster_xp = xp; cluster_yp = yp; | |
| 396 + for (int code_idx = 0; code_idx < shaped.count;… | |
| 397 + int idx = shaped.glyphs[code_idx].clust… | |
| 398 + | |
| 399 + if (glyphs[start + idx].mode & ATTR_WDU… | |
| 400 + continue; | |
| 401 + | |
| 402 + /* Advance the drawing cursor if we've … | |
| 403 + if (code_idx > 0 && idx != shaped.glyph… | |
| 404 + xp += runewidth; | |
| 405 + cluster_xp = xp; | |
| 406 + cluster_yp = yp; | |
| 407 + runewidth = win.cw * ((glyphs[s… | |
| 408 + } | |
| 409 + | |
| 410 + if (glyphs[start + idx].mode & ATTR_BOX… | |
| 411 + /* minor shoehorning: boxdraw u… | |
| 412 + specs[numspecs].font = font->ma… | |
| 413 + specs[numspecs].glyph = boxdraw… | |
| 414 + specs[numspecs].x = xp; | |
| 415 + specs[numspecs].y = yp; | |
| 416 + numspecs++; | |
| 417 + } else if (shaped.glyphs[code_idx].code… | |
| 418 + /* If symbol is found, put it i… | |
| 419 + specs[numspecs].font = font->ma… | |
| 420 + specs[numspecs].glyph = shaped.… | |
| 421 + specs[numspecs].x = cluster_xp … | |
| 422 + specs[numspecs].y = cluster_yp … | |
| 423 + cluster_xp += shaped.positions[… | |
| 424 + cluster_yp += shaped.positions[… | |
| 425 + numspecs++; | |
| 426 + } else { | |
| 427 + /* If it's not found, try to fe… | |
| 428 + rune = glyphs[start + idx].u; | |
| 429 + for (f = 0; f < frclen; f++) { | |
| 430 + glyphidx = XftCharIndex… | |
| 431 + /* Everything correct. … | |
| 432 + if (glyphidx && frc[f].… | |
| 433 + break; | |
| 434 + /* We got a default fon… | |
| 435 + if (!glyphidx && frc[f]… | |
| 436 + && frc[… | |
| 437 + break; | |
| 438 + } | |
| 439 + } | |
| 440 + | |
| 441 + /* Nothing was found. Use fontc… | |
| 442 + if (f >= frclen) { | |
| 443 + if (!font->set) | |
| 444 + font->set = FcF… | |
| 445 + … | |
| 446 + fcsets[0] = font->set; | |
| 447 + | |
| 448 + /* | |
| 449 + * Nothing was found in… | |
| 450 + * some dozen of Fontco… | |
| 451 + * font for one single … | |
| 452 + * | |
| 453 + * Xft and fontconfig a… | |
| 454 + */ | |
| 455 + fcpattern = FcPatternDu… | |
| 456 + fccharset = FcCharSetCr… | |
| 457 + | |
| 458 + FcCharSetAddChar(fcchar… | |
| 459 + FcPatternAddCharSet(fcp… | |
| 460 + fcchars… | |
| 461 + FcPatternAddBool(fcpatt… | |
| 462 + | |
| 463 + FcConfigSubstitute(0, f… | |
| 464 + FcMatch… | |
| 465 + FcDefaultSubstitute(fcp… | |
| 466 + | |
| 467 + fontpattern = FcFontSet… | |
| 468 + fcpatte… | |
| 469 + | |
| 470 + /* Allocate memory for … | |
| 471 + if (frclen >= frccap) { | |
| 472 + frccap += 16; | |
| 473 + frc = xrealloc(… | |
| 474 + } | |
| 475 + | |
| 476 + frc[frclen].font = XftF… | |
| 477 + fontpat… | |
| 478 + if (!frc[frclen].font) | |
| 479 + die("XftFontOpe… | |
| 480 + strerro… | |
| 481 + frc[frclen].flags = frc… | |
| 482 + frc[frclen].unicodep = … | |
| 483 + | |
| 484 + glyphidx = XftCharIndex… | |
| 485 + | |
| 486 + f = frclen; | |
| 487 + frclen++; | |
| 488 + | |
| 489 + FcPatternDestroy(fcpatt… | |
| 490 + FcCharSetDestroy(fcchar… | |
| 491 + } | |
| 492 + | |
| 493 + specs[numspecs].font = frc[f].f… | |
| 494 + specs[numspecs].glyph = glyphid… | |
| 495 + specs[numspecs].x = (short)xp; | |
| 496 + specs[numspecs].y = (short)yp; | |
| 497 + numspecs++; | |
| 498 + } | |
| 499 } | |
| 500 - } | |
| 501 | |
| 502 - /* Nothing was found. Use fontconfig to find matching f… | |
| 503 - if (f >= frclen) { | |
| 504 - if (!font->set) | |
| 505 - font->set = FcFontSort(0, font->pattern, | |
| 506 - 1, 0, &fcres); | |
| 507 - fcsets[0] = font->set; | |
| 508 + /* Cleanup and get ready for next segment. */ | |
| 509 + hbcleanup(&shaped); | |
| 510 + start = i; | |
| 511 | |
| 512 - /* | |
| 513 - * Nothing was found in the cache. Now use | |
| 514 - * some dozen of Fontconfig calls to get the | |
| 515 - * font for one single character. | |
| 516 - * | |
| 517 - * Xft and fontconfig are design failures. | |
| 518 - */ | |
| 519 - fcpattern = FcPatternDuplicate(font->pattern); | |
| 520 - fccharset = FcCharSetCreate(); | |
| 521 - | |
| 522 - FcCharSetAddChar(fccharset, rune); | |
| 523 - FcPatternAddCharSet(fcpattern, FC_CHARSET, | |
| 524 - fccharset); | |
| 525 - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); | |
| 526 - | |
| 527 - FcConfigSubstitute(0, fcpattern, | |
| 528 - FcMatchPattern); | |
| 529 - FcDefaultSubstitute(fcpattern); | |
| 530 - | |
| 531 - fontpattern = FcFontSetMatch(0, fcsets, 1, | |
| 532 - fcpattern, &fcres); | |
| 533 - | |
| 534 - /* Allocate memory for the new cache entry. */ | |
| 535 - if (frclen >= frccap) { | |
| 536 - frccap += 16; | |
| 537 - frc = xrealloc(frc, frccap * sizeof(Fon… | |
| 538 + /* Determine font for glyph if different from p… | |
| 539 + if (prevmode != mode) { | |
| 540 + prevmode = mode; | |
| 541 + xresetfontsettings(mode, &font, &frcfla… | |
| 542 + yp = winy + font->ascent; | |
| 543 } | |
| 544 - | |
| 545 - frc[frclen].font = XftFontOpenPattern(xw.dpy, | |
| 546 - fontpattern); | |
| 547 - if (!frc[frclen].font) | |
| 548 - die("XftFontOpenPattern failed seeking … | |
| 549 - strerror(errno)); | |
| 550 - frc[frclen].flags = frcflags; | |
| 551 - frc[frclen].unicodep = rune; | |
| 552 - | |
| 553 - glyphidx = XftCharIndex(xw.dpy, frc[frclen].fon… | |
| 554 - | |
| 555 - f = frclen; | |
| 556 - frclen++; | |
| 557 - | |
| 558 - FcPatternDestroy(fcpattern); | |
| 559 - FcCharSetDestroy(fccharset); | |
| 560 } | |
| 561 - | |
| 562 - specs[numspecs].font = frc[f].font; | |
| 563 - specs[numspecs].glyph = glyphidx; | |
| 564 - specs[numspecs].x = (short)xp; | |
| 565 - specs[numspecs].y = (short)yp; | |
| 566 - xp += runewidth; | |
| 567 - numspecs++; | |
| 568 } | |
| 569 | |
| 570 + hbcleanup(&shaped); | |
| 571 return numspecs; | |
| 572 } | |
| 573 | |
| 574 void | |
| 575 -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len,… | |
| 576 +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len,… | |
| 577 { | |
| 578 - int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); | |
| 579 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, | |
| 580 width = charlen * win.cw; | |
| 581 Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; | |
| 582 @@ -1521,21 +1573,24 @@ void | |
| 583 xdrawglyph(Glyph g, int x, int y) | |
| 584 { | |
| 585 int numspecs; | |
| 586 - XftGlyphFontSpec spec; | |
| 587 + XftGlyphFontSpec *specs = xw.specbuf; | |
| 588 | |
| 589 - numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); | |
| 590 - xdrawglyphfontspecs(&spec, g, numspecs, x, y); | |
| 591 + numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y); | |
| 592 + xdrawglyphfontspecs(specs, g, numspecs, x, y, (g.mode & ATTR_WI… | |
| 593 } | |
| 594 | |
| 595 void | |
| 596 -xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) | |
| 597 +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line lin… | |
| 598 { | |
| 599 Color drawcol; | |
| 600 | |
| 601 /* remove the old cursor */ | |
| 602 if (selected(ox, oy)) | |
| 603 og.mode ^= ATTR_REVERSE; | |
| 604 - xdrawglyph(og, ox, oy); | |
| 605 + | |
| 606 + /* Redraw the line where cursor was previously. | |
| 607 + * It will restore the ligatures broken by the cursor. */ | |
| 608 + xdrawline(line, 0, oy, len); | |
| 609 | |
| 610 if (IS_SET(MODE_HIDE)) | |
| 611 return; | |
| 612 @@ -1663,18 +1718,16 @@ xdrawline(Line line, int x1, int y1, int x2) | |
| 613 Glyph base, new; | |
| 614 XftGlyphFontSpec *specs = xw.specbuf; | |
| 615 | |
| 616 - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y… | |
| 617 i = ox = 0; | |
| 618 - for (x = x1; x < x2 && i < numspecs; x++) { | |
| 619 + for (x = x1; x < x2; x++) { | |
| 620 new = line[x]; | |
| 621 if (new.mode == ATTR_WDUMMY) | |
| 622 continue; | |
| 623 if (selected(x, y1)) | |
| 624 new.mode ^= ATTR_REVERSE; | |
| 625 - if (i > 0 && ATTRCMP(base, new)) { | |
| 626 - xdrawglyphfontspecs(specs, base, i, ox, y1); | |
| 627 - specs += i; | |
| 628 - numspecs -= i; | |
| 629 + if ((i > 0) && ATTRCMP(base, new)) { | |
| 630 + numspecs = xmakeglyphfontspecs(specs, &line[ox]… | |
| 631 + xdrawglyphfontspecs(specs, base, numspecs, ox, … | |
| 632 i = 0; | |
| 633 } | |
| 634 if (i == 0) { | |
| 635 @@ -1683,8 +1736,10 @@ xdrawline(Line line, int x1, int y1, int x2) | |
| 636 } | |
| 637 i++; | |
| 638 } | |
| 639 - if (i > 0) | |
| 640 - xdrawglyphfontspecs(specs, base, i, ox, y1); | |
| 641 + if (i > 0) { | |
| 642 + numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - o… | |
| 643 + xdrawglyphfontspecs(specs, base, numspecs, ox, y1, x2 -… | |
| 644 + } | |
| 645 } | |
| 646 | |
| 647 void |