font.c revision 8c7c3c7e
1f80a6dcdSmrg/*
2f80a6dcdSmrg * font.c
3f80a6dcdSmrg *
4f80a6dcdSmrg * map dvi fonts to X fonts
5f80a6dcdSmrg */
6f80a6dcdSmrg
7f80a6dcdSmrg#include <X11/Xos.h>
8f80a6dcdSmrg#include <X11/IntrinsicP.h>
9f80a6dcdSmrg#include <X11/StringDefs.h>
10f80a6dcdSmrg#include <stdio.h>
11f80a6dcdSmrg#include <stdlib.h>
12f80a6dcdSmrg#include <ctype.h>
13f80a6dcdSmrg#include "DviP.h"
14f80a6dcdSmrg#include "XFontName.h"
15f80a6dcdSmrg
16f80a6dcdSmrgstatic char *
17c166fba9Smrgsavestr (const char *s)
18f80a6dcdSmrg{
19f80a6dcdSmrg	char	*n;
20f80a6dcdSmrg
21f80a6dcdSmrg	if (!s)
2265912f00Smrg		return NULL;
23f80a6dcdSmrg	n = XtMalloc (strlen (s) + 1);
24f80a6dcdSmrg	if (n)
25f80a6dcdSmrg		strcpy (n, s);
26f80a6dcdSmrg	return n;
27f80a6dcdSmrg}
28f80a6dcdSmrg
29f80a6dcdSmrgstatic DviFontList *
30f80a6dcdSmrgLookupFontByPosition (DviWidget dw, int position)
31f80a6dcdSmrg{
32f80a6dcdSmrg	DviFontList	*f;
33f80a6dcdSmrg
34f80a6dcdSmrg	for (f = dw->dvi.fonts; f; f=f->next)
35f80a6dcdSmrg		if (f->dvi_number == position)
36f80a6dcdSmrg			break;
37f80a6dcdSmrg	return f;
38f80a6dcdSmrg}
39f80a6dcdSmrg
40f80a6dcdSmrgstatic DviFontSizeList *
41f80a6dcdSmrgLookupFontSizeBySize (DviWidget dw, DviFontList *f, int size)
42f80a6dcdSmrg{
438c7c3c7eSmrg    DviFontSizeList	*best = NULL;
44f80a6dcdSmrg
45f80a6dcdSmrg    if (f->scalable)
46f80a6dcdSmrg    {
478c7c3c7eSmrg	char		fontNameString[2048];
488c7c3c7eSmrg	XFontName	fontName;
498c7c3c7eSmrg	unsigned int	fontNameAttributes;
508c7c3c7eSmrg
51f80a6dcdSmrg	for (best = f->sizes; best; best = best->next)
52f80a6dcdSmrg	    if (best->size == size)
53f80a6dcdSmrg		return best;
54f80a6dcdSmrg	best = (DviFontSizeList *) XtMalloc (sizeof *best);
55f80a6dcdSmrg	best->next = f->sizes;
56f80a6dcdSmrg	best->size = size;
57f80a6dcdSmrg	XParseFontName (f->x_name, &fontName, &fontNameAttributes);
58f80a6dcdSmrg	fontNameAttributes &= ~(FontNamePixelSize|FontNameAverageWidth);
59f80a6dcdSmrg	fontNameAttributes |= FontNameResolutionX;
60f80a6dcdSmrg	fontNameAttributes |= FontNameResolutionY;
61f80a6dcdSmrg	fontNameAttributes |= FontNamePointSize;
62f80a6dcdSmrg	fontName.ResolutionX = dw->dvi.screen_resolution;
63f80a6dcdSmrg	fontName.ResolutionY = dw->dvi.screen_resolution;
64f80a6dcdSmrg	fontName.PointSize = size * 10 / dw->dvi.size_scale;
65f80a6dcdSmrg	XFormatFontName (&fontName, fontNameAttributes, fontNameString);
66f80a6dcdSmrg	best->x_name = savestr (fontNameString);
67f80a6dcdSmrg#ifdef USE_XFT
68f80a6dcdSmrg	/*
69f80a6dcdSmrg	 * Force a match of a core font for adobe-fontspecific
708c7c3c7eSmrg	 * encodings; we don't have a scalable font in
71f80a6dcdSmrg	 * the right encoding
72f80a6dcdSmrg	 */
73f80a6dcdSmrg	best->core = False;
74f80a6dcdSmrg	if (!strcmp (fontName.CharSetRegistry, "adobe") &&
75f80a6dcdSmrg	    !strcmp (fontName.CharSetEncoding, "fontspecific"))
76f80a6dcdSmrg	{
77f80a6dcdSmrg	    best->core = True;
78f80a6dcdSmrg	}
79f80a6dcdSmrg#endif
80f80a6dcdSmrg	best->doesnt_exist = 0;
8165912f00Smrg	best->font = NULL;
82f80a6dcdSmrg	f->sizes = best;
83f80a6dcdSmrg    }
84f80a6dcdSmrg    else
85f80a6dcdSmrg    {
868c7c3c7eSmrg	int 	bestdist = 65536;
878c7c3c7eSmrg
888c7c3c7eSmrg	for (DviFontSizeList *fs = f->sizes; fs; fs=fs->next) {
898c7c3c7eSmrg	    int	dist = size - fs->size;
90f80a6dcdSmrg	    if (dist < 0)
91f80a6dcdSmrg		dist = -dist * 16;
92f80a6dcdSmrg	    if (dist < bestdist)
93f80a6dcdSmrg	    {
94f80a6dcdSmrg		best = fs;
95f80a6dcdSmrg		bestdist = dist;
96f80a6dcdSmrg	    }
97f80a6dcdSmrg    	}
98f80a6dcdSmrg    }
99f80a6dcdSmrg    return best;
100f80a6dcdSmrg}
101f80a6dcdSmrg
102f80a6dcdSmrgstatic char *
103f80a6dcdSmrgSkipFontNameElement (char *n)
104f80a6dcdSmrg{
105f80a6dcdSmrg	while (*n != '-')
106f80a6dcdSmrg		if (!*++n)
10765912f00Smrg			return NULL;
108f80a6dcdSmrg	return n+1;
109f80a6dcdSmrg}
110f80a6dcdSmrg
111f80a6dcdSmrg# define SizePosition		8
112f80a6dcdSmrg# define EncodingPosition	13
113f80a6dcdSmrg
114f80a6dcdSmrg#ifndef USE_XFT
115f80a6dcdSmrgstatic int
116f80a6dcdSmrgConvertFontNameToSize (char *n)
117f80a6dcdSmrg{
118f80a6dcdSmrg	int	i, size;
119f80a6dcdSmrg
120f80a6dcdSmrg	for (i = 0; i < SizePosition; i++) {
121f80a6dcdSmrg		n = SkipFontNameElement (n);
122f80a6dcdSmrg		if (!n)
123f80a6dcdSmrg			return -1;
124f80a6dcdSmrg	}
125f80a6dcdSmrg	size = atoi (n);
126f80a6dcdSmrg	return size/10;
127f80a6dcdSmrg}
128f80a6dcdSmrg#endif
129f80a6dcdSmrg
130f80a6dcdSmrgstatic char *
131f80a6dcdSmrgConvertFontNameToEncoding (char *n)
132f80a6dcdSmrg{
1338c7c3c7eSmrg	for (int i = 0; i < EncodingPosition; i++) {
134f80a6dcdSmrg		n = SkipFontNameElement (n);
135f80a6dcdSmrg		if (!n)
13665912f00Smrg			return NULL;
137f80a6dcdSmrg	}
138f80a6dcdSmrg	return n;
139f80a6dcdSmrg}
140f80a6dcdSmrg
141f80a6dcdSmrgstatic void
142f80a6dcdSmrgDisposeFontSizes (DviWidget dw, DviFontSizeList *fs)
143f80a6dcdSmrg{
144f80a6dcdSmrg    DviFontSizeList	*next;
145f80a6dcdSmrg
146f80a6dcdSmrg    for (; fs; fs=next) {
147f80a6dcdSmrg	next = fs->next;
148f80a6dcdSmrg	if (fs->x_name)
149f80a6dcdSmrg		XtFree (fs->x_name);
150f80a6dcdSmrg	if (fs->font)
151f80a6dcdSmrg	{
152f80a6dcdSmrg#ifdef USE_XFT
153f80a6dcdSmrg	    XftFontClose (XtDisplay (dw), fs->font);
154f80a6dcdSmrg#else
155f80a6dcdSmrg	    XUnloadFont (XtDisplay (dw), fs->font->fid);
156f80a6dcdSmrg	    XFree ((char *)fs->font);
157f80a6dcdSmrg#endif
158f80a6dcdSmrg	}
159f80a6dcdSmrg	XtFree ((char *) fs);
160f80a6dcdSmrg    }
161f80a6dcdSmrg}
162f80a6dcdSmrg
163f80a6dcdSmrgvoid
164f80a6dcdSmrgResetFonts (DviWidget dw)
165f80a6dcdSmrg{
1668c7c3c7eSmrg    for (DviFontList *f = dw->dvi.fonts; f; f = f->next)
167f80a6dcdSmrg    {
168f80a6dcdSmrg	if (f->initialized)
169f80a6dcdSmrg	{
170f80a6dcdSmrg	    DisposeFontSizes (dw, f->sizes);
17165912f00Smrg	    f->sizes = NULL;
172f80a6dcdSmrg	    f->initialized = FALSE;
173f80a6dcdSmrg	    f->scalable = FALSE;
174f80a6dcdSmrg	}
175f80a6dcdSmrg    }
176f80a6dcdSmrg    /*
177f80a6dcdSmrg     * force requery of fonts
178f80a6dcdSmrg     */
17965912f00Smrg    dw->dvi.font = NULL;
180f80a6dcdSmrg    dw->dvi.font_number = -1;
18165912f00Smrg    dw->dvi.cache.font = NULL;
182f80a6dcdSmrg    dw->dvi.cache.font_number = -1;
183f80a6dcdSmrg}
184f80a6dcdSmrg
185f80a6dcdSmrgstatic DviFontSizeList *
186f80a6dcdSmrgInstallFontSizes (DviWidget dw, char *x_name, Boolean *scalablep)
187f80a6dcdSmrg{
188f80a6dcdSmrg#ifndef USE_XFT
189f80a6dcdSmrg    char	    fontNameString[2048];
190f80a6dcdSmrg    char	    **fonts;
1918c7c3c7eSmrg    int		    count;
192f80a6dcdSmrg    XFontName	    fontName;
193f80a6dcdSmrg    unsigned int    fontNameAttributes;
194f80a6dcdSmrg#endif
195f80a6dcdSmrg    DviFontSizeList *sizes;
196f80a6dcdSmrg
19765912f00Smrg    sizes = NULL;
198f80a6dcdSmrg#ifdef USE_XFT
199f80a6dcdSmrg    *scalablep = TRUE;
200f80a6dcdSmrg#else
201f80a6dcdSmrg    *scalablep = FALSE;
202f80a6dcdSmrg    if (!XParseFontName (x_name, &fontName, &fontNameAttributes))
20365912f00Smrg	return NULL;
204f80a6dcdSmrg
205f80a6dcdSmrg    fontNameAttributes &= ~(FontNamePixelSize|FontNamePointSize);
206f80a6dcdSmrg    fontNameAttributes |= FontNameResolutionX;
207f80a6dcdSmrg    fontNameAttributes |= FontNameResolutionY;
208f80a6dcdSmrg    fontName.ResolutionX = dw->dvi.screen_resolution;
209f80a6dcdSmrg    fontName.ResolutionY = dw->dvi.screen_resolution;
210f80a6dcdSmrg    XFormatFontName (&fontName, fontNameAttributes, fontNameString);
211f80a6dcdSmrg    fonts = XListFonts (XtDisplay (dw), fontNameString, 10000000, &count);
2128c7c3c7eSmrg    for (int i = 0; i < count; i++) {
2138c7c3c7eSmrg	int	size = ConvertFontNameToSize (fonts[i]);
2148c7c3c7eSmrg
215f80a6dcdSmrg	if (size == 0)
216f80a6dcdSmrg	{
217f80a6dcdSmrg	    DisposeFontSizes (dw, sizes);
218f80a6dcdSmrg	    *scalablep = TRUE;
21965912f00Smrg	    sizes = NULL;
220f80a6dcdSmrg	    break;
221f80a6dcdSmrg	}
222f80a6dcdSmrg	if (size != -1) {
2238c7c3c7eSmrg	    DviFontSizeList *new = (DviFontSizeList *) XtMalloc (sizeof *new);
224f80a6dcdSmrg	    new->next = sizes;
225f80a6dcdSmrg	    new->size = size;
226f80a6dcdSmrg	    new->x_name = savestr (fonts[i]);
227f80a6dcdSmrg	    new->doesnt_exist = 0;
22865912f00Smrg	    new->font = NULL;
229f80a6dcdSmrg	    sizes = new;
230f80a6dcdSmrg	}
231f80a6dcdSmrg    }
232f80a6dcdSmrg    XFreeFontNames (fonts);
233f80a6dcdSmrg#endif
234f80a6dcdSmrg    return sizes;
235f80a6dcdSmrg}
236f80a6dcdSmrg
237f80a6dcdSmrgstatic DviFontList *
238c166fba9SmrgInstallFont (DviWidget dw, int position, const char *dvi_name, const char *x_name)
239f80a6dcdSmrg{
240f80a6dcdSmrg    DviFontList	*f;
241f80a6dcdSmrg
242f80a6dcdSmrg    f = LookupFontByPosition (dw, position);
243f80a6dcdSmrg    if (f) {
244f80a6dcdSmrg	/*
245f80a6dcdSmrg	 * ignore gratuitous font loading
246f80a6dcdSmrg	 */
247f80a6dcdSmrg	if (!strcmp (f->dvi_name, dvi_name) && !strcmp (f->x_name, x_name))
248f80a6dcdSmrg	    return f;
249f80a6dcdSmrg
250f80a6dcdSmrg	DisposeFontSizes (dw, f->sizes);
251f80a6dcdSmrg	if (f->dvi_name)
252f80a6dcdSmrg	    XtFree (f->dvi_name);
253f80a6dcdSmrg	if (f->x_name)
254f80a6dcdSmrg	    XtFree (f->x_name);
255f80a6dcdSmrg    } else {
256f80a6dcdSmrg	f = (DviFontList *) XtMalloc (sizeof (*f));
257f80a6dcdSmrg	f->next = dw->dvi.fonts;
258f80a6dcdSmrg	dw->dvi.fonts = f;
259f80a6dcdSmrg    }
260f80a6dcdSmrg    f->initialized = FALSE;
261f80a6dcdSmrg    f->dvi_name = savestr (dvi_name);
262f80a6dcdSmrg    f->x_name = savestr (x_name);
263f80a6dcdSmrg    f->dvi_number = position;
26465912f00Smrg    f->sizes = NULL;
265f80a6dcdSmrg    f->scalable = FALSE;
266f80a6dcdSmrg    if (f->x_name) {
2678c7c3c7eSmrg	const char *encoding = ConvertFontNameToEncoding (f->x_name);
268f80a6dcdSmrg	f->char_map = DviFindMap (encoding);
269f80a6dcdSmrg    } else
27065912f00Smrg	f->char_map = NULL;
271f80a6dcdSmrg    /*
272f80a6dcdSmrg     * force requery of fonts
273f80a6dcdSmrg     */
27465912f00Smrg    dw->dvi.font = NULL;
275f80a6dcdSmrg    dw->dvi.font_number = -1;
27665912f00Smrg    dw->dvi.cache.font = NULL;
277f80a6dcdSmrg    dw->dvi.cache.font_number = -1;
278f80a6dcdSmrg    return f;
279f80a6dcdSmrg}
280f80a6dcdSmrg
281c166fba9Smrgstatic const char *
282c166fba9SmrgMapDviNameToXName (DviWidget dw, const char *dvi_name)
283f80a6dcdSmrg{
284f80a6dcdSmrg    DviFontMap	*fm;
285f80a6dcdSmrg
286f80a6dcdSmrg    for (fm = dw->dvi.font_map; fm; fm=fm->next)
287f80a6dcdSmrg	if (!strcmp (fm->dvi_name, dvi_name))
288f80a6dcdSmrg	    return fm->x_name;
289f80a6dcdSmrg    ++dvi_name;
290f80a6dcdSmrg    for (fm = dw->dvi.font_map; fm; fm=fm->next)
291f80a6dcdSmrg	if (!strcmp (fm->dvi_name, "R"))
292f80a6dcdSmrg	    return fm->x_name;
293f80a6dcdSmrg    if (dw->dvi.font_map->x_name)
294f80a6dcdSmrg	return dw->dvi.font_map->x_name;
295f80a6dcdSmrg    return "-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-1";
296f80a6dcdSmrg}
297f80a6dcdSmrg
298f80a6dcdSmrg
299f80a6dcdSmrgvoid
30065912f00SmrgParseFontMap (DviWidget dw)
301f80a6dcdSmrg{
3028c7c3c7eSmrg    char	*m;
3038c7c3c7eSmrg    DviFontMap	*fm;
304f80a6dcdSmrg
305f80a6dcdSmrg    if (dw->dvi.font_map)
306f80a6dcdSmrg	    DestroyFontMap (dw->dvi.font_map);
30765912f00Smrg    fm = NULL;
308f80a6dcdSmrg    m = dw->dvi.font_map_string;
309f80a6dcdSmrg    while (*m) {
3108c7c3c7eSmrg	char		dvi_name[1024];
3118c7c3c7eSmrg	char		x_name[2048];
3128c7c3c7eSmrg
3138c7c3c7eSmrg	char *s = m;
314f80a6dcdSmrg	while (*m && !isspace (*m))
315f80a6dcdSmrg	    ++m;
316f80a6dcdSmrg	strncpy (dvi_name, s, m-s);
317f80a6dcdSmrg	dvi_name[m-s] = '\0';
318f80a6dcdSmrg	while (isspace (*m))
319f80a6dcdSmrg	    ++m;
320f80a6dcdSmrg	s = m;
321f80a6dcdSmrg	while (*m && *m != '\n')
322f80a6dcdSmrg	    ++m;
323f80a6dcdSmrg	strncpy (x_name, s, m-s);
324f80a6dcdSmrg	x_name[m-s] = '\0';
3258c7c3c7eSmrg
3268c7c3c7eSmrg	DviFontMap	*new = (DviFontMap *) XtMalloc (sizeof *new);
327f80a6dcdSmrg	new->x_name = savestr (x_name);
328f80a6dcdSmrg	new->dvi_name = savestr (dvi_name);
329f80a6dcdSmrg	new->next = fm;
330f80a6dcdSmrg	fm = new;
331f80a6dcdSmrg	++m;
332f80a6dcdSmrg    }
333f80a6dcdSmrg    dw->dvi.font_map = fm;
334f80a6dcdSmrg}
335f80a6dcdSmrg
336f80a6dcdSmrgvoid
33765912f00SmrgDestroyFontMap (DviFontMap *font_map)
338f80a6dcdSmrg{
339f80a6dcdSmrg    DviFontMap	*next;
340f80a6dcdSmrg
341f80a6dcdSmrg    for (; font_map; font_map = next) {
342f80a6dcdSmrg	next = font_map->next;
343f80a6dcdSmrg	if (font_map->x_name)
344f80a6dcdSmrg	    XtFree (font_map->x_name);
345f80a6dcdSmrg	if (font_map->dvi_name)
346f80a6dcdSmrg	    XtFree (font_map->dvi_name);
347f80a6dcdSmrg	XtFree ((char *) font_map);
348f80a6dcdSmrg    }
349f80a6dcdSmrg}
350f80a6dcdSmrg
351f80a6dcdSmrg/*ARGSUSED*/
352f80a6dcdSmrgvoid
353c166fba9SmrgSetFontPosition (DviWidget dw, int position, const char *dvi_name, const char *extra)
354f80a6dcdSmrg{
355c166fba9Smrg    const char	*x_name;
356f80a6dcdSmrg
357f80a6dcdSmrg    x_name = MapDviNameToXName (dw, dvi_name);
358f80a6dcdSmrg    (void) InstallFont (dw, position, dvi_name, x_name);
359f80a6dcdSmrg}
360f80a6dcdSmrg
361f80a6dcdSmrg#ifdef USE_XFT
362f80a6dcdSmrgXftFont *
363f80a6dcdSmrg#else
364f80a6dcdSmrgXFontStruct *
365f80a6dcdSmrg#endif
36665912f00SmrgQueryFont (DviWidget dw, int position, int size)
367f80a6dcdSmrg{
368f80a6dcdSmrg    DviFontList	*f;
369f80a6dcdSmrg    DviFontSizeList	*fs;
370f80a6dcdSmrg
371f80a6dcdSmrg    f = LookupFontByPosition (dw, position);
372f80a6dcdSmrg    if (!f)
373f80a6dcdSmrg	return dw->dvi.default_font;
374f80a6dcdSmrg    if (!f->initialized) {
375f80a6dcdSmrg	f->sizes = InstallFontSizes (dw, f->x_name, &f->scalable);
376f80a6dcdSmrg	f->initialized = TRUE;
377f80a6dcdSmrg    }
378f80a6dcdSmrg    fs = LookupFontSizeBySize (dw, f, size);
379f80a6dcdSmrg    if (!fs)
380f80a6dcdSmrg	return dw->dvi.default_font;
381f80a6dcdSmrg    if (!fs->font) {
382f80a6dcdSmrg	if (fs->x_name)
383f80a6dcdSmrg	{
384f80a6dcdSmrg#ifdef USE_XFT
385f80a6dcdSmrg	    XftPattern	*pat;
386f80a6dcdSmrg	    XftPattern	*match;
387f80a6dcdSmrg	    XftResult	result;
388f80a6dcdSmrg
389f80a6dcdSmrg	    pat = XftXlfdParse (fs->x_name, False, False);
390f80a6dcdSmrg	    XftPatternAddBool (pat, XFT_CORE, fs->core);
391f80a6dcdSmrg	    match = XftFontMatch (XtDisplay (dw),
392f80a6dcdSmrg				  XScreenNumberOfScreen(dw->core.screen),
393f80a6dcdSmrg				  pat, &result);
394f80a6dcdSmrg	    XftPatternDestroy (pat);
395f80a6dcdSmrg	    if (match)
396f80a6dcdSmrg	    {
397f80a6dcdSmrg		fs->font = XftFontOpenPattern (XtDisplay (dw),
398f80a6dcdSmrg					       match);
399f80a6dcdSmrg		if (!fs->font)
400f80a6dcdSmrg		    XftPatternDestroy (match);
401f80a6dcdSmrg	    }
402f80a6dcdSmrg	    else
403f80a6dcdSmrg		fs->font = 0;
404f80a6dcdSmrg#else
405f80a6dcdSmrg	    fs->font = XLoadQueryFont (XtDisplay (dw), fs->x_name);
406f80a6dcdSmrg#endif
407f80a6dcdSmrg	}
408f80a6dcdSmrg	if (!fs->font)
409f80a6dcdSmrg	    fs->font = dw->dvi.default_font;
410f80a6dcdSmrg    }
411f80a6dcdSmrg    return fs->font;
412f80a6dcdSmrg}
413f80a6dcdSmrg
414f80a6dcdSmrgDviCharNameMap *
41565912f00SmrgQueryFontMap (DviWidget dw, int position)
416f80a6dcdSmrg{
417f80a6dcdSmrg	DviFontList	*f;
418f80a6dcdSmrg
419f80a6dcdSmrg	f = LookupFontByPosition (dw, position);
420f80a6dcdSmrg	if (f)
421f80a6dcdSmrg	    return f->char_map;
422f80a6dcdSmrg	else
42365912f00Smrg	    return NULL;
424f80a6dcdSmrg}
425f80a6dcdSmrg
426f80a6dcdSmrgunsigned char *
427c166fba9SmrgDviCharIsLigature (DviCharNameMap *map, const char *name)
428f80a6dcdSmrg{
4298c7c3c7eSmrg    for (int i = 0; i < DVI_MAX_LIGATURES; i++) {
430f80a6dcdSmrg	if (!map->ligatures[i][0])
431f80a6dcdSmrg	    break;
432f80a6dcdSmrg	if (!strcmp (name, map->ligatures[i][0]))
433f80a6dcdSmrg	    return (unsigned char *) map->ligatures[i][1];
434f80a6dcdSmrg    }
43565912f00Smrg    return NULL;
436f80a6dcdSmrg}
437