[dev] [st] [PATCH] Converted "font" string to "fonts" array

From: Eric Pruitt <eric.pruitt_AT_gmail.com>
Date: Sun, 31 Jul 2016 15:01:24 -0700

Modifies st to support user-defined fallback fonts specified in an
array. This change also resolves an issue where fallback fonts were used
in place of default fonts in an inconsistent manner which caused
identical sets of text to sometimes use different fonts.
---
 config.def.h |  15 +++++---
 st.c         | 120 ++++++++++++++++++++++++++++++++++++++---------------------
 2 files changed, 87 insertions(+), 48 deletions(-)
diff --git a/config.def.h b/config.def.h
index b41747f..2febe40 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -1,11 +1,16 @@
 /* See LICENSE file for copyright and license details. */
-/*
- * appearance
- *
- * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
+/**
+ * Array of the primary font and fallback fonts. The first string in the array
+ * is the primary font while the rest of the fonts will be used as fallbacks
+ * when preceding fonts are missing a specific glyph. See
+ * http://freedesktop.org/software/fontconfig/fontconfig-user.html for more
+ * info on font definitions.
  */
-static char font[] = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
+static char *fonts[] = {
+    "Liberation Mono:pixelsize=12:antialias=true:autohint=true",
+};
+
 static int borderpx = 2;
 /*
diff --git a/st.c b/st.c
index 2594c65..f7973bd 100644
--- a/st.c
+++ b/st.c
_AT_@ -353,10 +353,17 @@ typedef struct {
        FcPattern *pattern;
 } Font;
+typedef struct {
+       Font font;
+       Font bfont;
+       Font ifont;
+       Font ibfont;
+} FontFamily;
+
 /* Drawing Context */
 typedef struct {
        Color col[MAX(LEN(colorname), 256)];
-       Font font, bfont, ifont, ibfont;
+       FontFamily fontfamily;
        GC gc;
 } DC;
_AT_@ -434,7 +441,7 @@ static void xloadcols(void);
 static int xsetcolorname(int, const char *);
 static int xgeommasktogravity(int);
 static int xloadfont(Font *, FcPattern *);
-static void xloadfonts(char *, double);
+static void xloadfonts(const char *, double);
 static void xsettitle(char *);
 static void xresettitle(void);
 static void xsetpointermotion(int);
_AT_@ -533,7 +540,7 @@ static char *opt_name  = NULL;
 static char *opt_title = NULL;
 static int oldbutton   = 3; /* button event on startup: 3 = release */
-static char *usedfont = NULL;
+static const char *usedfont = NULL;
 static double usedfontsize = 0;
 static double defaultfontsize = 0;
_AT_@ -542,6 +549,9 @@ static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
 static Rune utfmin[UTF_SIZ + 1] = {       0,    0,  0x80,  0x800,  0x10000};
 static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+static FontFamily fontfamilies[16];
+static int fontfamiliescount = 0;
+
 /* Font Ring Cache */
 enum {
        FRC_NORMAL,
_AT_@ -3307,11 +3317,16 @@ xloadfont(Font *f, FcPattern *pattern)
 }
 void
-xloadfonts(char *fontstr, double fontsize)
+xloadfonts(const char *fontstr, double fontsize)
 {
        FcPattern *pattern;
        double fontval;
        float ceilf(float);
+       FontFamily fontfamily;
+
+       if (fontfamiliescount >= LEN(fontfamilies)) {
+               die("Font family array is full.\n");
+       }
        if (fontstr[0] == '-') {
                pattern = XftXlfdParse(fontstr, False, False);
_AT_@ -3345,37 +3360,43 @@ xloadfonts(char *fontstr, double fontsize)
                defaultfontsize = usedfontsize;
        }
-       if (xloadfont(&dc.font, pattern))
+       if (xloadfont(&fontfamily.font, pattern))
                die("st: can't open font %s\n", fontstr);
        if (usedfontsize < 0) {
-               FcPatternGetDouble(dc.font.match->pattern,
+               FcPatternGetDouble(fontfamily.font.match->pattern,
                                   FC_PIXEL_SIZE, 0, &fontval);
                usedfontsize = fontval;
                if (fontsize == 0)
                        defaultfontsize = fontval;
        }
-       /* Setting character width and height. */
-       xw.cw = ceilf(dc.font.width * cwscale);
-       xw.ch = ceilf(dc.font.height * chscale);
-
        FcPatternDel(pattern, FC_SLANT);
        FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
-       if (xloadfont(&dc.ifont, pattern))
+       if (xloadfont(&fontfamily.ifont, pattern))
                die("st: can't open font %s\n", fontstr);
        FcPatternDel(pattern, FC_WEIGHT);
        FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
-       if (xloadfont(&dc.ibfont, pattern))
+       if (xloadfont(&fontfamily.ibfont, pattern))
                die("st: can't open font %s\n", fontstr);
        FcPatternDel(pattern, FC_SLANT);
        FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
-       if (xloadfont(&dc.bfont, pattern))
+       if (xloadfont(&fontfamily.bfont, pattern))
                die("st: can't open font %s\n", fontstr);
        FcPatternDestroy(pattern);
+
+       /* Setting character width and height. */
+       if (!fontfamiliescount) {
+               xw.cw = ceilf(fontfamily.font.width * cwscale);
+               xw.ch = ceilf(fontfamily.font.height * chscale);
+               dc.fontfamily = fontfamily;
+               usedfont = fontstr;
+       }
+
+       fontfamilies[fontfamiliescount++] = fontfamily;
 }
 void
_AT_@ -3394,10 +3415,13 @@ xunloadfonts(void)
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-       xunloadfont(&dc.font);
-       xunloadfont(&dc.bfont);
-       xunloadfont(&dc.ifont);
-       xunloadfont(&dc.ibfont);
+       while (fontfamiliescount > 0) {
+               fontfamiliescount--;
+               xunloadfont(&fontfamilies[fontfamiliescount].font);
+               xunloadfont(&fontfamilies[fontfamiliescount].bfont);
+               xunloadfont(&fontfamilies[fontfamiliescount].ifont);
+               xunloadfont(&fontfamilies[fontfamiliescount].ibfont);
+       }
 }
 void
