font.c revision 65912f00
1/*
2 * font.c
3 *
4 * map dvi fonts to X fonts
5 */
6/* $XFree86: xc/programs/xditview/font.c,v 1.5 2001/08/27 23:35:12 dawes Exp $ */
7
8#include <X11/Xos.h>
9#include <X11/IntrinsicP.h>
10#include <X11/StringDefs.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <ctype.h>
14#include "DviP.h"
15#include "XFontName.h"
16
17static char *
18savestr (char *s)
19{
20	char	*n;
21
22	if (!s)
23		return NULL;
24	n = XtMalloc (strlen (s) + 1);
25	if (n)
26		strcpy (n, s);
27	return n;
28}
29
30static DviFontList *
31LookupFontByPosition (DviWidget dw, int position)
32{
33	DviFontList	*f;
34
35	for (f = dw->dvi.fonts; f; f=f->next)
36		if (f->dvi_number == position)
37			break;
38	return f;
39}
40
41static DviFontSizeList *
42LookupFontSizeBySize (DviWidget dw, DviFontList *f, int size)
43{
44    DviFontSizeList *fs, *best = NULL;
45    int		    bestdist;
46    char	    fontNameString[2048];
47    XFontName	    fontName;
48    unsigned int    fontNameAttributes;
49    int		    dist;
50
51    if (f->scalable)
52    {
53	for (best = f->sizes; best; best = best->next)
54	    if (best->size == size)
55		return best;
56	best = (DviFontSizeList *) XtMalloc (sizeof *best);
57	best->next = f->sizes;
58	best->size = size;
59	XParseFontName (f->x_name, &fontName, &fontNameAttributes);
60	fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth);
61	fontNameAttributes |= FontNameResolutionX;
62	fontNameAttributes |= FontNameResolutionY;
63	fontNameAttributes |= FontNamePointSize;
64	fontName.ResolutionX = dw->dvi.screen_resolution;
65	fontName.ResolutionY = dw->dvi.screen_resolution;
66	fontName.PointSize = size * 10 / dw->dvi.size_scale;
67	XFormatFontName (&fontName, fontNameAttributes, fontNameString);
68	best->x_name = savestr (fontNameString);
69#ifdef USE_XFT
70	/*
71	 * Force a match of a core font for adobe-fontspecific
72	 * encodings; we dont have a scalable font in
73	 * the right encoding
74	 */
75	best->core = False;
76	if (!strcmp (fontName.CharSetRegistry, "adobe") &&
77	    !strcmp (fontName.CharSetEncoding, "fontspecific"))
78	{
79	    best->core = True;
80	}
81#endif
82	best->doesnt_exist = 0;
83	best->font = NULL;
84	f->sizes = best;
85    }
86    else
87    {
88	bestdist = 65536;
89    	for (fs = f->sizes; fs; fs=fs->next) {
90	    dist = size - fs->size;
91	    if (dist < 0)
92		dist = -dist * 16;
93	    if (dist < bestdist)
94	    {
95		best = fs;
96		bestdist = dist;
97	    }
98    	}
99    }
100    return best;
101}
102
103static char *
104SkipFontNameElement (char *n)
105{
106	while (*n != '-')
107		if (!*++n)
108			return NULL;
109	return n+1;
110}
111
112# define SizePosition		8
113# define EncodingPosition	13
114
115#ifndef USE_XFT
116static int
117ConvertFontNameToSize (char *n)
118{
119	int	i, size;
120
121	for (i = 0; i < SizePosition; i++) {
122		n = SkipFontNameElement (n);
123		if (!n)
124			return -1;
125	}
126	size = atoi (n);
127	return size/10;
128}
129#endif
130
131static char *
132ConvertFontNameToEncoding (char *n)
133{
134        int i;
135	for (i = 0; i < EncodingPosition; i++) {
136		n = SkipFontNameElement (n);
137		if (!n)
138			return NULL;
139	}
140	return n;
141}
142
143static void
144DisposeFontSizes (DviWidget dw, DviFontSizeList *fs)
145{
146    DviFontSizeList	*next;
147
148    for (; fs; fs=next) {
149	next = fs->next;
150	if (fs->x_name)
151		XtFree (fs->x_name);
152	if (fs->font)
153	{
154#ifdef USE_XFT
155	    XftFontClose (XtDisplay (dw), fs->font);
156#else
157	    XUnloadFont (XtDisplay (dw), fs->font->fid);
158	    XFree ((char *)fs->font);
159#endif
160	}
161	XtFree ((char *) fs);
162    }
163}
164
165void
166ResetFonts (DviWidget dw)
167{
168    DviFontList	*f;
169
170    for (f = dw->dvi.fonts; f; f = f->next)
171    {
172	if (f->initialized)
173	{
174	    DisposeFontSizes (dw, f->sizes);
175	    f->sizes = NULL;
176	    f->initialized = FALSE;
177	    f->scalable = FALSE;
178	}
179    }
180    /*
181     * force requery of fonts
182     */
183    dw->dvi.font = NULL;
184    dw->dvi.font_number = -1;
185    dw->dvi.cache.font = NULL;
186    dw->dvi.cache.font_number = -1;
187}
188
189static DviFontSizeList *
190InstallFontSizes (DviWidget dw, char *x_name, Boolean *scalablep)
191{
192#ifndef USE_XFT
193    char	    fontNameString[2048];
194    char	    **fonts;
195    int		    i, count;
196    int		    size;
197    DviFontSizeList *new;
198    XFontName	    fontName;
199    unsigned int    fontNameAttributes;
200#endif
201    DviFontSizeList *sizes;
202
203    sizes = NULL;
204#ifdef USE_XFT
205    *scalablep = TRUE;
206#else
207    *scalablep = FALSE;
208    if (!XParseFontName (x_name, &fontName, &fontNameAttributes))
209	return NULL;
210
211    fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize);
212    fontNameAttributes |= FontNameResolutionX;
213    fontNameAttributes |= FontNameResolutionY;
214    fontName.ResolutionX = dw->dvi.screen_resolution;
215    fontName.ResolutionY = dw->dvi.screen_resolution;
216    XFormatFontName (&fontName, fontNameAttributes, fontNameString);
217    fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count);
218    for (i = 0; i < count; i++) {
219	size = ConvertFontNameToSize (fonts[i]);
220	if (size == 0)
221	{
222	    DisposeFontSizes (dw, sizes);
223	    *scalablep = TRUE;
224	    sizes = NULL;
225	    break;
226	}
227	if (size != -1) {
228	    new = (DviFontSizeList *) XtMalloc (sizeof *new);
229	    new->next = sizes;
230	    new->size = size;
231	    new->x_name = savestr (fonts[i]);
232	    new->doesnt_exist = 0;
233	    new->font = NULL;
234	    sizes = new;
235	}
236    }
237    XFreeFontNames (fonts);
238#endif
239    return sizes;
240}
241
242static DviFontList *
243InstallFont (DviWidget dw, int position, char *dvi_name, char *x_name)
244{
245    DviFontList	*f;
246    char		*encoding;
247
248    f = LookupFontByPosition (dw, position);
249    if (f) {
250	/*
251	 * ignore gratuitous font loading
252	 */
253	if (!strcmp (f->dvi_name, dvi_name) && !strcmp (f->x_name, x_name))
254	    return f;
255
256	DisposeFontSizes (dw, f->sizes);
257	if (f->dvi_name)
258	    XtFree (f->dvi_name);
259	if (f->x_name)
260	    XtFree (f->x_name);
261    } else {
262	f = (DviFontList *) XtMalloc (sizeof (*f));
263	f->next = dw->dvi.fonts;
264	dw->dvi.fonts = f;
265    }
266    f->initialized = FALSE;
267    f->dvi_name = savestr (dvi_name);
268    f->x_name = savestr (x_name);
269    f->dvi_number = position;
270    f->sizes = NULL;
271    f->scalable = FALSE;
272    if (f->x_name) {
273	encoding = ConvertFontNameToEncoding (f->x_name);
274	f->char_map = DviFindMap (encoding);
275    } else
276	f->char_map = NULL;
277    /*
278     * force requery of fonts
279     */
280    dw->dvi.font = NULL;
281    dw->dvi.font_number = -1;
282    dw->dvi.cache.font = NULL;
283    dw->dvi.cache.font_number = -1;
284    return f;
285}
286
287static char *
288MapDviNameToXName (DviWidget dw, char *dvi_name)
289{
290    DviFontMap	*fm;
291
292    for (fm = dw->dvi.font_map; fm; fm=fm->next)
293	if (!strcmp (fm->dvi_name, dvi_name))
294	    return fm->x_name;
295    ++dvi_name;
296    for (fm = dw->dvi.font_map; fm; fm=fm->next)
297	if (!strcmp (fm->dvi_name, "R"))
298	    return fm->x_name;
299    if (dw->dvi.font_map->x_name)
300	return dw->dvi.font_map->x_name;
301    return "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1";
302}
303
304#ifdef NOTUSED
305static char *
306MapXNameToDviName (DviWidget dw, char *x_name)
307{
308    DviFontMap	*fm;
309
310    for (fm = dw->dvi.font_map; fm; fm=fm->next)
311	if (!strcmp (fm->x_name, x_name))
312	    return fm->dvi_name;
313    return 0;
314}
315#endif
316
317void
318ParseFontMap (DviWidget dw)
319{
320    char		dvi_name[1024];
321    char		x_name[2048];
322    char		*m, *s;
323    DviFontMap	*fm, *new;
324
325    if (dw->dvi.font_map)
326	    DestroyFontMap (dw->dvi.font_map);
327    fm = NULL;
328    m = dw->dvi.font_map_string;
329    while (*m) {
330	s = m;
331	while (*m && !isspace (*m))
332	    ++m;
333	strncpy (dvi_name, s, m-s);
334	dvi_name[m-s] = '\0';
335	while (isspace (*m))
336	    ++m;
337	s = m;
338	while (*m && *m != '\n')
339	    ++m;
340	strncpy (x_name, s, m-s);
341	x_name[m-s] = '\0';
342	new = (DviFontMap *) XtMalloc (sizeof *new);
343	new->x_name = savestr (x_name);
344	new->dvi_name = savestr (dvi_name);
345	new->next = fm;
346	fm = new;
347	++m;
348    }
349    dw->dvi.font_map = fm;
350}
351
352void
353DestroyFontMap (DviFontMap *font_map)
354{
355    DviFontMap	*next;
356
357    for (; font_map; font_map = next) {
358	next = font_map->next;
359	if (font_map->x_name)
360	    XtFree (font_map->x_name);
361	if (font_map->dvi_name)
362	    XtFree (font_map->dvi_name);
363	XtFree ((char *) font_map);
364    }
365}
366
367/*ARGSUSED*/
368void
369SetFontPosition (DviWidget dw, int position, char *dvi_name, char *extra)
370{
371    char	*x_name;
372
373    x_name = MapDviNameToXName (dw, dvi_name);
374    (void) InstallFont (dw, position, dvi_name, x_name);
375}
376
377#ifdef USE_XFT
378XftFont *
379#else
380XFontStruct *
381#endif
382QueryFont (DviWidget dw, int position, int size)
383{
384    DviFontList	*f;
385    DviFontSizeList	*fs;
386
387    f = LookupFontByPosition (dw, position);
388    if (!f)
389	return dw->dvi.default_font;
390    if (!f->initialized) {
391	f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable);
392	f->initialized = TRUE;
393    }
394    fs = LookupFontSizeBySize (dw, f, size);
395    if (!fs)
396	return dw->dvi.default_font;
397    if (!fs->font) {
398	if (fs->x_name)
399	{
400#ifdef USE_XFT
401	    XftPattern	*pat;
402	    XftPattern	*match;
403	    XftResult	result;
404
405	    pat = XftXlfdParse (fs->x_name, False, False);
406	    XftPatternAddBool (pat, XFT_CORE, fs->core);
407	    match = XftFontMatch (XtDisplay (dw),
408				  XScreenNumberOfScreen(dw->core.screen),
409				  pat, &result);
410	    XftPatternDestroy (pat);
411	    if (match)
412	    {
413		fs->font = XftFontOpenPattern (XtDisplay (dw),
414					       match);
415		if (!fs->font)
416		    XftPatternDestroy (match);
417	    }
418	    else
419		fs->font = 0;
420#else
421	    fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name);
422#endif
423	}
424	if (!fs->font)
425	    fs->font = dw->dvi.default_font;
426    }
427    return fs->font;
428}
429
430DviCharNameMap *
431QueryFontMap (DviWidget dw, int position)
432{
433	DviFontList	*f;
434
435	f = LookupFontByPosition (dw, position);
436	if (f)
437	    return f->char_map;
438	else
439	    return NULL;
440}
441
442unsigned char *
443DviCharIsLigature (DviCharNameMap *map, char *name)
444{
445    int	    i;
446
447    for (i = 0; i < DVI_MAX_LIGATURES; i++) {
448	if (!map->ligatures[i][0])
449	    break;
450	if (!strcmp (name, map->ligatures[i][0]))
451	    return (unsigned char *) map->ligatures[i][1];
452    }
453    return NULL;
454}
455
456#if 0
457LoadFont (DviWidget dw, int position, int size)
458{
459	XFontStruct	*font;
460
461	font = QueryFont (dw, position, size);
462	dw->dvi.font_number = position;
463	dw->dvi.font_size = size;
464	dw->dvi.font = font;
465	XSetFont (XtDisplay (dw), dw->dvi.normal_GC, font->fid);
466	return;
467}
468#endif
469