--- There is for sure a better way of dealing with the 'badcombining' thing, but I'm not very familiar with X(ft). Anyone here with more insight? To repro: - Delete the badcombining test (x.c:977) - Compile st with "Liberation Mono" font, notice diacritics are off by 1 along x (it's trying to back-up for us?) - Compile st with "SourceCodePro" font, notice diacritics are correct Please let me know what yall think! Have a test string (notice 'o\xcc\x81' (U+006F, U+0301) is the decomposed form of 'รณ' (U+00F3)): printf 'Bo\xcc\x81br k*rwa ja p*erdole jakie bydle\xcc\xa8! w\xcc\x82a\xe2\x83\x97?\numlaut replacing: o\xcc\x83\xcc\x88!\numlaut replacing the previous line: o\xcc\x83 \n\xcc\x88' Regards, Vally. TODO | 3 +-- st.c | 47 +++++++++++++++++++++++++++++++------ st.h | 1 + x.c | 75 +++++++++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 99 insertions(+), 27 deletions(-) diff --git a/TODO b/TODO index 5f74cd5..c2a528c 100644 --- a/TODO +++ b/TODO _AT_@ -10,8 +10,7 @@ code & interface drawing ------- -* add diacritics support to xdraws() - * switch to a suckless font drawing library +* switch to a suckless font drawing library * make the font cache simpler * add better support for brightening of the upper colors diff --git a/st.c b/st.c index 03b9bc8..c82a990 100644 --- a/st.c +++ b/st.c _AT_@ -189,6 +189,7 @@ static void tscrollup(int, int); static void tscrolldown(int, int); static void tsetattr(const int *, int); static void tsetchar(Rune, const Glyph *, int, int); +static void tsetdiacritic(Rune, const Glyph *, int, int); static void tsetdirt(int, int); static void tsetscroll(int, int); static void tswapscreen(void); _AT_@ -412,7 +413,7 @@ tlinelen(int y) if (term.line[y][i - 1].mode & ATTR_WRAP) return i; - while (i > 0 && term.line[y][i - 1].u == ' ') + while (i > 0 && term.line[y][i - 1].u == ' ' && term.line[y][i - 1].d == '\0') --i; return i; _AT_@ -591,7 +592,7 @@ getsel(void) if (sel.ob.x == -1) return NULL; - bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ; + bufsize = (term.col+1) * (sel.ne.y-sel.nb.y+1) * UTF_SIZ * 2; ptr = str = xmalloc(bufsize); /* append every set & selected glyph to the selection */ _AT_@ -609,7 +610,7 @@ getsel(void) lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; } last = &term.line[y][MIN(lastx, linelen-1)]; - while (last >= gp && last->u == ' ') + while (last >= gp && last->u == ' ' && last->d == '\0') --last; for ( ; gp <= last; ++gp) { _AT_@ -617,6 +618,8 @@ getsel(void) continue; ptr += utf8encode(gp->u, ptr); + if (gp->d) + ptr += utf8encode(gp->d, ptr); } /* _AT_@ -1220,6 +1223,28 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) term.line[y][x].u = u; } +void +tsetdiacritic(Rune d, const Glyph * attr, int x, int y) +{ + Rune u; + if (x > 0) { + --x; + } else if (y > 0) { + --y; + x = tlinelen(y); + if (x > 0) + --x; + } + if (x > 0 && (term.line[y][x].mode & ATTR_WDUMMY)) { + --x; + } + term.dirty[y] = 1; + u = term.line[y][x].u; + term.line[y][x] = *attr; + term.line[y][x].u = u; /* *attr stomps on u */ + term.line[y][x].d = d; +} + void tclearregion(int x1, int y1, int x2, int y2) { _AT_@ -1246,6 +1271,7 @@ tclearregion(int x1, int y1, int x2, int y2) gp->bg = term.c.attr.bg; gp->mode = 0; gp->u = ' '; + gp->d = '\0'; } } } _AT_@ -2088,9 +2114,12 @@ tdumpline(int n) bp = &term.line[n][0]; end = &bp[MIN(tlinelen(n), term.col) - 1]; - if (bp != end || bp->u != ' ') { - for ( ; bp <= end; ++bp) + if (bp != end || bp->u != ' ' || bp->d != '\0') { + for ( ; bp <= end; ++bp) { tprinter(buf, utf8encode(bp->u, buf)); + if (bp->d) + tprinter(buf, utf8encode(bp->d, buf)); + } } tprinter("\n", 1); } _AT_@ -2493,8 +2522,12 @@ check_control_code: gp = &term.line[term.c.y][term.c.x]; } - tsetchar(u, &term.c.attr, term.c.x, term.c.y); - term.lastc = u; + if (width > 0) { + tsetchar(u, &term.c.attr, term.c.x, term.c.y); + term.lastc = u; + } else { + tsetdiacritic(u, &term.c.attr, term.c.x, term.c.y); + } if (width == 2) { gp->mode |= ATTR_WIDE; diff --git a/st.h b/st.h index fd3b0d8..cddccde 100644 --- a/st.h +++ b/st.h _AT_@ -62,6 +62,7 @@ typedef uint_least32_t Rune; #define Glyph Glyph_ typedef struct { Rune u; /* character code */ + Rune d; /* diacritic */ ushort mode; /* attribute flags */ uint32_t fg; /* foreground */ uint32_t bg; /* background */ diff --git a/x.c b/x.c index d73152b..c23ff8e 100644 --- a/x.c +++ b/x.c _AT_@ -125,6 +125,7 @@ typedef struct { int descent; int badslant; int badweight; + int badcombining; short lbearing; short rbearing; XftFont *match; _AT_@ -142,7 +143,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); _AT_@ -757,7 +758,7 @@ xresize(int col, int row) xclear(0, 0, win.w, win.h); /* resize to new width */ - xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); + xw.specbuf = xrealloc(xw.specbuf, col * 2 * sizeof(GlyphFontSpec)); } ushort _AT_@ -977,6 +978,16 @@ xloadfont(Font *f, FcPattern *pattern) f->height = f->ascent + f->descent; f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + /* + * Test xoff to see if the font is trying to + * help us position diacritics along x. + */ + XftTextExtentsUtf8(xw.dpy, f->match, + (const FcChar8 *) "a\xcc\x81", + strlen("a\xcc\x81"), &extents); + + f->badcombining = (extents.xOff <= f->width) ? 1 : 0; + return 0; } _AT_@ -1188,7 +1199,7 @@ xinit(int cols, int rows) XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ - xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); + xw.specbuf = xmalloc(cols * 2 * sizeof(GlyphFontSpec)); /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); _AT_@ -1256,11 +1267,11 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, numspecs = 0; + int i, f, numspecs = 0, ondiacritic = 0; for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; + rune = ondiacritic ? glyphs[i].d : glyphs[i].u; mode = glyphs[i].mode; /* Skip dummy wide-character spacing. */ _AT_@ -1291,10 +1302,19 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x if (glyphidx) { specs[numspecs].font = font->match; specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; + specs[numspecs].x = (short)(xp + ( + (ondiacritic && font->badcombining) ? + runewidth : + 0.0)); specs[numspecs].y = (short)yp; - xp += runewidth; numspecs++; + if (!ondiacritic && glyphs[i].d) { + ondiacritic = 1; + --i; + } else { + ondiacritic = 0; + xp += runewidth; + } continue; } _AT_@ -1365,18 +1385,32 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x specs[numspecs].font = frc[f].font; specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; + /* + * TODO: fallback font didn't come from xloadfont, + * don't know if it's badcombining. + */ + specs[numspecs].x = (short)(xp + ( + (ondiacritic && font->badcombining) ? + runewidth : + 0.0)); specs[numspecs].y = (short)yp; - xp += runewidth; numspecs++; + if (!ondiacritic && glyphs[i].d) { + ondiacritic = 1; + --i; + } else { + ondiacritic = 0; + xp += runewidth; + } } return numspecs; } void -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int numspecs, int numdiacritics, int x, int y) { + int len = numspecs - numdiacritics; int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, width = charlen * win.cw; _AT_@ -1492,7 +1526,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); /* Render the glyphs. */ - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + XftDrawGlyphFontSpec(xw.draw, fg, specs, numspecs); /* Render underline and strikethrough. */ if (base.mode & ATTR_UNDERLINE) { _AT_@ -1513,10 +1547,10 @@ void xdrawglyph(Glyph g, int x, int y) { int numspecs; - XftGlyphFontSpec spec; + XftGlyphFontSpec specs[2]; - numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y); + xdrawglyphfontspecs(specs, g, numspecs, g.d ? 1 : 0, x, y); } void _AT_@ -1657,12 +1691,12 @@ xstartdraw(void) void xdrawline(Line line, int x1, int y1, int x2) { - int i, x, ox, numspecs; + int i, x, ox, numspecs, numdiacritics; Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); - i = ox = 0; + i = ox = numdiacritics = 0; for (x = x1; x < x2 && i < numspecs; x++) { new = line[x]; if (new.mode == ATTR_WDUMMY) _AT_@ -1670,19 +1704,24 @@ xdrawline(Line line, int x1, int y1, int x2) if (selected(x, y1)) new.mode ^= ATTR_REVERSE; if (i > 0 && ATTRCMP(base, new)) { - xdrawglyphfontspecs(specs, base, i, ox, y1); + xdrawglyphfontspecs(specs, base, i, numdiacritics, ox, y1); specs += i; numspecs -= i; i = 0; + numdiacritics = 0; } if (i == 0) { ox = x; base = new; } i++; + if (new.d) { + i++; + numdiacritics++; + } } if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y1); + xdrawglyphfontspecs(specs, base, i, numdiacritics, ox, y1); } void -- 2.49.0Received on Mon May 05 2025 - 22:00:53 CEST
This archive was generated by hypermail 2.3.0 : Mon May 05 2025 - 22:12:42 CEST