st-ligatures-alpha-scrollback-ringbuffer-20240105-0.9.diff - sites - public wik… | |
git clone git://git.suckless.org/sites | |
Log | |
Files | |
Refs | |
--- | |
st-ligatures-alpha-scrollback-ringbuffer-20240105-0.9.diff (18790B) | |
--- | |
1 diff --git a/Makefile b/Makefile | |
2 index 470ac86..38240da 100644 | |
3 --- a/Makefile | |
4 +++ b/Makefile | |
5 @@ -4,7 +4,7 @@ | |
6 | |
7 include config.mk | |
8 | |
9 -SRC = st.c x.c | |
10 +SRC = st.c x.c hb.c | |
11 OBJ = $(SRC:.c=.o) | |
12 | |
13 all: options st | |
14 @@ -22,7 +22,8 @@ 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 +hb.o: st.h | |
21 | |
22 $(OBJ): config.h config.mk | |
23 | |
24 diff --git a/config.mk b/config.mk | |
25 index 47c615e..d7439a3 100644 | |
26 --- a/config.mk | |
27 +++ b/config.mk | |
28 @@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config | |
29 # includes and libs | |
30 INCS = -I$(X11INC) \ | |
31 `$(PKG_CONFIG) --cflags fontconfig` \ | |
32 - `$(PKG_CONFIG) --cflags freetype2` | |
33 -LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ | |
34 + `$(PKG_CONFIG) --cflags freetype2` \ | |
35 + `$(PKG_CONFIG) --cflags harfbuzz` | |
36 +LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \ | |
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 c44797b..18aa1bf 100644 | |
197 --- a/st.c | |
198 +++ b/st.c | |
199 @@ -2759,7 +2759,9 @@ draw(void) | |
200 drawregion(0, 0, term.col, term.row); | |
201 if (TSCREEN.off == 0) | |
202 xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], | |
203 - term.ocx, term.ocy, TLINE(term.ocy)[ter… | |
204 + term.ocx, term.ocy, TLINE(term.ocy)[ter… | |
205 + TLINE(term.ocy), term.col); | |
206 + | |
207 term.ocx = cx; | |
208 term.ocy = term.c.y; | |
209 xfinishdraw(); | |
210 diff --git a/st.h b/st.h | |
211 index 073851a..d0b071d 100644 | |
212 --- a/st.h | |
213 +++ b/st.h | |
214 @@ -11,7 +11,8 @@ | |
215 #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) | |
216 #define DEFAULT(a, b) (a) = (a) ? (a) : (b) | |
217 #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b)… | |
218 -#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg !=… | |
219 +#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP)) != ((b)… | |
220 + (a).fg != (b).fg || \ | |
221 (a).bg != (b).bg) | |
222 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ | |
223 (t1.tv_nsec-t2.tv_nsec)/1E6) | |
224 diff --git a/win.h b/win.h | |
225 index 6de960d..94679e4 100644 | |
226 --- a/win.h | |
227 +++ b/win.h | |
228 @@ -25,7 +25,7 @@ enum win_mode { | |
229 | |
230 void xbell(void); | |
231 void xclipcopy(void); | |
232 -void xdrawcursor(int, int, Glyph, int, int, Glyph); | |
233 +void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int); | |
234 void xdrawline(Line, int, int, int); | |
235 void xfinishdraw(void); | |
236 void xloadcols(void); | |
237 diff --git a/x.c b/x.c | |
238 index b81f5be..c1611bb 100644 | |
239 --- a/x.c | |
240 +++ b/x.c | |
241 @@ -19,6 +19,7 @@ char *argv0; | |
242 #include "arg.h" | |
243 #include "st.h" | |
244 #include "win.h" | |
245 +#include "hb.h" | |
246 | |
247 /* types used in config.h */ | |
248 typedef struct { | |
249 @@ -144,8 +145,9 @@ typedef struct { | |
250 } DC; | |
251 | |
252 static inline ushort sixd_to_16bit(int); | |
253 +static void xresetfontsettings(ushort mode, Font **font, int *frcflags); | |
254 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, … | |
255 -static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, i… | |
256 +static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, i… | |
257 static void xdrawglyph(Glyph, int, int); | |
258 static void xclear(int, int, int, int); | |
259 static int xgeommasktogravity(int); | |
260 @@ -761,7 +763,7 @@ xresize(int col, int row) | |
261 xclear(0, 0, win.w, win.h); | |
262 | |
263 /* resize to new width */ | |
264 - xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); | |
265 + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) *… | |
266 } | |
267 | |
268 ushort | |
269 @@ -1073,6 +1075,9 @@ xunloadfont(Font *f) | |
270 void | |
271 xunloadfonts(void) | |
272 { | |
273 + /* Clear Harfbuzz font cache. */ | |
274 + hbunloadfonts(); | |
275 + | |
276 /* Free the loaded fonts in the font cache. */ | |
277 while (frclen > 0) | |
278 XftFontClose(xw.dpy, frc[--frclen].font); | |
279 @@ -1204,7 +1209,7 @@ xinit(int cols, int rows) | |
280 XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); | |
281 | |
282 /* font spec buffer */ | |
283 - xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); | |
284 + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); | |
285 | |
286 /* Xft rendering context */ | |
287 xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); | |
288 @@ -1258,6 +1263,22 @@ xinit(int cols, int rows) | |
289 xsel.xtarget = XA_STRING; | |
290 } | |
291 | |
292 +void | |
293 +xresetfontsettings(ushort mode, Font **font, int *frcflags) | |
294 +{ | |
295 + *font = &dc.font; | |
296 + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { | |
297 + *font = &dc.ibfont; | |
298 + *frcflags = FRC_ITALICBOLD; | |
299 + } else if (mode & ATTR_ITALIC) { | |
300 + *font = &dc.ifont; | |
301 + *frcflags = FRC_ITALIC; | |
302 + } else if (mode & ATTR_BOLD) { | |
303 + *font = &dc.bfont; | |
304 + *frcflags = FRC_BOLD; | |
305 + } | |
306 +} | |
307 + | |
308 int | |
309 xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int l… | |
310 { | |
311 @@ -1272,128 +1293,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, c… | |
312 FcPattern *fcpattern, *fontpattern; | |
313 FcFontSet *fcsets[] = { NULL }; | |
314 FcCharSet *fccharset; | |
315 - int i, f, numspecs = 0; | |
316 + int i, f, length = 0, start = 0, numspecs = 0; | |
317 + float cluster_xp = xp, cluster_yp = yp; | |
318 + HbTransformData shaped = { 0 }; | |
319 + | |
320 + /* Initial values. */ | |
321 + mode = prevmode = glyphs[0].mode & ~ATTR_WRAP; | |
322 + xresetfontsettings(mode, &font, &frcflags); | |
323 | |
324 for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { | |
325 - /* Fetch rune and mode for current glyph. */ | |
326 - rune = glyphs[i].u; | |
327 - mode = glyphs[i].mode; | |
328 + mode = glyphs[i].mode & ~ATTR_WRAP; | |
329 | |
330 /* Skip dummy wide-character spacing. */ | |
331 - if (mode == ATTR_WDUMMY) | |
332 + if (mode & ATTR_WDUMMY && i < (len - 1)) | |
333 continue; | |
334 | |
335 - /* Determine font for glyph if different from previous … | |
336 - if (prevmode != mode) { | |
337 - prevmode = mode; | |
338 - font = &dc.font; | |
339 - frcflags = FRC_NORMAL; | |
340 - runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f… | |
341 - if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD))… | |
342 - font = &dc.ibfont; | |
343 - frcflags = FRC_ITALICBOLD; | |
344 - } else if (mode & ATTR_ITALIC) { | |
345 - font = &dc.ifont; | |
346 - frcflags = FRC_ITALIC; | |
347 - } else if (mode & ATTR_BOLD) { | |
348 - font = &dc.bfont; | |
349 - frcflags = FRC_BOLD; | |
350 + if ( | |
351 + prevmode != mode | |
352 + || ATTRCMP(glyphs[start], glyphs[i]) | |
353 + || selected(x + i, y) != selected(x + start, y) | |
354 + || i == (len - 1) | |
355 + ) { | |
356 + /* Handle 1-character wide segments and end of … | |
357 + length = i - start; | |
358 + if (i == start) { | |
359 + length = 1; | |
360 + } else if (i == (len - 1)) { | |
361 + length = (i - start + 1); | |
362 } | |
363 - yp = winy + font->ascent; | |
364 - } | |
365 | |
366 - /* Lookup character index with default font. */ | |
367 - glyphidx = XftCharIndex(xw.dpy, font->match, rune); | |
368 - if (glyphidx) { | |
369 - specs[numspecs].font = font->match; | |
370 - specs[numspecs].glyph = glyphidx; | |
371 - specs[numspecs].x = (short)xp; | |
372 - specs[numspecs].y = (short)yp; | |
373 - xp += runewidth; | |
374 - numspecs++; | |
375 - continue; | |
376 - } | |
377 - | |
378 - /* Fallback on font cache, search the font cache for ma… | |
379 - for (f = 0; f < frclen; f++) { | |
380 - glyphidx = XftCharIndex(xw.dpy, frc[f].font, ru… | |
381 - /* Everything correct. */ | |
382 - if (glyphidx && frc[f].flags == frcflags) | |
383 - break; | |
384 - /* We got a default font for a not found glyph.… | |
385 - if (!glyphidx && frc[f].flags == frcflags | |
386 - && frc[f].unicodep == rune) { | |
387 - break; | |
388 + /* Shape the segment. */ | |
389 + hbtransform(&shaped, font->match, glyphs, start… | |
390 + runewidth = win.cw * ((glyphs[start].mode & ATT… | |
391 + cluster_xp = xp; cluster_yp = yp; | |
392 + for (int code_idx = 0; code_idx < shaped.count;… | |
393 + int idx = shaped.glyphs[code_idx].clust… | |
394 + | |
395 + if (glyphs[start + idx].mode & ATTR_WDU… | |
396 + continue; | |
397 + | |
398 + /* Advance the drawing cursor if we've … | |
399 + if (code_idx > 0 && idx != shaped.glyph… | |
400 + xp += runewidth; | |
401 + cluster_xp = xp; | |
402 + cluster_yp = yp; | |
403 + runewidth = win.cw * ((glyphs[s… | |
404 + } | |
405 + | |
406 + if (shaped.glyphs[code_idx].codepoint !… | |
407 + /* If symbol is found, put it i… | |
408 + specs[numspecs].font = font->ma… | |
409 + specs[numspecs].glyph = shaped.… | |
410 + specs[numspecs].x = cluster_xp … | |
411 + specs[numspecs].y = cluster_yp … | |
412 + cluster_xp += shaped.positions[… | |
413 + cluster_yp += shaped.positions[… | |
414 + numspecs++; | |
415 + } else { | |
416 + /* If it's not found, try to fe… | |
417 + rune = glyphs[start + idx].u; | |
418 + for (f = 0; f < frclen; f++) { | |
419 + glyphidx = XftCharIndex… | |
420 + /* Everything correct. … | |
421 + if (glyphidx && frc[f].… | |
422 + break; | |
423 + /* We got a default fon… | |
424 + if (!glyphidx && frc[f]… | |
425 + && frc[… | |
426 + break; | |
427 + } | |
428 + } | |
429 + | |
430 + /* Nothing was found. Use fontc… | |
431 + if (f >= frclen) { | |
432 + if (!font->set) | |
433 + font->set = FcF… | |
434 + … | |
435 + fcsets[0] = font->set; | |
436 + | |
437 + /* | |
438 + * Nothing was found in… | |
439 + * some dozen of Fontco… | |
440 + * font for one single … | |
441 + * | |
442 + * Xft and fontconfig a… | |
443 + */ | |
444 + fcpattern = FcPatternDu… | |
445 + fccharset = FcCharSetCr… | |
446 + | |
447 + FcCharSetAddChar(fcchar… | |
448 + FcPatternAddCharSet(fcp… | |
449 + fcchars… | |
450 + FcPatternAddBool(fcpatt… | |
451 + | |
452 + FcConfigSubstitute(0, f… | |
453 + FcMatch… | |
454 + FcDefaultSubstitute(fcp… | |
455 + | |
456 + fontpattern = FcFontSet… | |
457 + fcpatte… | |
458 + | |
459 + /* Allocate memory for … | |
460 + if (frclen >= frccap) { | |
461 + frccap += 16; | |
462 + frc = xrealloc(… | |
463 + } | |
464 + | |
465 + frc[frclen].font = XftF… | |
466 + fontpat… | |
467 + if (!frc[frclen].font) | |
468 + die("XftFontOpe… | |
469 + strerro… | |
470 + frc[frclen].flags = frc… | |
471 + frc[frclen].unicodep = … | |
472 + | |
473 + glyphidx = XftCharIndex… | |
474 + | |
475 + f = frclen; | |
476 + frclen++; | |
477 + | |
478 + FcPatternDestroy(fcpatt… | |
479 + FcCharSetDestroy(fcchar… | |
480 + } | |
481 + | |
482 + specs[numspecs].font = frc[f].f… | |
483 + specs[numspecs].glyph = glyphid… | |
484 + specs[numspecs].x = (short)xp; | |
485 + specs[numspecs].y = (short)yp; | |
486 + numspecs++; | |
487 + } | |
488 } | |
489 - } | |
490 | |
491 - /* Nothing was found. Use fontconfig to find matching f… | |
492 - if (f >= frclen) { | |
493 - if (!font->set) | |
494 - font->set = FcFontSort(0, font->pattern, | |
495 - 1, 0, &fcres); | |
496 - fcsets[0] = font->set; | |
497 + /* Cleanup and get ready for next segment. */ | |
498 + hbcleanup(&shaped); | |
499 + start = i; | |
500 | |
501 - /* | |
502 - * Nothing was found in the cache. Now use | |
503 - * some dozen of Fontconfig calls to get the | |
504 - * font for one single character. | |
505 - * | |
506 - * Xft and fontconfig are design failures. | |
507 - */ | |
508 - fcpattern = FcPatternDuplicate(font->pattern); | |
509 - fccharset = FcCharSetCreate(); | |
510 - | |
511 - FcCharSetAddChar(fccharset, rune); | |
512 - FcPatternAddCharSet(fcpattern, FC_CHARSET, | |
513 - fccharset); | |
514 - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); | |
515 - | |
516 - FcConfigSubstitute(0, fcpattern, | |
517 - FcMatchPattern); | |
518 - FcDefaultSubstitute(fcpattern); | |
519 - | |
520 - fontpattern = FcFontSetMatch(0, fcsets, 1, | |
521 - fcpattern, &fcres); | |
522 - | |
523 - /* Allocate memory for the new cache entry. */ | |
524 - if (frclen >= frccap) { | |
525 - frccap += 16; | |
526 - frc = xrealloc(frc, frccap * sizeof(Fon… | |
527 + /* Determine font for glyph if different from p… | |
528 + if (prevmode != mode) { | |
529 + prevmode = mode; | |
530 + xresetfontsettings(mode, &font, &frcfla… | |
531 + yp = winy + font->ascent; | |
532 } | |
533 - | |
534 - frc[frclen].font = XftFontOpenPattern(xw.dpy, | |
535 - fontpattern); | |
536 - if (!frc[frclen].font) | |
537 - die("XftFontOpenPattern failed seeking … | |
538 - strerror(errno)); | |
539 - frc[frclen].flags = frcflags; | |
540 - frc[frclen].unicodep = rune; | |
541 - | |
542 - glyphidx = XftCharIndex(xw.dpy, frc[frclen].fon… | |
543 - | |
544 - f = frclen; | |
545 - frclen++; | |
546 - | |
547 - FcPatternDestroy(fcpattern); | |
548 - FcCharSetDestroy(fccharset); | |
549 } | |
550 - | |
551 - specs[numspecs].font = frc[f].font; | |
552 - specs[numspecs].glyph = glyphidx; | |
553 - specs[numspecs].x = (short)xp; | |
554 - specs[numspecs].y = (short)yp; | |
555 - xp += runewidth; | |
556 - numspecs++; | |
557 } | |
558 | |
559 return numspecs; | |
560 } | |
561 | |
562 void | |
563 -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len,… | |
564 +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len,… | |
565 { | |
566 - int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); | |
567 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, | |
568 width = charlen * win.cw; | |
569 Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; | |
570 @@ -1529,21 +1578,24 @@ void | |
571 xdrawglyph(Glyph g, int x, int y) | |
572 { | |
573 int numspecs; | |
574 - XftGlyphFontSpec spec; | |
575 + XftGlyphFontSpec *specs = xw.specbuf; | |
576 | |
577 - numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); | |
578 - xdrawglyphfontspecs(&spec, g, numspecs, x, y); | |
579 + numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y); | |
580 + xdrawglyphfontspecs(specs, g, numspecs, x, y, (g.mode & ATTR_WI… | |
581 } | |
582 | |
583 void | |
584 -xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) | |
585 +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line lin… | |
586 { | |
587 Color drawcol; | |
588 | |
589 /* remove the old cursor */ | |
590 if (selected(ox, oy)) | |
591 og.mode ^= ATTR_REVERSE; | |
592 - xdrawglyph(og, ox, oy); | |
593 + | |
594 + /* Redraw the line where cursor was previously. | |
595 + * It will restore the ligatures broken by the cursor. */ | |
596 + xdrawline(line, 0, oy, len); | |
597 | |
598 if (IS_SET(MODE_HIDE)) | |
599 return; | |
600 @@ -1671,18 +1723,16 @@ xdrawline(Line line, int x1, int y1, int x2) | |
601 Glyph base, new; | |
602 XftGlyphFontSpec *specs = xw.specbuf; | |
603 | |
604 - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y… | |
605 i = ox = 0; | |
606 - for (x = x1; x < x2 && i < numspecs; x++) { | |
607 + for (x = x1; x < x2; x++) { | |
608 new = line[x]; | |
609 if (new.mode == ATTR_WDUMMY) | |
610 continue; | |
611 if (selected(x, y1)) | |
612 new.mode ^= ATTR_REVERSE; | |
613 - if (i > 0 && ATTRCMP(base, new)) { | |
614 - xdrawglyphfontspecs(specs, base, i, ox, y1); | |
615 - specs += i; | |
616 - numspecs -= i; | |
617 + if ((i > 0) && ATTRCMP(base, new)) { | |
618 + numspecs = xmakeglyphfontspecs(specs, &line[ox]… | |
619 + xdrawglyphfontspecs(specs, base, numspecs, ox, … | |
620 i = 0; | |
621 } | |
622 if (i == 0) { | |
623 @@ -1691,8 +1741,10 @@ xdrawline(Line line, int x1, int y1, int x2) | |
624 } | |
625 i++; | |
626 } | |
627 - if (i > 0) | |
628 - xdrawglyphfontspecs(specs, base, i, ox, y1); | |
629 + if (i > 0) { | |
630 + numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - o… | |
631 + xdrawglyphfontspecs(specs, base, numspecs, ox, y1, x2 -… | |
632 + } | |
633 } | |
634 | |
635 void |