Created
August 19, 2021 22:45
-
-
Save mohkale/75169f0a400e70d66097cd9f0e0c14e7 to your computer and use it in GitHub Desktop.
st: Fix wide glyph truncation (courtesy of @Dreomite)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/st.h b/st.h | |
index fa2eddf..73debe6 100644 | |
--- a/st.h | |
+++ b/st.h | |
@@ -36,6 +36,12 @@ enum glyph_attribute { | |
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, | |
}; | |
+enum drawing_mode { | |
+ DRAW_NONE = 0, | |
+ DRAW_BG = 1 << 0, | |
+ DRAW_FG = 1 << 1, | |
+}; | |
+ | |
enum selection_mode { | |
SEL_IDLE = 0, | |
SEL_EMPTY = 1, | |
diff --git a/x.c b/x.c | |
index 248d505..6158ef9 100644 | |
--- a/x.c | |
+++ b/x.c | |
@@ -142,7 +142,7 @@ typedef struct { | |
static inline ushort sixd_to_16bit(int); | |
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); | |
-static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); | |
+static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); | |
static void xdrawglyph(Glyph, int, int); | |
static void xclear(int, int, int, int); | |
static int xgeommasktogravity(int); | |
@@ -1343,7 +1343,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x | |
} | |
void | |
-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) | |
+xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) | |
{ | |
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); | |
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, | |
@@ -1434,44 +1434,40 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i | |
if (base.mode & ATTR_INVISIBLE) | |
fg = bg; | |
- /* Intelligent cleaning up of the borders. */ | |
- if (x == 0) { | |
- xclear(0, (y == 0)? 0 : winy, borderpx, | |
- winy + win.ch + | |
- ((winy + win.ch >= borderpx + win.th)? win.h : 0)); | |
- } | |
- if (winx + width >= borderpx + win.tw) { | |
- xclear(winx + width, (y == 0)? 0 : winy, win.w, | |
- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); | |
- } | |
- if (y == 0) | |
- xclear(winx, 0, winx + width, borderpx); | |
- if (winy + win.ch >= borderpx + win.th) | |
- xclear(winx, winy + win.ch, winx + width, win.h); | |
- | |
- /* Clean up the region we want to draw to. */ | |
- XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); | |
- | |
- /* Set the clip region because Xft is sometimes dirty. */ | |
- r.x = 0; | |
- r.y = 0; | |
- r.height = win.ch; | |
- r.width = width; | |
- XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); | |
- | |
- /* Render the glyphs. */ | |
- XftDrawGlyphFontSpec(xw.draw, fg, specs, len); | |
- | |
- /* Render underline and strikethrough. */ | |
- if (base.mode & ATTR_UNDERLINE) { | |
- XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, | |
- width, 1); | |
- } | |
- | |
- if (base.mode & ATTR_STRUCK) { | |
- XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, | |
- width, 1); | |
- } | |
+ if (dmode & DRAW_BG) { | |
+ /* Intelligent cleaning up of the borders. */ | |
+ if (x == 0) { | |
+ xclear(0, (y == 0)? 0 : winy, borderpx, | |
+ winy + win.ch + | |
+ ((winy + win.ch >= borderpx + win.th)? win.h : 0)); | |
+ } | |
+ if (winx + width >= borderpx + win.tw) { | |
+ xclear(winx + width, (y == 0)? 0 : winy, win.w, | |
+ ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); | |
+ } | |
+ if (y == 0) | |
+ xclear(winx, 0, winx + width, borderpx); | |
+ if (winy + win.ch >= borderpx + win.th) | |
+ xclear(winx, winy + win.ch, winx + width, win.h); | |
+ /* Fill the background */ | |
+ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); | |
+ } | |
+ | |
+ if (dmode & DRAW_FG) { | |
+ /* Render the glyphs. */ | |
+ XftDrawGlyphFontSpec(xw.draw, fg, specs, len); | |
+ | |
+ /* Render underline and strikethrough. */ | |
+ if (base.mode & ATTR_UNDERLINE) { | |
+ XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, | |
+ width, 1); | |
+ } | |
+ | |
+ if (base.mode & ATTR_STRUCK) { | |
+ XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, | |
+ width, 1); | |
+ } | |
+ } | |
/* Reset clip to none. */ | |
XftDrawSetClip(xw.draw, 0); | |
@@ -1484,7 +1480,7 @@ xdrawglyph(Glyph g, int x, int y) | |
XftGlyphFontSpec spec; | |
numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); | |
- xdrawglyphfontspecs(&spec, g, numspecs, x, y); | |
+ xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); | |
} | |
void | |
@@ -1617,32 +1613,40 @@ xstartdraw(void) | |
void | |
xdrawline(Line line, int x1, int y1, int x2) | |
{ | |
- int i, x, ox, numspecs; | |
+ int i, x, ox, numspecs, numspecs_cached; | |
Glyph base, new; | |
- XftGlyphFontSpec *specs = xw.specbuf; | |
+ XftGlyphFontSpec *specs; | |
+ | |
+ numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); | |
+ | |
+ /* Draw line in 2 passes: background and foreground. This way wide glyphs | |
+ won't get truncated (#223) */ | |
+ for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { | |
+ specs = xw.specbuf; | |
+ numspecs = numspecs_cached; | |
+ i = ox = 0; | |
+ for (x = x1; x < x2 && i < numspecs; 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, dmode); | |
+ specs += i; | |
+ numspecs -= i; | |
+ i = 0; | |
+ } | |
+ if (i == 0) { | |
+ ox = x; | |
+ base = new; | |
+ } | |
+ i++; | |
+ } | |
+ if (i > 0) | |
+ xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); | |
+ } | |
- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); | |
- i = ox = 0; | |
- for (x = x1; x < x2 && i < numspecs; 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; | |
- i = 0; | |
- } | |
- if (i == 0) { | |
- ox = x; | |
- base = new; | |
- } | |
- i++; | |
- } | |
- if (i > 0) | |
- xdrawglyphfontspecs(specs, base, i, ox, y1); | |
} | |
void |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment