Introduction
Introduction Statistics Contact Development Disclaimer Help
st-ligatures-20210824-0.8.4.diff - sites - public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log
Files
Refs
---
st-ligatures-20210824-0.8.4.diff (8255B)
---
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 c070a4a..3d236f0 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 + `$(PKG_CONFIG) --cflags freetype2` \
34 + `$(PKG_CONFIG) --cflags harfbuzz`
35 LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
36 `$(PKG_CONFIG) --libs fontconfig` \
37 - `$(PKG_CONFIG) --libs freetype2`
38 + `$(PKG_CONFIG) --libs freetype2` \
39 + `$(PKG_CONFIG) --libs harfbuzz`
40
41 # flags
42 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
43 diff --git a/hb.c b/hb.c
44 new file mode 100644
45 index 0000000..6389e95
46 --- /dev/null
47 +++ b/hb.c
48 @@ -0,0 +1,146 @@
49 +#include <stdlib.h>
50 +#include <stdio.h>
51 +#include <math.h>
52 +#include <X11/Xft/Xft.h>
53 +#include <X11/cursorfont.h>
54 +#include <hb.h>
55 +#include <hb-ft.h>
56 +
57 +#include "st.h"
58 +
59 +#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, …
60 +
61 +void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoi…
62 +hb_font_t *hbfindfont(XftFont *match);
63 +
64 +typedef struct {
65 + XftFont *match;
66 + hb_font_t *font;
67 +} HbFontMatch;
68 +
69 +static int hbfontslen = 0;
70 +static HbFontMatch *hbfontcache = NULL;
71 +
72 +/*
73 + * Poplulate the array with a list of font features, wrapped in FEATURE…
74 + * e. g.
75 + * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
76 + */
77 +hb_feature_t features[] = { };
78 +
79 +void
80 +hbunloadfonts()
81 +{
82 + for (int i = 0; i < hbfontslen; i++) {
83 + hb_font_destroy(hbfontcache[i].font);
84 + XftUnlockFace(hbfontcache[i].match);
85 + }
86 +
87 + if (hbfontcache != NULL) {
88 + free(hbfontcache);
89 + hbfontcache = NULL;
90 + }
91 + hbfontslen = 0;
92 +}
93 +
94 +hb_font_t *
95 +hbfindfont(XftFont *match)
96 +{
97 + for (int i = 0; i < hbfontslen; i++) {
98 + if (hbfontcache[i].match == match)
99 + return hbfontcache[i].font;
100 + }
101 +
102 + /* Font not found in cache, caching it now. */
103 + hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfon…
104 + FT_Face face = XftLockFace(match);
105 + hb_font_t *font = hb_ft_font_create(face, NULL);
106 + if (font == NULL)
107 + die("Failed to load Harfbuzz font.");
108 +
109 + hbfontcache[hbfontslen].match = match;
110 + hbfontcache[hbfontslen].font = font;
111 + hbfontslen += 1;
112 +
113 + return font;
114 +}
115 +
116 +void
117 +hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, i…
118 +{
119 + int start = 0, length = 1, gstart = 0;
120 + hb_codepoint_t *codepoints = calloc((unsigned int)len, sizeof(h…
121 +
122 + for (int idx = 1, specidx = 1; idx < len; idx++) {
123 + if (glyphs[idx].mode & ATTR_WDUMMY) {
124 + length += 1;
125 + continue;
126 + }
127 +
128 + if (specs[specidx].font != specs[start].font || ATTRCMP…
129 + hbtransformsegment(specs[start].font, glyphs, c…
130 +
131 + /* Reset the sequence. */
132 + length = 1;
133 + start = specidx;
134 + gstart = idx;
135 + } else {
136 + length += 1;
137 + }
138 +
139 + specidx++;
140 + }
141 +
142 + /* EOL. */
143 + hbtransformsegment(specs[start].font, glyphs, codepoints, gstar…
144 +
145 + /* Apply the transformation to glyph specs. */
146 + for (int i = 0, specidx = 0; i < len; i++) {
147 + if (glyphs[i].mode & ATTR_WDUMMY)
148 + continue;
149 +
150 + if (codepoints[i] != specs[specidx].glyph)
151 + ((Glyph *)glyphs)[i].mode |= ATTR_LIGA;
152 +
153 + specs[specidx++].glyph = codepoints[i];
154 + }
155 +
156 + free(codepoints);
157 +}
158 +
159 +void
160 +hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t …
161 +{
162 + hb_font_t *font = hbfindfont(xfont);
163 + if (font == NULL)
164 + return;
165 +
166 + Rune rune;
167 + ushort mode = USHRT_MAX;
168 + hb_buffer_t *buffer = hb_buffer_create();
169 + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
170 +
171 + /* Fill buffer with codepoints. */
172 + for (int i = start; i < (start+length); i++) {
173 + rune = string[i].u;
174 + mode = string[i].mode;
175 + if (mode & ATTR_WDUMMY)
176 + rune = 0x0020;
177 + hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
178 + }
179 +
180 + /* Shape the segment. */
181 + hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_fea…
182 +
183 + /* Get new glyph info. */
184 + hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);
185 +
186 + /* Write new codepoints. */
187 + for (int i = 0; i < length; i++) {
188 + hb_codepoint_t gid = info[i].codepoint;
189 + codepoints[start+i] = gid;
190 + }
191 +
192 + /* Cleanup. */
193 + hb_buffer_destroy(buffer);
194 +}
195 diff --git a/hb.h b/hb.h
196 new file mode 100644
197 index 0000000..07888df
198 --- /dev/null
199 +++ b/hb.h
200 @@ -0,0 +1,6 @@
201 +#include <X11/Xft/Xft.h>
202 +#include <hb.h>
203 +#include <hb-ft.h>
204 +
205 +void hbunloadfonts();
206 +void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);
207 diff --git a/st.c b/st.c
208 index 76b7e0d..e60bf58 100644
209 --- a/st.c
210 +++ b/st.c
211 @@ -2581,7 +2581,8 @@ draw(void)
212
213 drawregion(0, 0, term.col, term.row);
214 xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
215 - term.ocx, term.ocy, term.line[term.ocy][term.oc…
216 + term.ocx, term.ocy, term.line[term.ocy][term.oc…
217 + term.line[term.ocy], term.col);
218 term.ocx = cx;
219 term.ocy = term.c.y;
220 xfinishdraw();
221 diff --git a/st.h b/st.h
222 index 3d351b6..06b115d 100644
223 --- a/st.h
224 +++ b/st.h
225 @@ -11,7 +11,8 @@
226 #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
227 #define DEFAULT(a, b) (a) = (a) ? (a) : (b)
228 #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b)…
229 -#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg !=…
230 +#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR…
231 + (a).fg != (b).fg || \
232 (a).bg != (b).bg)
233 #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
234 (t1.tv_nsec-t2.tv_nsec)/1E6)
235 @@ -33,6 +34,7 @@ enum glyph_attribute {
236 ATTR_WRAP = 1 << 8,
237 ATTR_WIDE = 1 << 9,
238 ATTR_WDUMMY = 1 << 10,
239 + ATTR_LIGA = 1 << 11,
240 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
241 };
242
243 diff --git a/win.h b/win.h
244 index a6ef1b9..bc0d180 100644
245 --- a/win.h
246 +++ b/win.h
247 @@ -25,7 +25,7 @@ enum win_mode {
248
249 void xbell(void);
250 void xclipcopy(void);
251 -void xdrawcursor(int, int, Glyph, int, int, Glyph);
252 +void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
253 void xdrawline(Line, int, int, int);
254 void xfinishdraw(void);
255 void xloadcols(void);
256 diff --git a/x.c b/x.c
257 index 210f184..f6d67ef 100644
258 --- a/x.c
259 +++ b/x.c
260 @@ -19,6 +19,7 @@ char *argv0;
261 #include "arg.h"
262 #include "st.h"
263 #include "win.h"
264 +#include "hb.h"
265
266 /* types used in config.h */
267 typedef struct {
268 @@ -1031,6 +1032,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 @@ -1229,7 +1233,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const…
279 mode = glyphs[i].mode;
280
281 /* Skip dummy wide-character spacing. */
282 - if (mode == ATTR_WDUMMY)
283 + if (mode & ATTR_WDUMMY)
284 continue;
285
286 /* Determine font for glyph if different from previous …
287 @@ -1336,6 +1340,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const…
288 numspecs++;
289 }
290
291 + /* Harfbuzz transformation for ligatures. */
292 + hbtransform(specs, glyphs, len, x, y);
293 +
294 return numspecs;
295 }
296
297 @@ -1485,14 +1492,17 @@ xdrawglyph(Glyph g, int x, int y)
298 }
299
300 void
301 -xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
302 +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line lin…
303 {
304 Color drawcol;
305
306 /* remove the old cursor */
307 if (selected(ox, oy))
308 og.mode ^= ATTR_REVERSE;
309 - xdrawglyph(og, ox, oy);
310 +
311 + /* Redraw the line where cursor was previously.
312 + * It will restore the ligatures broken by the cursor. */
313 + xdrawline(line, 0, oy, len);
314
315 if (IS_SET(MODE_HIDE))
316 return;
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.