st-glyph-wide-support-20230701-5770f2f.diff (7400B)
1 From 5770f2fc02afca341c275fc340bbc5003ecc3df8 Mon Sep 17 00:00:00 2001 2 From: Iskustvo <iskustvo@yahoo.com> 3 Date: Sat, 7 Jan 2023 01:23:37 +0100 4 Subject: [PATCH] [PATCH] add glyph wide support patch 5 6 --- 7 st.c | 3 +- 8 st.h | 6 +++ 9 win.h | 2 +- 10 x.c | 141 ++++++++++++++++++++++++++++++---------------------------- 11 4 files changed, 81 insertions(+), 71 deletions(-) 12 13 diff --git a/st.c b/st.c 14 index 62def59..cc6c78e 100644 15 --- a/st.c 16 +++ b/st.c 17 @@ -2640,7 +2640,8 @@ draw(void) 18 19 drawregion(0, 0, term.col, term.row); 20 xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 21 - term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 22 + term.ocx, term.ocy, term.line[term.ocy][term.ocx], 23 + term.line[term.ocy], term.col); 24 term.ocx = cx; 25 term.ocy = term.c.y; 26 xfinishdraw(); 27 diff --git a/st.h b/st.h 28 index fd3b0d8..0053050 100644 29 --- a/st.h 30 +++ b/st.h 31 @@ -36,6 +36,12 @@ enum glyph_attribute { 32 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, 33 }; 34 35 +enum drawing_mode { 36 + DRAW_NONE = 0, 37 + DRAW_BG = 1 << 0, 38 + DRAW_FG = 1 << 1, 39 +}; 40 + 41 enum selection_mode { 42 SEL_IDLE = 0, 43 SEL_EMPTY = 1, 44 diff --git a/win.h b/win.h 45 index 6de960d..94679e4 100644 46 --- a/win.h 47 +++ b/win.h 48 @@ -25,7 +25,7 @@ enum win_mode { 49 50 void xbell(void); 51 void xclipcopy(void); 52 -void xdrawcursor(int, int, Glyph, int, int, Glyph); 53 +void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int); 54 void xdrawline(Line, int, int, int); 55 void xfinishdraw(void); 56 void xloadcols(void); 57 diff --git a/x.c b/x.c 58 index aa09997..85deee6 100644 59 --- a/x.c 60 +++ b/x.c 61 @@ -142,7 +142,7 @@ typedef struct { 62 63 static inline ushort sixd_to_16bit(int); 64 static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); 65 -static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); 66 +static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); 67 static void xdrawglyph(Glyph, int, int); 68 static void xclear(int, int, int, int); 69 static int xgeommasktogravity(int); 70 @@ -1372,7 +1372,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x 71 } 72 73 void 74 -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) 75 +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) 76 { 77 int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); 78 int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, 79 @@ -1463,47 +1463,40 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 80 if (base.mode & ATTR_INVISIBLE) 81 fg = bg; 82 83 - /* Intelligent cleaning up of the borders. */ 84 - if (x == 0) { 85 - xclear(0, (y == 0)? 0 : winy, borderpx, 86 - winy + win.ch + 87 - ((winy + win.ch >= borderpx + win.th)? win.h : 0)); 88 - } 89 - if (winx + width >= borderpx + win.tw) { 90 - xclear(winx + width, (y == 0)? 0 : winy, win.w, 91 - ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); 92 - } 93 - if (y == 0) 94 - xclear(winx, 0, winx + width, borderpx); 95 - if (winy + win.ch >= borderpx + win.th) 96 - xclear(winx, winy + win.ch, winx + width, win.h); 97 - 98 - /* Clean up the region we want to draw to. */ 99 - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); 100 - 101 - /* Set the clip region because Xft is sometimes dirty. */ 102 - r.x = 0; 103 - r.y = 0; 104 - r.height = win.ch; 105 - r.width = width; 106 - XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); 107 - 108 - /* Render the glyphs. */ 109 - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); 110 - 111 - /* Render underline and strikethrough. */ 112 - if (base.mode & ATTR_UNDERLINE) { 113 - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, 114 - width, 1); 115 - } 116 - 117 - if (base.mode & ATTR_STRUCK) { 118 - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, 119 - width, 1); 120 - } 121 - 122 - /* Reset clip to none. */ 123 - XftDrawSetClip(xw.draw, 0); 124 + if (dmode & DRAW_BG) { 125 + /* Intelligent cleaning up of the borders. */ 126 + if (x == 0) { 127 + xclear(0, (y == 0)? 0 : winy, borderpx, 128 + winy + win.ch + 129 + ((winy + win.ch >= borderpx + win.th)? win.h : 0)); 130 + } 131 + if (winx + width >= borderpx + win.tw) { 132 + xclear(winx + width, (y == 0)? 0 : winy, win.w, 133 + ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); 134 + } 135 + if (y == 0) 136 + xclear(winx, 0, winx + width, borderpx); 137 + if (winy + win.ch >= borderpx + win.th) 138 + xclear(winx, winy + win.ch, winx + width, win.h); 139 + /* Fill the background */ 140 + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); 141 + } 142 + 143 + if (dmode & DRAW_FG) { 144 + /* Render the glyphs. */ 145 + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); 146 + 147 + /* Render underline and strikethrough. */ 148 + if (base.mode & ATTR_UNDERLINE) { 149 + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, 150 + width, 1); 151 + } 152 + 153 + if (base.mode & ATTR_STRUCK) { 154 + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, 155 + width, 1); 156 + } 157 + } 158 } 159 160 void 161 @@ -1513,18 +1506,21 @@ xdrawglyph(Glyph g, int x, int y) 162 XftGlyphFontSpec spec; 163 164 numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); 165 - xdrawglyphfontspecs(&spec, g, numspecs, x, y); 166 + xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); 167 } 168 169 void 170 -xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) 171 +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len) 172 { 173 Color drawcol; 174 175 /* remove the old cursor */ 176 if (selected(ox, oy)) 177 og.mode ^= ATTR_REVERSE; 178 - xdrawglyph(og, ox, oy); 179 + 180 + /* Redraw the line where cursor was previously. 181 + * It will restore wide glyphs and ligatures broken by the cursor. */ 182 + xdrawline(line, 0, oy, len); 183 184 if (IS_SET(MODE_HIDE)) 185 return; 186 @@ -1648,32 +1644,39 @@ xstartdraw(void) 187 void 188 xdrawline(Line line, int x1, int y1, int x2) 189 { 190 - int i, x, ox, numspecs; 191 + int i, x, ox, numspecs, numspecs_cached; 192 Glyph base, new; 193 - XftGlyphFontSpec *specs = xw.specbuf; 194 - 195 - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); 196 - i = ox = 0; 197 - for (x = x1; x < x2 && i < numspecs; x++) { 198 - new = line[x]; 199 - if (new.mode == ATTR_WDUMMY) 200 - continue; 201 - if (selected(x, y1)) 202 - new.mode ^= ATTR_REVERSE; 203 - if (i > 0 && ATTRCMP(base, new)) { 204 - xdrawglyphfontspecs(specs, base, i, ox, y1); 205 - specs += i; 206 - numspecs -= i; 207 - i = 0; 208 - } 209 - if (i == 0) { 210 - ox = x; 211 - base = new; 212 + XftGlyphFontSpec *specs; 213 + 214 + numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); 215 + 216 + /* Draw line in 2 passes: background and foreground. This way wide glyphs 217 + won't get truncated (#223) */ 218 + for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { 219 + specs = xw.specbuf; 220 + numspecs = numspecs_cached; 221 + i = ox = 0; 222 + for (x = x1; x < x2 && i < numspecs; x++) { 223 + new = line[x]; 224 + if (new.mode == ATTR_WDUMMY) 225 + continue; 226 + if (selected(x, y1)) 227 + new.mode ^= ATTR_REVERSE; 228 + if (i > 0 && ATTRCMP(base, new)) { 229 + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); 230 + specs += i; 231 + numspecs -= i; 232 + i = 0; 233 + } 234 + if (i == 0) { 235 + ox = x; 236 + base = new; 237 + } 238 + i++; 239 } 240 - i++; 241 + if (i > 0) 242 + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); 243 } 244 - if (i > 0) 245 - xdrawglyphfontspecs(specs, base, i, ox, y1); 246 } 247 248 void 249 -- 250 2.39.0 251