_AT_@ -3434,6 +3458,8 @@ xzoomreset(const Arg *arg)
 void
 xinit(void)
 {
+       int i;
+
        XGCValues gcvalues;
        Cursor cursor;
        Window parent;
_AT_@ -3449,8 +3475,13 @@ xinit(void)
        if (!FcInit())
                die("Could not init fontconfig.\n");
-       usedfont = (opt_font == NULL)? font : opt_font;
-       xloadfonts(usedfont, 0);
+       if (opt_font) {
+               xloadfonts(opt_font, 0);
+       }
+
+       for (i = 0; i < LEN(fonts); i++) {
+               xloadfonts(fonts[i], 0);
+       }
        /* colors */
        xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
_AT_@ -3546,9 +3577,9 @@ xinit(void)
 int
 xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
 {
-       float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp;
-       ushort mode, prevmode = USHRT_MAX;
-       Font *font = &dc.font;
+       float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp;
+       ushort mode;
+       Font *font, *reference = NULL;
        int frcflags = FRC_NORMAL;
        float runewidth = xw.cw;
        Rune rune;
_AT_@ -3559,7 +3590,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph
*glyphs, int len, int x
        FcCharSet *fccharset;
        int i, f, numspecs = 0;
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+       for (i = 0, xp = winx; i < len; ++i) {
                /* Fetch rune and mode for current glyph. */
                rune = glyphs[i].u;
                mode = glyphs[i].mode;
_AT_@ -3568,32 +3599,33 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const
Glyph *glyphs, int len, int x
                if (mode == ATTR_WDUMMY)
                        continue;
-               /* Determine font for glyph if different from previous glyph. */
-               if (prevmode != mode) {
-                       prevmode = mode;
-                       font = &dc.font;
+               /* Lookup character index within user-defined fonts. */
+               for (glyphidx = 0, f = 0; f < fontfamiliescount && !glyphidx; f++) {
+                       font = &fontfamilies[f].font;
                        frcflags = FRC_NORMAL;
                        runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
                        if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
-                               font = &dc.ibfont;
+                               font = &fontfamilies[f].ibfont;
                                frcflags = FRC_ITALICBOLD;
                        } else if (mode & ATTR_ITALIC) {
-                               font = &dc.ifont;
+                               font = &fontfamilies[f].ifont;
                                frcflags = FRC_ITALIC;
                        } else if (mode & ATTR_BOLD) {
-                               font = &dc.bfont;
+                               font = &fontfamilies[f].bfont;
                                frcflags = FRC_BOLD;
                        }
-                       yp = winy + font->ascent;
+
+                       if (!f) {
+                               reference = font;
+                       }
+                       glyphidx = XftCharIndex(xw.dpy, font->match, rune);
                }
-               /* Lookup character index with default font. */
-               glyphidx = XftCharIndex(xw.dpy, font->match, rune);
                if (glyphidx) {
                        specs[numspecs].font = font->match;
                        specs[numspecs].glyph = glyphidx;
                        specs[numspecs].x = (short)xp;
-                       specs[numspecs].y = (short)yp;
+                       specs[numspecs].y = (short) (winy + font->ascent);
                        xp += runewidth;
                        numspecs++;
                        continue;
_AT_@ -3612,12 +3644,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const
Glyph *glyphs, int len, int x
                        }
                }
-               /* Nothing was found. Use fontconfig to find matching font. */
+               /* Nothing was found. Use fontconfig to find matching font using the
+                * default font as the reference font.
+                */
                if (f >= frclen) {
-                       if (!font->set)
-                               font->set = FcFontSort(0, font->pattern,
-                                                      1, 0, &fcres);
-                       fcsets[0] = font->set;
+                       if (!reference->set)
+                               reference->set = FcFontSort(0, reference->pattern,
+                                                           1, 0, &fcres);
+                       fcsets[0] = reference->set;
                        /*
                         * Nothing was found in the cache. Now use
_AT_@ -3626,7 +3660,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph
*glyphs, int len, int x
                         *
                         * Xft and fontconfig are design failures.
                         */
-                       fcpattern = FcPatternDuplicate(font->pattern);
+                       fcpattern = FcPatternDuplicate(reference->pattern);
                        fccharset = FcCharSetCreate();
                        FcCharSetAddChar(fccharset, rune);
_AT_@ -3667,7 +3701,7 @@ 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;
-               specs[numspecs].y = (short)yp;
+               specs[numspecs].y = (short) (winy + frc[f].font->ascent);
                xp += runewidth;
                numspecs++;
        }
_AT_@ -3796,12 +3830,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs,
Glyph base, int len, int x, i
        /* Render underline and strikethrough. */
        if (base.mode & ATTR_UNDERLINE) {
-               XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
+               XftDrawRect(xw.draw, fg, winx, winy + dc.fontfamily.font.ascent + 1,
                                width, 1);
        }
        if (base.mode & ATTR_STRUCK) {
-               XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
+               XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.fontfamily.font.ascent / 3,
                                width, 1);
        }
--
2.1.4
Received on Mon Aug 01 2016 - 00:01:24 CEST

This archive was generated by hypermail 2.3.0 : Mon Aug 01 2016 - 00:13:34 CEST