2
* fonts.c -- $Id: fonts.c,v 1.1 2003/03/08 15:26:51 travo Exp $
3
* font management for X11
5
* Copyright (c) 1998. See accompanying LEGAL file for details.
8
/* see README in this directory for explanatory notes */
18
/* x_parse_fonts is semi-private, used only in connect.c */
19
extern void x_parse_fonts(x_display *xdpy);
21
static int x_substitute(x_display *xdpy, int *font, int *pixsize);
22
static void x_analyze(x_display *xdpy, int fam);
23
static void tmp_free(void);
25
static int x_closest(int pixsize, int *sizes, int nsizes, int *ndx);
26
static int x_lookup(int pixsize, int *sizes, int nsizes);
27
static char *x_face(char *name, int *face);
28
static int x_insert(int pixsize, int *sizes, char **names, int nsizes);
31
x_parse_fonts(x_display *xdpy)
33
x_analyze(xdpy, P_COURIER);
34
x_analyze(xdpy, P_TIMES);
35
x_analyze(xdpy, P_HELVETICA);
36
x_analyze(xdpy, P_SYMBOL);
37
x_analyze(xdpy, P_NEWCENTURY);
40
static char **tmp_fonts = 0;
44
char **tmp = tmp_fonts;
52
x_font(x_display *xdpy, int font, int pixsize)
56
if (tmp_fonts) tmp_free();
58
if (font>=P_GUI_FONT || font<0 || pixsize<=0 || pixsize>180) {
62
int siz, i, j, pass, *ip, *jp;
63
for (pass=siz=0 ;; pass++) {
66
i = xdpy->most_recent;
68
if (!xdpy->cached[i].f) {
69
/* handle interrupted unload operation */
73
if (xdpy->cached[i].font==font &&
74
xdpy->cached[i].pixsize==pixsize) {
76
/* CRITICAL section */
77
*ip = xdpy->cached[i].next;
78
xdpy->cached[i].next = xdpy->most_recent;
79
xdpy->most_recent = i;
81
return xdpy->cached[i].f;
84
ip = &xdpy->cached[i].next;
89
siz = x_substitute(xdpy, &font, &pixsize);
90
if (font==P_GUI_FONT) return xdpy->font;
93
/* construct font name */
94
name = xdpy->available[font].names[siz];
95
if (!xdpy->available[font].sizes[siz]) {
96
/* scalable, need to find specific instance */
99
while (n--) while ((*(pnm++)= *(name++))!='-');
100
sprintf(pnm, "%d%n", pixsize, &n);
102
tmp_fonts = XListFonts(xdpy->dpy, nm, 4, &n);
103
if (n<=0) return xdpy->font; /* should never happen (X server bug) */
104
strcpy(nm, tmp_fonts[0]);
105
XFreeFontNames(tmp_fonts);
110
/* should be able to load it */
111
f = XLoadQueryFont(xdpy->dpy, name);
112
if (!f) return xdpy->font; /* should never happen (X server bug) */
114
if (!xdpy->cached[0].f) {
115
/* cache not yet full */
116
for (j=0 ; j<N_FONT_CACHE-1 ; j++)
117
if (xdpy->cached[j+1].f) break;
119
/* cache is full, need to unload one, j is least recent */
120
XFontStruct *fold = xdpy->cached[j].f;
121
xdpy->cached[j].f = 0;
122
if (jp) *jp = -1; /* jp pointed to j, now least recent */
123
XFreeFont(xdpy->dpy, fold);
126
xdpy->cached[j].font = font;
127
xdpy->cached[j].pixsize = pixsize;
128
xdpy->cached[j].f = f;
129
xdpy->cached[j].next = xdpy->most_recent;
130
xdpy->most_recent = j;
133
if (p_signalling) p_abort();
139
x_substitute(x_display *xdpy, int *font, int *pixsize)
143
int face = fnt&(P_BOLD|P_ITALIC);
145
if (!xdpy->available[fnt].nsizes) {
147
if (!face || !xdpy->available[fnt].nsizes) {
149
for (i=1 ; i<4 ; i++) if (xdpy->available[fnt|i].nsizes) break;
153
if (xdpy->available[P_TIMES|face].nsizes)
155
else if (xdpy->available[P_NEWCENTURY|face].nsizes)
156
fnt = P_NEWCENTURY|face;
157
else if (xdpy->available[P_HELVETICA|face].nsizes)
158
fnt = P_HELVETICA|face;
159
else if (xdpy->available[P_COURIER|face].nsizes)
160
fnt = P_COURIER|face;
162
if (xdpy->available[P_TIMES].nsizes)
164
else if (xdpy->available[P_NEWCENTURY].nsizes)
166
else if (xdpy->available[P_HELVETICA].nsizes)
168
else if (xdpy->available[P_COURIER].nsizes)
179
siz = x_closest(siz, xdpy->available[fnt].sizes,
180
xdpy->available[fnt].nsizes, &face);
191
-foundry-family-wgt-slant-wid--pixels-pts-hres-vres-spacing-avgwid-char-set
194
static char *pattern[5] = {
195
"-*-courier-*-*-normal--*-*-*-*-m-*-iso8859-1",
196
"-*-times-*-*-normal--*-*-*-*-p-*-iso8859-1",
197
"-*-helvetica-*-*-normal--*-*-*-*-p-*-iso8859-1",
198
"-*-symbol-*-*-normal--*-*-*-*-p-*-*-*",
199
"-*-new century schoolbook-*-*-normal--*-*-*-*-p-*-iso8859-1" };
202
x_analyze(x_display *xdpy, int fam)
204
int i, j, n, face, pixsize, nsizes;
206
if (tmp_fonts) tmp_free();
207
tmp_fonts = XListFonts(xdpy->dpy, pattern[((unsigned int)fam)>>2], 1024, &n);
209
for (i=0 ; i<n ; i++) {
210
name = x_face(tmp_fonts[i], &face);
213
/* extract pixels field */
215
if (name[0]!='*') while (name[0] && name[0]>='0' && name[0]<='9')
216
pixsize = 10*pixsize + *(name++) - '0';
219
if (name[0]!='-') continue;
221
/* protect against superlong font names */
222
if (!pixsize && strlen(tmp_fonts[i])>120) continue;
226
nsizes = xdpy->available[face].nsizes;
227
if (x_lookup(pixsize, xdpy->available[face].sizes, nsizes)) continue;
229
int *sizes = xdpy->available[face].sizes;
230
char **names = xdpy->available[face].names;
231
xdpy->available[face].sizes = p_realloc(sizes, sizeof(int)*(nsizes+12));
232
if (!xdpy->available[face].sizes) {
233
xdpy->available[face].sizes = sizes;
236
xdpy->available[face].names = p_realloc(names,sizeof(char*)*(nsizes+13));
237
if (!xdpy->available[face].names) {
238
xdpy->available[face].names = names;
242
j = x_insert(pixsize, xdpy->available[face].sizes,
243
xdpy->available[face].names, nsizes);
244
xdpy->available[face].nsizes++;
246
xdpy->available[face].names[j] = p_strcpy(tmp_fonts[i]);
248
/* scalable font needs wildcard name */
249
char nm[128], *pnm = nm;
252
while (n--) while ((*(pnm++)= *(name++))!='-');
253
/* skip over pixels, points fields */
254
*(pnm++)= '*'; *(pnm++)= '-'; *(pnm++)= '*'; *(pnm++)= '-';
255
for (n=2 ; n-- ;) while (name[0] && *(name++)!='-');
256
/* copy hres, vres, spacing fields */
257
for (n=3 ; n-- ;) while (name[0] && (*(pnm++)= *(name++))!='-');
258
/* skip over average width field */
259
*(pnm++)= '*'; *(pnm++)= '-';
260
while (name[0] && *(name++)!='-');
261
/* copy remainder (character set fields) */
262
while ((*(pnm++)= *(name++)));
263
xdpy->available[face].names[j] = p_strcpy(nm);
271
x_face(char *name, int *face)
275
/* skip to wgt field */
277
while (n--) while (name[0] && *(name++)!='-');
279
if (!name[0]) return 0;
281
/* compare with "bold" -- otherwise assume non-bold */
282
while (name[0] && name[0]==pat[0]) name++, pat++;
283
if (!pat[0] && name[0]=='-') *face |= P_BOLD;
285
/* skip to slant field, compare with "r" -- otherwise assume italic */
286
while (name[0] && *(name++)!='-');
287
if (!name[0] || !name[1]) return 0;
288
if (name[0]!='r' || name[1]!='-') *face |= P_ITALIC;
290
/* skip to pixels field */
292
while (n--) while (name[0] && *(name++)!='-');
293
return name[0]? name : 0;
297
x_insert(int pixsize, int *sizes, char **names, int nsizes)
301
if (!nsizes || sizes[0]>pixsize) {
303
} else if (sizes[nsizes-1]<pixsize) {
307
for (i=0,j=nsizes-1,k=j>>1 ; k!=i ; k=(i+j)>>1) {
308
if (sizes[k]>pixsize) j = k;
312
names[nsizes+1] = 0; /* see x_disconnect */
313
for (i=nsizes ; i>j ; i--) {
314
sizes[i] = sizes[i-1];
316
names[i-1] = 0; /* never want two copies of nm in names[] */
324
x_lookup(int pixsize, int *sizes, int nsizes)
326
unsigned int i, j=nsizes-1, k;
327
if (nsizes<=0 || sizes[0]>pixsize || sizes[j]<pixsize) return 0;
328
if (sizes[j]==pixsize) return nsizes;
330
if (sizes[0]==pixsize) return 1;
332
for (k=j>>1 ; k!=i ; k=(i+j)>>1) {
333
if (sizes[k]==pixsize) return k+1;
334
if (sizes[k]>pixsize) j = k;
341
x_closest(int pixsize, int *sizes, int nsizes, int *ndx)
343
unsigned int i, j=nsizes-1, k;
344
if (nsizes<=0 || pixsize<=0) return (*ndx=-1, 0);
345
if (sizes[j]<=pixsize) return (*ndx=j, sizes[j]);
346
else if (sizes[0]>=pixsize) return (*ndx=0, sizes[0]);
348
for (k=j>>1 ; k!=i ; k=(i+j)>>1) {
349
if (sizes[k]==pixsize) return (*ndx=k, pixsize);
350
if (sizes[k]>pixsize) j = k;
353
if (pixsize-sizes[i] < sizes[j]-pixsize) return (*ndx=i, sizes[i]);
354
else return (*ndx=j, sizes[j]);