1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00

gtkfont: refactor parse/unparse of XLFDs.

There were already two places in the code (x11font_enum_fonts and
x11_guess_derived_font_name) where we retrieved an XLFD from the X
server, sawed it up ad-hoc into its '-'-separated parts and accessed
them by numeric index.

I'm about to add a third, so before I do, let's turn this into a
somewhat principled system where we get to do the decode/encode in
just one place and call all the individual fields by names that are
actually memorable.

No functional change intended by this commit.
This commit is contained in:
Simon Tatham 2016-11-13 12:02:13 +00:00
parent 22013390c4
commit d9c68d236b

View File

@ -219,6 +219,86 @@ static const struct unifont_vtable x11font_vtable = {
"server",
};
#define XLFD_STRING_PARTS_LIST(S,I) \
S(foundry) \
S(family_name) \
S(weight_name) \
S(slant) \
S(setwidth_name) \
S(add_style_name) \
I(pixel_size) \
I(point_size) \
I(resolution_x) \
I(resolution_y) \
S(spacing) \
I(average_width) \
S(charset_registry) \
S(charset_encoding) \
/* end of list */
struct xlfd_decomposed {
#define STR_FIELD(f) const char *f;
#define INT_FIELD(f) int f;
XLFD_STRING_PARTS_LIST(STR_FIELD, INT_FIELD)
#undef STR_FIELD
#undef INT_FIELD
};
static struct xlfd_decomposed *xlfd_decompose(const char *xlfd)
{
void *mem;
char *p, *components[14];
struct xlfd_decomposed *dec;
int i;
if (!xlfd)
return NULL;
mem = smalloc(sizeof(struct xlfd_decomposed) + strlen(xlfd) + 1);
p = ((char *)mem) + sizeof(struct xlfd_decomposed);
strcpy(p, xlfd);
dec = (struct xlfd_decomposed *)mem;
for (i = 0; i < 14; i++) {
if (*p != '-') {
/* Malformed XLFD: not enough '-' */
sfree(mem);
return NULL;
}
*p++ = '\0';
components[i] = p;
p += strcspn(p, "-");
}
if (*p) {
/* Malformed XLFD: too many '-' */
sfree(mem);
return NULL;
}
i = 0;
#define STORE_STR(f) dec->f = components[i++];
#define STORE_INT(f) dec->f = atoi(components[i++]);
XLFD_STRING_PARTS_LIST(STORE_STR, STORE_INT)
#undef STORE_STR
#undef STORE_INT
return dec;
}
static char *xlfd_recompose(const struct xlfd_decomposed *dec)
{
#define FMT_STR(f) "-%s"
#define ARG_STR(f) , dec->f
#define FMT_INT(f) "-%d"
#define ARG_INT(f) , dec->f
return dupprintf(XLFD_STRING_PARTS_LIST(FMT_STR, FMT_INT)
XLFD_STRING_PARTS_LIST(ARG_STR, ARG_INT));
#undef FMT_STR
#undef ARG_STR
#undef FMT_INT
#undef ARG_INT
}
static char *x11_guess_derived_font_name(XFontStruct *xfs, int bold, int wide)
{
Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
@ -226,48 +306,27 @@ static char *x11_guess_derived_font_name(XFontStruct *xfs, int bold, int wide)
unsigned long ret;
if (XGetFontProperty(xfs, fontprop, &ret)) {
char *name = XGetAtomName(disp, (Atom)ret);
if (name && name[0] == '-') {
const char *strings[13];
char *dupname, *extrafree = NULL, *ret;
char *p, *q;
int nstr;
struct xlfd_decomposed *xlfd = xlfd_decompose(name);
if (!xlfd)
return NULL;
p = q = dupname = dupstr(name); /* skip initial minus */
nstr = 0;
if (bold)
xlfd->weight_name = "bold";
while (*p && nstr < lenof(strings)) {
if (*p == '-') {
*p = '\0';
strings[nstr++] = p+1;
}
p++;
}
if (wide) {
/* Width name obviously may have changed. */
/* Additional style may now become e.g. `ja' or `ko'. */
xlfd->setwidth_name = xlfd->add_style_name = "*";
if (nstr < lenof(strings)) {
sfree(dupname);
return NULL; /* XLFD was malformed */
}
/* Expect to double the average width. */
xlfd->average_width *= 2;
}
if (bold)
strings[2] = "bold";
if (wide) {
/* 4 is `wideness', which obviously may have changed. */
/* 5 is additional style, which may be e.g. `ja' or `ko'. */
strings[4] = strings[5] = "*";
strings[11] = extrafree = dupprintf("%d", 2*atoi(strings[11]));
}
ret = dupcat("-", strings[ 0], "-", strings[ 1], "-", strings[ 2],
"-", strings[ 3], "-", strings[ 4], "-", strings[ 5],
"-", strings[ 6], "-", strings[ 7], "-", strings[ 8],
"-", strings[ 9], "-", strings[10], "-", strings[11],
"-", strings[12], NULL);
sfree(extrafree);
sfree(dupname);
return ret;
}
{
char *ret = xlfd_recompose(xlfd);
sfree(xlfd);
return ret;
}
}
return NULL;
}
@ -921,73 +980,65 @@ static void x11font_enum_fonts(GtkWidget *widget,
tmpsize = 0;
for (i = 0; i < nnames; i++) {
if (fontnames[i][0] == '-') {
struct xlfd_decomposed *xlfd = xlfd_decompose(fontnames[i]);
if (xlfd) {
char *p, *font, *style, *stylekey, *charset;
int weightkey, slantkey, setwidthkey;
int thistmpsize;
/*
* Dismember an XLFD and convert it into the format
* we'll be using in the font selector.
* Convert a dismembered XLFD into the format we'll be
* using in the font selector.
*/
char *components[14];
char *p, *font, *style, *stylekey, *charset;
int j, weightkey, slantkey, setwidthkey;
int thistmpsize, fontsize, flags;
thistmpsize = 4 * strlen(fontnames[i]) + 256;
if (tmpsize < thistmpsize) {
tmpsize = thistmpsize;
tmp = sresize(tmp, tmpsize, char);
}
strcpy(tmp, fontnames[i]);
thistmpsize = 4 * strlen(fontnames[i]) + 256;
if (tmpsize < thistmpsize) {
tmpsize = thistmpsize;
tmp = sresize(tmp, tmpsize, char);
}
p = tmp;
for (j = 0; j < 14; j++) {
if (*p)
*p++ = '\0';
components[j] = p;
while (*p && *p != '-')
p++;
}
*p++ = '\0';
/*
* Font name is made up of fields 0 and 1, in reverse
* order with parentheses. (This is what the GTK 1.2 X
* font selector does, and it seems to come out
* looking reasonably sensible.)
* Font name is in the form "family (foundry)". (This is
* what the GTK 1.2 X font selector does, and it seems to
* come out looking reasonably sensible.)
*/
font = p;
p += 1 + sprintf(p, "%s (%s)", components[1], components[0]);
p += 1 + sprintf(p, "%s (%s)", xlfd->family_name, xlfd->foundry);
/*
* Charset is made up of fields 12 and 13.
* Character set.
*/
charset = p;
p += 1 + sprintf(p, "%s-%s", components[12], components[13]);
p += 1 + sprintf(p, "%s-%s", xlfd->charset_registry,
xlfd->charset_encoding);
/*
* Style is a mixture of quite a lot of the fields,
* with some strange formatting.
*/
style = p;
p += sprintf(p, "%s", components[2][0] ? components[2] :
p += sprintf(p, "%s", xlfd->weight_name[0] ? xlfd->weight_name :
"regular");
if (!g_ascii_strcasecmp(components[3], "i"))
if (!g_ascii_strcasecmp(xlfd->slant, "i"))
p += sprintf(p, " italic");
else if (!g_ascii_strcasecmp(components[3], "o"))
else if (!g_ascii_strcasecmp(xlfd->slant, "o"))
p += sprintf(p, " oblique");
else if (!g_ascii_strcasecmp(components[3], "ri"))
else if (!g_ascii_strcasecmp(xlfd->slant, "ri"))
p += sprintf(p, " reverse italic");
else if (!g_ascii_strcasecmp(components[3], "ro"))
else if (!g_ascii_strcasecmp(xlfd->slant, "ro"))
p += sprintf(p, " reverse oblique");
else if (!g_ascii_strcasecmp(components[3], "ot"))
else if (!g_ascii_strcasecmp(xlfd->slant, "ot"))
p += sprintf(p, " other-slant");
if (components[4][0] && g_ascii_strcasecmp(components[4], "normal"))
p += sprintf(p, " %s", components[4]);
if (!g_ascii_strcasecmp(components[10], "m"))
if (xlfd->setwidth_name[0] &&
g_ascii_strcasecmp(xlfd->setwidth_name, "normal"))
p += sprintf(p, " %s", xlfd->setwidth_name);
if (!g_ascii_strcasecmp(xlfd->spacing, "m"))
p += sprintf(p, " [M]");
if (!g_ascii_strcasecmp(components[10], "c"))
if (!g_ascii_strcasecmp(xlfd->spacing, "c"))
p += sprintf(p, " [C]");
if (components[5][0])
p += sprintf(p, " %s", components[5]);
if (xlfd->add_style_name[0])
p += sprintf(p, " %s", xlfd->add_style_name);
/*
* Style key is the same stuff as above, but with a
@ -996,63 +1047,59 @@ static void x11font_enum_fonts(GtkWidget *widget,
*/
p++;
stylekey = p;
if (!g_ascii_strcasecmp(components[2], "medium") ||
!g_ascii_strcasecmp(components[2], "regular") ||
!g_ascii_strcasecmp(components[2], "normal") ||
!g_ascii_strcasecmp(components[2], "book"))
if (!g_ascii_strcasecmp(xlfd->weight_name, "medium") ||
!g_ascii_strcasecmp(xlfd->weight_name, "regular") ||
!g_ascii_strcasecmp(xlfd->weight_name, "normal") ||
!g_ascii_strcasecmp(xlfd->weight_name, "book"))
weightkey = 0;
else if (!g_ascii_strncasecmp(components[2], "demi", 4) ||
!g_ascii_strncasecmp(components[2], "semi", 4))
else if (!g_ascii_strncasecmp(xlfd->weight_name, "demi", 4) ||
!g_ascii_strncasecmp(xlfd->weight_name, "semi", 4))
weightkey = 1;
else
weightkey = 2;
if (!g_ascii_strcasecmp(components[3], "r"))
if (!g_ascii_strcasecmp(xlfd->slant, "r"))
slantkey = 0;
else if (!g_ascii_strncasecmp(components[3], "r", 1))
else if (!g_ascii_strncasecmp(xlfd->slant, "r", 1))
slantkey = 2;
else
slantkey = 1;
if (!g_ascii_strcasecmp(components[4], "normal"))
if (!g_ascii_strcasecmp(xlfd->setwidth_name, "normal"))
setwidthkey = 0;
else
setwidthkey = 1;
p += sprintf(p, "%04d%04d%s%04d%04d%s%04d%04d%s%04d%s%04d%s",
weightkey,
(int)strlen(components[2]), components[2],
slantkey,
(int)strlen(components[3]), components[3],
setwidthkey,
(int)strlen(components[4]), components[4],
(int)strlen(components[10]), components[10],
(int)strlen(components[5]), components[5]);
p += sprintf(
p, "%04d%04d%s%04d%04d%s%04d%04d%s%04d%s%04d%s",
weightkey, (int)strlen(xlfd->weight_name), xlfd->weight_name,
slantkey, (int)strlen(xlfd->slant), xlfd->slant,
setwidthkey,
(int)strlen(xlfd->setwidth_name), xlfd->setwidth_name,
(int)strlen(xlfd->spacing), xlfd->spacing,
(int)strlen(xlfd->add_style_name), xlfd->add_style_name);
assert(p - tmp < thistmpsize);
/*
* Size is in pixels, for our application, so we
* derive it directly from the pixel size field,
* number 6.
*/
fontsize = atoi(components[6]);
/*
* Flags: we need to know whether this is a monospaced
* font, which we do by examining the spacing field
* again.
*/
flags = FONTFLAG_SERVERSIDE;
if (!strchr("CcMm", components[10][0]))
if (!strchr("CcMm", xlfd->spacing[0]))
flags |= FONTFLAG_NONMONOSPACED;
/*
* Not sure why, but sometimes the X server will
* deliver dummy font types in which fontsize comes
* out as zero. Filter those out.
* Some fonts have a pixel size of zero, meaning they're
* treated as scalable. For these purposes, we only want
* fonts whose pixel size we actually know, so filter
* those out.
*/
if (fontsize)
callback(callback_ctx, fontnames[i], font, charset,
style, stylekey, fontsize, flags, &x11font_vtable);
if (xlfd->pixel_size)
callback(callback_ctx, fontnames[i], font, charset,
style, stylekey, xlfd->pixel_size, flags,
&x11font_vtable);
sfree(xlfd);
} else {
/*
* This isn't an XLFD, so it must be an alias.
@ -1064,6 +1111,8 @@ static void x11font_enum_fonts(GtkWidget *widget,
*/
callback(callback_ctx, fontnames[i], fontnames[i], NULL,
NULL, NULL, 0, FONTFLAG_SERVERALIAS, &x11font_vtable);
sfree(xlfd);
}
}
XFreeFontNames(fontnames);