---
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.0
Received 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